diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3336534..b4fb060 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,5 +33,10 @@ + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3336534..b4fb060 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,5 +33,10 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt new file mode 100644 index 0000000..28e22c9 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -0,0 +1,75 @@ +package com.casic.endoscope.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Environment +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.casic.endoscope.view.BigImageActivity +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.navigatePageTo +import java.io.File + +abstract class MediaDirAdapter( + private val context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val kTag = "MediaDirAdapter" + private var fileBeans = ArrayList() + private lateinit var fileAdapter: MediaFileAdapter + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(context).inflate(R.layout.item_dir_list_rv, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) { + val date = dataRows[position].name + holder.setText(R.id.dateView, date) + + //根据不同的日期显示不同的改日期下的九宫格形式子文件 + val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) + videoDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) + imageDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val realPaths = ArrayList() + fileBeans.forEach { + val absolutePath = it.absolutePath + if (!absolutePath.endsWith(".mp4")) { + realPaths.add(absolutePath) + } + } + + fileAdapter = object : MediaFileAdapter(context, fileBeans) { + override fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) { + bindChildVideoRes(child, childPos, item) + } + + override fun bindImageRes(child: ViewHolder, item: File) { + child.setImageResource(R.id.imageView, item.absolutePath) + } + } + val recyclerView = holder.getView(R.id.recyclerView) + recyclerView.adapter = fileAdapter + fileAdapter.setOnItemClickedListener(object : MediaFileAdapter.OnItemClickedListener { + override fun onItemClicked(item: File) { + if (!item.name.endsWith(".mp4")) { + context.navigatePageTo(position, realPaths) + } + } + }) + } + + abstract fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3336534..b4fb060 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,5 +33,10 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt new file mode 100644 index 0000000..28e22c9 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -0,0 +1,75 @@ +package com.casic.endoscope.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Environment +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.casic.endoscope.view.BigImageActivity +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.navigatePageTo +import java.io.File + +abstract class MediaDirAdapter( + private val context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val kTag = "MediaDirAdapter" + private var fileBeans = ArrayList() + private lateinit var fileAdapter: MediaFileAdapter + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(context).inflate(R.layout.item_dir_list_rv, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) { + val date = dataRows[position].name + holder.setText(R.id.dateView, date) + + //根据不同的日期显示不同的改日期下的九宫格形式子文件 + val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) + videoDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) + imageDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val realPaths = ArrayList() + fileBeans.forEach { + val absolutePath = it.absolutePath + if (!absolutePath.endsWith(".mp4")) { + realPaths.add(absolutePath) + } + } + + fileAdapter = object : MediaFileAdapter(context, fileBeans) { + override fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) { + bindChildVideoRes(child, childPos, item) + } + + override fun bindImageRes(child: ViewHolder, item: File) { + child.setImageResource(R.id.imageView, item.absolutePath) + } + } + val recyclerView = holder.getView(R.id.recyclerView) + recyclerView.adapter = fileAdapter + fileAdapter.setOnItemClickedListener(object : MediaFileAdapter.OnItemClickedListener { + override fun onItemClicked(item: File) { + if (!item.name.endsWith(".mp4")) { + context.navigatePageTo(position, realPaths) + } + } + }) + } + + abstract fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt new file mode 100644 index 0000000..e447913 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt @@ -0,0 +1,62 @@ +package com.casic.endoscope.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.pengxh.kt.lite.adapter.ViewHolder +import java.io.File + +abstract class MediaFileAdapter( + context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val inflater: LayoutInflater = LayoutInflater.from(context) + private val TYPE_VIDEO = 0 + private val TYPE_IMAGE = 1 + + override fun getItemCount(): Int = dataRows.size + + override fun getItemViewType(position: Int): Int { + return if (dataRows[position].name.endsWith(".mp4")) { + TYPE_VIDEO + } else { + TYPE_IMAGE + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return if (viewType == TYPE_VIDEO) { + ViewHolder(inflater.inflate(R.layout.item_video_list_gv, parent, false)) + } else { + ViewHolder(inflater.inflate(R.layout.item_image_list_gv, parent, false)) + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val file = dataRows[position] + if (holder.itemViewType == TYPE_VIDEO) { + bindVideoRes(holder, position, dataRows[position]) + } else { + bindImageRes(holder, dataRows[position]) + } + + holder.itemView.setOnClickListener { + itemClickedListener?.onItemClicked(file) + } + } + + abstract fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) + abstract fun bindImageRes(child: ViewHolder, item: File) + + private var itemClickedListener: OnItemClickedListener? = null + + interface OnItemClickedListener { + fun onItemClicked(item: File) + } + + fun setOnItemClickedListener(listener: OnItemClickedListener) { + itemClickedListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3336534..b4fb060 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,5 +33,10 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt new file mode 100644 index 0000000..28e22c9 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -0,0 +1,75 @@ +package com.casic.endoscope.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Environment +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.casic.endoscope.view.BigImageActivity +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.navigatePageTo +import java.io.File + +abstract class MediaDirAdapter( + private val context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val kTag = "MediaDirAdapter" + private var fileBeans = ArrayList() + private lateinit var fileAdapter: MediaFileAdapter + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(context).inflate(R.layout.item_dir_list_rv, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) { + val date = dataRows[position].name + holder.setText(R.id.dateView, date) + + //根据不同的日期显示不同的改日期下的九宫格形式子文件 + val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) + videoDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) + imageDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val realPaths = ArrayList() + fileBeans.forEach { + val absolutePath = it.absolutePath + if (!absolutePath.endsWith(".mp4")) { + realPaths.add(absolutePath) + } + } + + fileAdapter = object : MediaFileAdapter(context, fileBeans) { + override fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) { + bindChildVideoRes(child, childPos, item) + } + + override fun bindImageRes(child: ViewHolder, item: File) { + child.setImageResource(R.id.imageView, item.absolutePath) + } + } + val recyclerView = holder.getView(R.id.recyclerView) + recyclerView.adapter = fileAdapter + fileAdapter.setOnItemClickedListener(object : MediaFileAdapter.OnItemClickedListener { + override fun onItemClicked(item: File) { + if (!item.name.endsWith(".mp4")) { + context.navigatePageTo(position, realPaths) + } + } + }) + } + + abstract fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt new file mode 100644 index 0000000..e447913 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt @@ -0,0 +1,62 @@ +package com.casic.endoscope.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.pengxh.kt.lite.adapter.ViewHolder +import java.io.File + +abstract class MediaFileAdapter( + context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val inflater: LayoutInflater = LayoutInflater.from(context) + private val TYPE_VIDEO = 0 + private val TYPE_IMAGE = 1 + + override fun getItemCount(): Int = dataRows.size + + override fun getItemViewType(position: Int): Int { + return if (dataRows[position].name.endsWith(".mp4")) { + TYPE_VIDEO + } else { + TYPE_IMAGE + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return if (viewType == TYPE_VIDEO) { + ViewHolder(inflater.inflate(R.layout.item_video_list_gv, parent, false)) + } else { + ViewHolder(inflater.inflate(R.layout.item_image_list_gv, parent, false)) + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val file = dataRows[position] + if (holder.itemViewType == TYPE_VIDEO) { + bindVideoRes(holder, position, dataRows[position]) + } else { + bindImageRes(holder, dataRows[position]) + } + + holder.itemView.setOnClickListener { + itemClickedListener?.onItemClicked(file) + } + } + + abstract fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) + abstract fun bindImageRes(child: ViewHolder, item: File) + + private var itemClickedListener: OnItemClickedListener? = null + + interface OnItemClickedListener { + fun onItemClicked(item: File) + } + + fun setOnItemClickedListener(listener: OnItemClickedListener) { + itemClickedListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/extensions/Context.kt b/app/src/main/java/com/casic/endoscope/extensions/Context.kt index 0afcb27..a301aab 100644 --- a/app/src/main/java/com/casic/endoscope/extensions/Context.kt +++ b/app/src/main/java/com/casic/endoscope/extensions/Context.kt @@ -2,13 +2,22 @@ import android.content.Context import android.os.Environment +import com.pengxh.kt.lite.extensions.timestampToDate import java.io.File //扩展函数 fun Context.createVideoFileDir(): File { - val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), System.currentTimeMillis().timestampToDate()) if (!videoDir.exists()) { videoDir.mkdir() } return videoDir +} + +fun Context.createImageFileDir(): File { + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis().timestampToDate()) + if (!imageDir.exists()) { + imageDir.mkdir() + } + return imageDir } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3336534..b4fb060 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,5 +33,10 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt new file mode 100644 index 0000000..28e22c9 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -0,0 +1,75 @@ +package com.casic.endoscope.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Environment +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.casic.endoscope.view.BigImageActivity +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.navigatePageTo +import java.io.File + +abstract class MediaDirAdapter( + private val context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val kTag = "MediaDirAdapter" + private var fileBeans = ArrayList() + private lateinit var fileAdapter: MediaFileAdapter + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(context).inflate(R.layout.item_dir_list_rv, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) { + val date = dataRows[position].name + holder.setText(R.id.dateView, date) + + //根据不同的日期显示不同的改日期下的九宫格形式子文件 + val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) + videoDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) + imageDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val realPaths = ArrayList() + fileBeans.forEach { + val absolutePath = it.absolutePath + if (!absolutePath.endsWith(".mp4")) { + realPaths.add(absolutePath) + } + } + + fileAdapter = object : MediaFileAdapter(context, fileBeans) { + override fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) { + bindChildVideoRes(child, childPos, item) + } + + override fun bindImageRes(child: ViewHolder, item: File) { + child.setImageResource(R.id.imageView, item.absolutePath) + } + } + val recyclerView = holder.getView(R.id.recyclerView) + recyclerView.adapter = fileAdapter + fileAdapter.setOnItemClickedListener(object : MediaFileAdapter.OnItemClickedListener { + override fun onItemClicked(item: File) { + if (!item.name.endsWith(".mp4")) { + context.navigatePageTo(position, realPaths) + } + } + }) + } + + abstract fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt new file mode 100644 index 0000000..e447913 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt @@ -0,0 +1,62 @@ +package com.casic.endoscope.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.pengxh.kt.lite.adapter.ViewHolder +import java.io.File + +abstract class MediaFileAdapter( + context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val inflater: LayoutInflater = LayoutInflater.from(context) + private val TYPE_VIDEO = 0 + private val TYPE_IMAGE = 1 + + override fun getItemCount(): Int = dataRows.size + + override fun getItemViewType(position: Int): Int { + return if (dataRows[position].name.endsWith(".mp4")) { + TYPE_VIDEO + } else { + TYPE_IMAGE + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return if (viewType == TYPE_VIDEO) { + ViewHolder(inflater.inflate(R.layout.item_video_list_gv, parent, false)) + } else { + ViewHolder(inflater.inflate(R.layout.item_image_list_gv, parent, false)) + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val file = dataRows[position] + if (holder.itemViewType == TYPE_VIDEO) { + bindVideoRes(holder, position, dataRows[position]) + } else { + bindImageRes(holder, dataRows[position]) + } + + holder.itemView.setOnClickListener { + itemClickedListener?.onItemClicked(file) + } + } + + abstract fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) + abstract fun bindImageRes(child: ViewHolder, item: File) + + private var itemClickedListener: OnItemClickedListener? = null + + interface OnItemClickedListener { + fun onItemClicked(item: File) + } + + fun setOnItemClickedListener(listener: OnItemClickedListener) { + itemClickedListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/extensions/Context.kt b/app/src/main/java/com/casic/endoscope/extensions/Context.kt index 0afcb27..a301aab 100644 --- a/app/src/main/java/com/casic/endoscope/extensions/Context.kt +++ b/app/src/main/java/com/casic/endoscope/extensions/Context.kt @@ -2,13 +2,22 @@ import android.content.Context import android.os.Environment +import com.pengxh.kt.lite.extensions.timestampToDate import java.io.File //扩展函数 fun Context.createVideoFileDir(): File { - val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), System.currentTimeMillis().timestampToDate()) if (!videoDir.exists()) { videoDir.mkdir() } return videoDir +} + +fun Context.createImageFileDir(): File { + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis().timestampToDate()) + if (!imageDir.exists()) { + imageDir.mkdir() + } + return imageDir } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt index c0020ec..8c4b495 100644 --- a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt @@ -1,32 +1,127 @@ package com.casic.endoscope.view +import android.annotation.SuppressLint +import android.content.pm.ActivityInfo import android.os.Bundle -import android.util.Log +import android.os.Environment +import android.view.View +import android.widget.ImageView +import androidx.activity.OnBackPressedCallback +import androidx.lifecycle.lifecycleScope +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.adapter.MediaDirAdapter import com.casic.endoscope.databinding.ActivityAlbumBinding -import com.casic.endoscope.extensions.createVideoFileDir import com.gyf.immersionbar.ImmersionBar +import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getStatusBarHeight +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File class AlbumActivity : KotlinBaseActivity() { private val kTag = "AlbumActivity" + private val context = this@AlbumActivity + //子文件夹集合 + private var dirBeans = ArrayList() + private lateinit var directoryAdapter: MediaDirAdapter + + @SuppressLint("NotifyDataSetChanged") override fun initEvent() { + binding.ascButton.setOnClickListener { + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + binding.decButton.setOnClickListener { + //升序 + dirBeans.sortBy { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + + //替换onBackPressed + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + GSYVideoManager.backFromWindowFull(context) + //解决退出全屏后会被强制竖屏的问题 + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { - val videoDir = createVideoFileDir() - videoDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val temp = ArrayList() + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + videoDir.list()?.forEach { + temp.add(it) } - val imageDir = createImageFileDir() - imageDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + imageDir.list()?.forEach { + temp.add(it) } + + //去重 + val directoryNameSet = HashSet(temp) + + //全部转为File类型,方便是用自带的排序函数 + directoryNameSet.forEach { + dirBeans.add(File(it)) + } + + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + + //绑定数据 + directoryAdapter = object : MediaDirAdapter(this, dirBeans) { + override fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) { + val videoPlayer = child.getView(R.id.videoPlayer) + videoPlayer.titleTextView.visibility = View.GONE + videoPlayer.backButton.visibility = View.GONE + lifecycleScope.launch(Dispatchers.Main) { + try { + val drawable = withContext(Dispatchers.IO) { + Glide.with(context) + .load(item) + .submit() + .get() + } + val coverImg = ImageView(context) + coverImg.setImageDrawable(drawable) + videoPlayer.thumbImageView = coverImg + } catch (e: Exception) { + e.printStackTrace() + } + } + videoPlayer.setUp(item.absolutePath, true, "") + videoPlayer.fullscreenButton.setOnClickListener { + videoPlayer.startWindowFullscreen(context, false, true) + } + //防止错位设置 + videoPlayer.playTag = System.currentTimeMillis().toString() + videoPlayer.playPosition = childPos + //是否根据视频尺寸,自动选择竖屏全屏或者横屏全屏 + videoPlayer.isAutoFullWithSize = true + //音频焦点冲突时是否释放 + videoPlayer.isReleaseWhenLossAudio = false + //全屏动画 + videoPlayer.isShowFullAnimation = true + } + } + val offset = 10.dp2px(this) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(offset, offset, offset, offset) + ) + binding.recyclerView.adapter = directoryAdapter } override fun initViewBinding(): ActivityAlbumBinding { @@ -44,4 +139,19 @@ binding.rootView.setPadding(0, statusBarHeight, 0, 0) binding.rootView.requestLayout() } + + override fun onPause() { + super.onPause() + GSYVideoManager.onPause() + } + + override fun onResume() { + super.onResume() + GSYVideoManager.onResume() + } + + override fun onDestroy() { + super.onDestroy() + GSYVideoManager.releaseAllVideos() + } } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3336534..b4fb060 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,5 +33,10 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt new file mode 100644 index 0000000..28e22c9 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -0,0 +1,75 @@ +package com.casic.endoscope.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Environment +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.casic.endoscope.view.BigImageActivity +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.navigatePageTo +import java.io.File + +abstract class MediaDirAdapter( + private val context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val kTag = "MediaDirAdapter" + private var fileBeans = ArrayList() + private lateinit var fileAdapter: MediaFileAdapter + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(context).inflate(R.layout.item_dir_list_rv, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) { + val date = dataRows[position].name + holder.setText(R.id.dateView, date) + + //根据不同的日期显示不同的改日期下的九宫格形式子文件 + val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) + videoDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) + imageDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val realPaths = ArrayList() + fileBeans.forEach { + val absolutePath = it.absolutePath + if (!absolutePath.endsWith(".mp4")) { + realPaths.add(absolutePath) + } + } + + fileAdapter = object : MediaFileAdapter(context, fileBeans) { + override fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) { + bindChildVideoRes(child, childPos, item) + } + + override fun bindImageRes(child: ViewHolder, item: File) { + child.setImageResource(R.id.imageView, item.absolutePath) + } + } + val recyclerView = holder.getView(R.id.recyclerView) + recyclerView.adapter = fileAdapter + fileAdapter.setOnItemClickedListener(object : MediaFileAdapter.OnItemClickedListener { + override fun onItemClicked(item: File) { + if (!item.name.endsWith(".mp4")) { + context.navigatePageTo(position, realPaths) + } + } + }) + } + + abstract fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt new file mode 100644 index 0000000..e447913 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt @@ -0,0 +1,62 @@ +package com.casic.endoscope.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.pengxh.kt.lite.adapter.ViewHolder +import java.io.File + +abstract class MediaFileAdapter( + context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val inflater: LayoutInflater = LayoutInflater.from(context) + private val TYPE_VIDEO = 0 + private val TYPE_IMAGE = 1 + + override fun getItemCount(): Int = dataRows.size + + override fun getItemViewType(position: Int): Int { + return if (dataRows[position].name.endsWith(".mp4")) { + TYPE_VIDEO + } else { + TYPE_IMAGE + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return if (viewType == TYPE_VIDEO) { + ViewHolder(inflater.inflate(R.layout.item_video_list_gv, parent, false)) + } else { + ViewHolder(inflater.inflate(R.layout.item_image_list_gv, parent, false)) + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val file = dataRows[position] + if (holder.itemViewType == TYPE_VIDEO) { + bindVideoRes(holder, position, dataRows[position]) + } else { + bindImageRes(holder, dataRows[position]) + } + + holder.itemView.setOnClickListener { + itemClickedListener?.onItemClicked(file) + } + } + + abstract fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) + abstract fun bindImageRes(child: ViewHolder, item: File) + + private var itemClickedListener: OnItemClickedListener? = null + + interface OnItemClickedListener { + fun onItemClicked(item: File) + } + + fun setOnItemClickedListener(listener: OnItemClickedListener) { + itemClickedListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/extensions/Context.kt b/app/src/main/java/com/casic/endoscope/extensions/Context.kt index 0afcb27..a301aab 100644 --- a/app/src/main/java/com/casic/endoscope/extensions/Context.kt +++ b/app/src/main/java/com/casic/endoscope/extensions/Context.kt @@ -2,13 +2,22 @@ import android.content.Context import android.os.Environment +import com.pengxh.kt.lite.extensions.timestampToDate import java.io.File //扩展函数 fun Context.createVideoFileDir(): File { - val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), System.currentTimeMillis().timestampToDate()) if (!videoDir.exists()) { videoDir.mkdir() } return videoDir +} + +fun Context.createImageFileDir(): File { + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis().timestampToDate()) + if (!imageDir.exists()) { + imageDir.mkdir() + } + return imageDir } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt index c0020ec..8c4b495 100644 --- a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt @@ -1,32 +1,127 @@ package com.casic.endoscope.view +import android.annotation.SuppressLint +import android.content.pm.ActivityInfo import android.os.Bundle -import android.util.Log +import android.os.Environment +import android.view.View +import android.widget.ImageView +import androidx.activity.OnBackPressedCallback +import androidx.lifecycle.lifecycleScope +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.adapter.MediaDirAdapter import com.casic.endoscope.databinding.ActivityAlbumBinding -import com.casic.endoscope.extensions.createVideoFileDir import com.gyf.immersionbar.ImmersionBar +import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getStatusBarHeight +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File class AlbumActivity : KotlinBaseActivity() { private val kTag = "AlbumActivity" + private val context = this@AlbumActivity + //子文件夹集合 + private var dirBeans = ArrayList() + private lateinit var directoryAdapter: MediaDirAdapter + + @SuppressLint("NotifyDataSetChanged") override fun initEvent() { + binding.ascButton.setOnClickListener { + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + binding.decButton.setOnClickListener { + //升序 + dirBeans.sortBy { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + + //替换onBackPressed + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + GSYVideoManager.backFromWindowFull(context) + //解决退出全屏后会被强制竖屏的问题 + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { - val videoDir = createVideoFileDir() - videoDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val temp = ArrayList() + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + videoDir.list()?.forEach { + temp.add(it) } - val imageDir = createImageFileDir() - imageDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + imageDir.list()?.forEach { + temp.add(it) } + + //去重 + val directoryNameSet = HashSet(temp) + + //全部转为File类型,方便是用自带的排序函数 + directoryNameSet.forEach { + dirBeans.add(File(it)) + } + + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + + //绑定数据 + directoryAdapter = object : MediaDirAdapter(this, dirBeans) { + override fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) { + val videoPlayer = child.getView(R.id.videoPlayer) + videoPlayer.titleTextView.visibility = View.GONE + videoPlayer.backButton.visibility = View.GONE + lifecycleScope.launch(Dispatchers.Main) { + try { + val drawable = withContext(Dispatchers.IO) { + Glide.with(context) + .load(item) + .submit() + .get() + } + val coverImg = ImageView(context) + coverImg.setImageDrawable(drawable) + videoPlayer.thumbImageView = coverImg + } catch (e: Exception) { + e.printStackTrace() + } + } + videoPlayer.setUp(item.absolutePath, true, "") + videoPlayer.fullscreenButton.setOnClickListener { + videoPlayer.startWindowFullscreen(context, false, true) + } + //防止错位设置 + videoPlayer.playTag = System.currentTimeMillis().toString() + videoPlayer.playPosition = childPos + //是否根据视频尺寸,自动选择竖屏全屏或者横屏全屏 + videoPlayer.isAutoFullWithSize = true + //音频焦点冲突时是否释放 + videoPlayer.isReleaseWhenLossAudio = false + //全屏动画 + videoPlayer.isShowFullAnimation = true + } + } + val offset = 10.dp2px(this) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(offset, offset, offset, offset) + ) + binding.recyclerView.adapter = directoryAdapter } override fun initViewBinding(): ActivityAlbumBinding { @@ -44,4 +139,19 @@ binding.rootView.setPadding(0, statusBarHeight, 0, 0) binding.rootView.requestLayout() } + + override fun onPause() { + super.onPause() + GSYVideoManager.onPause() + } + + override fun onResume() { + super.onResume() + GSYVideoManager.onResume() + } + + override fun onDestroy() { + super.onDestroy() + GSYVideoManager.releaseAllVideos() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt new file mode 100644 index 0000000..c0aa2b3 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt @@ -0,0 +1,90 @@ +package com.casic.endoscope.view + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.databinding.ActivityBigImageBinding +import com.casic.endoscope.extensions.initImmersionBar +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant + +class BigImageActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityBigImageBinding { + return ActivityBigImageBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + binding.rootView.initImmersionBar(this, false, R.color.black) + binding.leftBackView.setOnClickListener { finish() } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + val index = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + binding.pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + binding.imagePagerView.adapter = BigImageAdapter(this, urls) + binding.imagePagerView.currentItem = index + binding.imagePagerView.offscreenPageLimit = imageSize + binding.imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + binding.pageNumberView.text = + String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3336534..b4fb060 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,5 +33,10 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt new file mode 100644 index 0000000..28e22c9 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -0,0 +1,75 @@ +package com.casic.endoscope.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Environment +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.casic.endoscope.view.BigImageActivity +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.navigatePageTo +import java.io.File + +abstract class MediaDirAdapter( + private val context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val kTag = "MediaDirAdapter" + private var fileBeans = ArrayList() + private lateinit var fileAdapter: MediaFileAdapter + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(context).inflate(R.layout.item_dir_list_rv, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) { + val date = dataRows[position].name + holder.setText(R.id.dateView, date) + + //根据不同的日期显示不同的改日期下的九宫格形式子文件 + val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) + videoDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) + imageDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val realPaths = ArrayList() + fileBeans.forEach { + val absolutePath = it.absolutePath + if (!absolutePath.endsWith(".mp4")) { + realPaths.add(absolutePath) + } + } + + fileAdapter = object : MediaFileAdapter(context, fileBeans) { + override fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) { + bindChildVideoRes(child, childPos, item) + } + + override fun bindImageRes(child: ViewHolder, item: File) { + child.setImageResource(R.id.imageView, item.absolutePath) + } + } + val recyclerView = holder.getView(R.id.recyclerView) + recyclerView.adapter = fileAdapter + fileAdapter.setOnItemClickedListener(object : MediaFileAdapter.OnItemClickedListener { + override fun onItemClicked(item: File) { + if (!item.name.endsWith(".mp4")) { + context.navigatePageTo(position, realPaths) + } + } + }) + } + + abstract fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt new file mode 100644 index 0000000..e447913 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt @@ -0,0 +1,62 @@ +package com.casic.endoscope.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.pengxh.kt.lite.adapter.ViewHolder +import java.io.File + +abstract class MediaFileAdapter( + context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val inflater: LayoutInflater = LayoutInflater.from(context) + private val TYPE_VIDEO = 0 + private val TYPE_IMAGE = 1 + + override fun getItemCount(): Int = dataRows.size + + override fun getItemViewType(position: Int): Int { + return if (dataRows[position].name.endsWith(".mp4")) { + TYPE_VIDEO + } else { + TYPE_IMAGE + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return if (viewType == TYPE_VIDEO) { + ViewHolder(inflater.inflate(R.layout.item_video_list_gv, parent, false)) + } else { + ViewHolder(inflater.inflate(R.layout.item_image_list_gv, parent, false)) + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val file = dataRows[position] + if (holder.itemViewType == TYPE_VIDEO) { + bindVideoRes(holder, position, dataRows[position]) + } else { + bindImageRes(holder, dataRows[position]) + } + + holder.itemView.setOnClickListener { + itemClickedListener?.onItemClicked(file) + } + } + + abstract fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) + abstract fun bindImageRes(child: ViewHolder, item: File) + + private var itemClickedListener: OnItemClickedListener? = null + + interface OnItemClickedListener { + fun onItemClicked(item: File) + } + + fun setOnItemClickedListener(listener: OnItemClickedListener) { + itemClickedListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/extensions/Context.kt b/app/src/main/java/com/casic/endoscope/extensions/Context.kt index 0afcb27..a301aab 100644 --- a/app/src/main/java/com/casic/endoscope/extensions/Context.kt +++ b/app/src/main/java/com/casic/endoscope/extensions/Context.kt @@ -2,13 +2,22 @@ import android.content.Context import android.os.Environment +import com.pengxh.kt.lite.extensions.timestampToDate import java.io.File //扩展函数 fun Context.createVideoFileDir(): File { - val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), System.currentTimeMillis().timestampToDate()) if (!videoDir.exists()) { videoDir.mkdir() } return videoDir +} + +fun Context.createImageFileDir(): File { + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis().timestampToDate()) + if (!imageDir.exists()) { + imageDir.mkdir() + } + return imageDir } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt index c0020ec..8c4b495 100644 --- a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt @@ -1,32 +1,127 @@ package com.casic.endoscope.view +import android.annotation.SuppressLint +import android.content.pm.ActivityInfo import android.os.Bundle -import android.util.Log +import android.os.Environment +import android.view.View +import android.widget.ImageView +import androidx.activity.OnBackPressedCallback +import androidx.lifecycle.lifecycleScope +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.adapter.MediaDirAdapter import com.casic.endoscope.databinding.ActivityAlbumBinding -import com.casic.endoscope.extensions.createVideoFileDir import com.gyf.immersionbar.ImmersionBar +import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getStatusBarHeight +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File class AlbumActivity : KotlinBaseActivity() { private val kTag = "AlbumActivity" + private val context = this@AlbumActivity + //子文件夹集合 + private var dirBeans = ArrayList() + private lateinit var directoryAdapter: MediaDirAdapter + + @SuppressLint("NotifyDataSetChanged") override fun initEvent() { + binding.ascButton.setOnClickListener { + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + binding.decButton.setOnClickListener { + //升序 + dirBeans.sortBy { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + + //替换onBackPressed + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + GSYVideoManager.backFromWindowFull(context) + //解决退出全屏后会被强制竖屏的问题 + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { - val videoDir = createVideoFileDir() - videoDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val temp = ArrayList() + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + videoDir.list()?.forEach { + temp.add(it) } - val imageDir = createImageFileDir() - imageDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + imageDir.list()?.forEach { + temp.add(it) } + + //去重 + val directoryNameSet = HashSet(temp) + + //全部转为File类型,方便是用自带的排序函数 + directoryNameSet.forEach { + dirBeans.add(File(it)) + } + + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + + //绑定数据 + directoryAdapter = object : MediaDirAdapter(this, dirBeans) { + override fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) { + val videoPlayer = child.getView(R.id.videoPlayer) + videoPlayer.titleTextView.visibility = View.GONE + videoPlayer.backButton.visibility = View.GONE + lifecycleScope.launch(Dispatchers.Main) { + try { + val drawable = withContext(Dispatchers.IO) { + Glide.with(context) + .load(item) + .submit() + .get() + } + val coverImg = ImageView(context) + coverImg.setImageDrawable(drawable) + videoPlayer.thumbImageView = coverImg + } catch (e: Exception) { + e.printStackTrace() + } + } + videoPlayer.setUp(item.absolutePath, true, "") + videoPlayer.fullscreenButton.setOnClickListener { + videoPlayer.startWindowFullscreen(context, false, true) + } + //防止错位设置 + videoPlayer.playTag = System.currentTimeMillis().toString() + videoPlayer.playPosition = childPos + //是否根据视频尺寸,自动选择竖屏全屏或者横屏全屏 + videoPlayer.isAutoFullWithSize = true + //音频焦点冲突时是否释放 + videoPlayer.isReleaseWhenLossAudio = false + //全屏动画 + videoPlayer.isShowFullAnimation = true + } + } + val offset = 10.dp2px(this) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(offset, offset, offset, offset) + ) + binding.recyclerView.adapter = directoryAdapter } override fun initViewBinding(): ActivityAlbumBinding { @@ -44,4 +139,19 @@ binding.rootView.setPadding(0, statusBarHeight, 0, 0) binding.rootView.requestLayout() } + + override fun onPause() { + super.onPause() + GSYVideoManager.onPause() + } + + override fun onResume() { + super.onResume() + GSYVideoManager.onResume() + } + + override fun onDestroy() { + super.onDestroy() + GSYVideoManager.releaseAllVideos() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt new file mode 100644 index 0000000..c0aa2b3 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt @@ -0,0 +1,90 @@ +package com.casic.endoscope.view + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.databinding.ActivityBigImageBinding +import com.casic.endoscope.extensions.initImmersionBar +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant + +class BigImageActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityBigImageBinding { + return ActivityBigImageBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + binding.rootView.initImmersionBar(this, false, R.color.black) + binding.leftBackView.setOnClickListener { finish() } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + val index = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + binding.pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + binding.imagePagerView.adapter = BigImageAdapter(this, urls) + binding.imagePagerView.currentItem = index + binding.imagePagerView.offscreenPageLimit = imageSize + binding.imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + binding.pageNumberView.text = + String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt index 8c1a5dd..d05c4c5 100644 --- a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt @@ -14,6 +14,7 @@ import com.casic.endoscope.adapter.CameraPointAdapter import com.casic.endoscope.bean.CameraPointBean import com.casic.endoscope.databinding.ActivityMainBinding +import com.casic.endoscope.extensions.createImageFileDir import com.casic.endoscope.extensions.createVideoFileDir import com.casic.endoscope.extensions.getChannel import com.casic.endoscope.extensions.toTime @@ -28,7 +29,6 @@ import com.hikvision.netsdk.NET_DVR_PREVIEWINFO import com.hikvision.netsdk.PTZCommand import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir import com.pengxh.kt.lite.extensions.getStatusBarHeight import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3336534..b4fb060 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,5 +33,10 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt new file mode 100644 index 0000000..28e22c9 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -0,0 +1,75 @@ +package com.casic.endoscope.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Environment +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.casic.endoscope.view.BigImageActivity +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.navigatePageTo +import java.io.File + +abstract class MediaDirAdapter( + private val context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val kTag = "MediaDirAdapter" + private var fileBeans = ArrayList() + private lateinit var fileAdapter: MediaFileAdapter + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(context).inflate(R.layout.item_dir_list_rv, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) { + val date = dataRows[position].name + holder.setText(R.id.dateView, date) + + //根据不同的日期显示不同的改日期下的九宫格形式子文件 + val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) + videoDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) + imageDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val realPaths = ArrayList() + fileBeans.forEach { + val absolutePath = it.absolutePath + if (!absolutePath.endsWith(".mp4")) { + realPaths.add(absolutePath) + } + } + + fileAdapter = object : MediaFileAdapter(context, fileBeans) { + override fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) { + bindChildVideoRes(child, childPos, item) + } + + override fun bindImageRes(child: ViewHolder, item: File) { + child.setImageResource(R.id.imageView, item.absolutePath) + } + } + val recyclerView = holder.getView(R.id.recyclerView) + recyclerView.adapter = fileAdapter + fileAdapter.setOnItemClickedListener(object : MediaFileAdapter.OnItemClickedListener { + override fun onItemClicked(item: File) { + if (!item.name.endsWith(".mp4")) { + context.navigatePageTo(position, realPaths) + } + } + }) + } + + abstract fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt new file mode 100644 index 0000000..e447913 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt @@ -0,0 +1,62 @@ +package com.casic.endoscope.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.pengxh.kt.lite.adapter.ViewHolder +import java.io.File + +abstract class MediaFileAdapter( + context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val inflater: LayoutInflater = LayoutInflater.from(context) + private val TYPE_VIDEO = 0 + private val TYPE_IMAGE = 1 + + override fun getItemCount(): Int = dataRows.size + + override fun getItemViewType(position: Int): Int { + return if (dataRows[position].name.endsWith(".mp4")) { + TYPE_VIDEO + } else { + TYPE_IMAGE + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return if (viewType == TYPE_VIDEO) { + ViewHolder(inflater.inflate(R.layout.item_video_list_gv, parent, false)) + } else { + ViewHolder(inflater.inflate(R.layout.item_image_list_gv, parent, false)) + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val file = dataRows[position] + if (holder.itemViewType == TYPE_VIDEO) { + bindVideoRes(holder, position, dataRows[position]) + } else { + bindImageRes(holder, dataRows[position]) + } + + holder.itemView.setOnClickListener { + itemClickedListener?.onItemClicked(file) + } + } + + abstract fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) + abstract fun bindImageRes(child: ViewHolder, item: File) + + private var itemClickedListener: OnItemClickedListener? = null + + interface OnItemClickedListener { + fun onItemClicked(item: File) + } + + fun setOnItemClickedListener(listener: OnItemClickedListener) { + itemClickedListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/extensions/Context.kt b/app/src/main/java/com/casic/endoscope/extensions/Context.kt index 0afcb27..a301aab 100644 --- a/app/src/main/java/com/casic/endoscope/extensions/Context.kt +++ b/app/src/main/java/com/casic/endoscope/extensions/Context.kt @@ -2,13 +2,22 @@ import android.content.Context import android.os.Environment +import com.pengxh.kt.lite.extensions.timestampToDate import java.io.File //扩展函数 fun Context.createVideoFileDir(): File { - val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), System.currentTimeMillis().timestampToDate()) if (!videoDir.exists()) { videoDir.mkdir() } return videoDir +} + +fun Context.createImageFileDir(): File { + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis().timestampToDate()) + if (!imageDir.exists()) { + imageDir.mkdir() + } + return imageDir } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt index c0020ec..8c4b495 100644 --- a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt @@ -1,32 +1,127 @@ package com.casic.endoscope.view +import android.annotation.SuppressLint +import android.content.pm.ActivityInfo import android.os.Bundle -import android.util.Log +import android.os.Environment +import android.view.View +import android.widget.ImageView +import androidx.activity.OnBackPressedCallback +import androidx.lifecycle.lifecycleScope +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.adapter.MediaDirAdapter import com.casic.endoscope.databinding.ActivityAlbumBinding -import com.casic.endoscope.extensions.createVideoFileDir import com.gyf.immersionbar.ImmersionBar +import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getStatusBarHeight +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File class AlbumActivity : KotlinBaseActivity() { private val kTag = "AlbumActivity" + private val context = this@AlbumActivity + //子文件夹集合 + private var dirBeans = ArrayList() + private lateinit var directoryAdapter: MediaDirAdapter + + @SuppressLint("NotifyDataSetChanged") override fun initEvent() { + binding.ascButton.setOnClickListener { + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + binding.decButton.setOnClickListener { + //升序 + dirBeans.sortBy { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + + //替换onBackPressed + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + GSYVideoManager.backFromWindowFull(context) + //解决退出全屏后会被强制竖屏的问题 + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { - val videoDir = createVideoFileDir() - videoDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val temp = ArrayList() + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + videoDir.list()?.forEach { + temp.add(it) } - val imageDir = createImageFileDir() - imageDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + imageDir.list()?.forEach { + temp.add(it) } + + //去重 + val directoryNameSet = HashSet(temp) + + //全部转为File类型,方便是用自带的排序函数 + directoryNameSet.forEach { + dirBeans.add(File(it)) + } + + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + + //绑定数据 + directoryAdapter = object : MediaDirAdapter(this, dirBeans) { + override fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) { + val videoPlayer = child.getView(R.id.videoPlayer) + videoPlayer.titleTextView.visibility = View.GONE + videoPlayer.backButton.visibility = View.GONE + lifecycleScope.launch(Dispatchers.Main) { + try { + val drawable = withContext(Dispatchers.IO) { + Glide.with(context) + .load(item) + .submit() + .get() + } + val coverImg = ImageView(context) + coverImg.setImageDrawable(drawable) + videoPlayer.thumbImageView = coverImg + } catch (e: Exception) { + e.printStackTrace() + } + } + videoPlayer.setUp(item.absolutePath, true, "") + videoPlayer.fullscreenButton.setOnClickListener { + videoPlayer.startWindowFullscreen(context, false, true) + } + //防止错位设置 + videoPlayer.playTag = System.currentTimeMillis().toString() + videoPlayer.playPosition = childPos + //是否根据视频尺寸,自动选择竖屏全屏或者横屏全屏 + videoPlayer.isAutoFullWithSize = true + //音频焦点冲突时是否释放 + videoPlayer.isReleaseWhenLossAudio = false + //全屏动画 + videoPlayer.isShowFullAnimation = true + } + } + val offset = 10.dp2px(this) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(offset, offset, offset, offset) + ) + binding.recyclerView.adapter = directoryAdapter } override fun initViewBinding(): ActivityAlbumBinding { @@ -44,4 +139,19 @@ binding.rootView.setPadding(0, statusBarHeight, 0, 0) binding.rootView.requestLayout() } + + override fun onPause() { + super.onPause() + GSYVideoManager.onPause() + } + + override fun onResume() { + super.onResume() + GSYVideoManager.onResume() + } + + override fun onDestroy() { + super.onDestroy() + GSYVideoManager.releaseAllVideos() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt new file mode 100644 index 0000000..c0aa2b3 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt @@ -0,0 +1,90 @@ +package com.casic.endoscope.view + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.databinding.ActivityBigImageBinding +import com.casic.endoscope.extensions.initImmersionBar +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant + +class BigImageActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityBigImageBinding { + return ActivityBigImageBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + binding.rootView.initImmersionBar(this, false, R.color.black) + binding.leftBackView.setOnClickListener { finish() } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + val index = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + binding.pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + binding.imagePagerView.adapter = BigImageAdapter(this, urls) + binding.imagePagerView.currentItem = index + binding.imagePagerView.offscreenPageLimit = imageSize + binding.imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + binding.pageNumberView.text = + String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt index 8c1a5dd..d05c4c5 100644 --- a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt @@ -14,6 +14,7 @@ import com.casic.endoscope.adapter.CameraPointAdapter import com.casic.endoscope.bean.CameraPointBean import com.casic.endoscope.databinding.ActivityMainBinding +import com.casic.endoscope.extensions.createImageFileDir import com.casic.endoscope.extensions.createVideoFileDir import com.casic.endoscope.extensions.getChannel import com.casic.endoscope.extensions.toTime @@ -28,7 +29,6 @@ import com.hikvision.netsdk.NET_DVR_PREVIEWINFO import com.hikvision.netsdk.PTZCommand import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir import com.pengxh.kt.lite.extensions.getStatusBarHeight import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show diff --git a/app/src/main/res/anim/activity_in.xml b/app/src/main/res/anim/activity_in.xml new file mode 100644 index 0000000..f2696ba --- /dev/null +++ b/app/src/main/res/anim/activity_in.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3336534..b4fb060 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,5 +33,10 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt new file mode 100644 index 0000000..28e22c9 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -0,0 +1,75 @@ +package com.casic.endoscope.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Environment +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.casic.endoscope.view.BigImageActivity +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.navigatePageTo +import java.io.File + +abstract class MediaDirAdapter( + private val context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val kTag = "MediaDirAdapter" + private var fileBeans = ArrayList() + private lateinit var fileAdapter: MediaFileAdapter + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(context).inflate(R.layout.item_dir_list_rv, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) { + val date = dataRows[position].name + holder.setText(R.id.dateView, date) + + //根据不同的日期显示不同的改日期下的九宫格形式子文件 + val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) + videoDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) + imageDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val realPaths = ArrayList() + fileBeans.forEach { + val absolutePath = it.absolutePath + if (!absolutePath.endsWith(".mp4")) { + realPaths.add(absolutePath) + } + } + + fileAdapter = object : MediaFileAdapter(context, fileBeans) { + override fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) { + bindChildVideoRes(child, childPos, item) + } + + override fun bindImageRes(child: ViewHolder, item: File) { + child.setImageResource(R.id.imageView, item.absolutePath) + } + } + val recyclerView = holder.getView(R.id.recyclerView) + recyclerView.adapter = fileAdapter + fileAdapter.setOnItemClickedListener(object : MediaFileAdapter.OnItemClickedListener { + override fun onItemClicked(item: File) { + if (!item.name.endsWith(".mp4")) { + context.navigatePageTo(position, realPaths) + } + } + }) + } + + abstract fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt new file mode 100644 index 0000000..e447913 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt @@ -0,0 +1,62 @@ +package com.casic.endoscope.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.pengxh.kt.lite.adapter.ViewHolder +import java.io.File + +abstract class MediaFileAdapter( + context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val inflater: LayoutInflater = LayoutInflater.from(context) + private val TYPE_VIDEO = 0 + private val TYPE_IMAGE = 1 + + override fun getItemCount(): Int = dataRows.size + + override fun getItemViewType(position: Int): Int { + return if (dataRows[position].name.endsWith(".mp4")) { + TYPE_VIDEO + } else { + TYPE_IMAGE + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return if (viewType == TYPE_VIDEO) { + ViewHolder(inflater.inflate(R.layout.item_video_list_gv, parent, false)) + } else { + ViewHolder(inflater.inflate(R.layout.item_image_list_gv, parent, false)) + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val file = dataRows[position] + if (holder.itemViewType == TYPE_VIDEO) { + bindVideoRes(holder, position, dataRows[position]) + } else { + bindImageRes(holder, dataRows[position]) + } + + holder.itemView.setOnClickListener { + itemClickedListener?.onItemClicked(file) + } + } + + abstract fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) + abstract fun bindImageRes(child: ViewHolder, item: File) + + private var itemClickedListener: OnItemClickedListener? = null + + interface OnItemClickedListener { + fun onItemClicked(item: File) + } + + fun setOnItemClickedListener(listener: OnItemClickedListener) { + itemClickedListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/extensions/Context.kt b/app/src/main/java/com/casic/endoscope/extensions/Context.kt index 0afcb27..a301aab 100644 --- a/app/src/main/java/com/casic/endoscope/extensions/Context.kt +++ b/app/src/main/java/com/casic/endoscope/extensions/Context.kt @@ -2,13 +2,22 @@ import android.content.Context import android.os.Environment +import com.pengxh.kt.lite.extensions.timestampToDate import java.io.File //扩展函数 fun Context.createVideoFileDir(): File { - val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), System.currentTimeMillis().timestampToDate()) if (!videoDir.exists()) { videoDir.mkdir() } return videoDir +} + +fun Context.createImageFileDir(): File { + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis().timestampToDate()) + if (!imageDir.exists()) { + imageDir.mkdir() + } + return imageDir } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt index c0020ec..8c4b495 100644 --- a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt @@ -1,32 +1,127 @@ package com.casic.endoscope.view +import android.annotation.SuppressLint +import android.content.pm.ActivityInfo import android.os.Bundle -import android.util.Log +import android.os.Environment +import android.view.View +import android.widget.ImageView +import androidx.activity.OnBackPressedCallback +import androidx.lifecycle.lifecycleScope +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.adapter.MediaDirAdapter import com.casic.endoscope.databinding.ActivityAlbumBinding -import com.casic.endoscope.extensions.createVideoFileDir import com.gyf.immersionbar.ImmersionBar +import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getStatusBarHeight +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File class AlbumActivity : KotlinBaseActivity() { private val kTag = "AlbumActivity" + private val context = this@AlbumActivity + //子文件夹集合 + private var dirBeans = ArrayList() + private lateinit var directoryAdapter: MediaDirAdapter + + @SuppressLint("NotifyDataSetChanged") override fun initEvent() { + binding.ascButton.setOnClickListener { + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + binding.decButton.setOnClickListener { + //升序 + dirBeans.sortBy { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + + //替换onBackPressed + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + GSYVideoManager.backFromWindowFull(context) + //解决退出全屏后会被强制竖屏的问题 + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { - val videoDir = createVideoFileDir() - videoDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val temp = ArrayList() + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + videoDir.list()?.forEach { + temp.add(it) } - val imageDir = createImageFileDir() - imageDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + imageDir.list()?.forEach { + temp.add(it) } + + //去重 + val directoryNameSet = HashSet(temp) + + //全部转为File类型,方便是用自带的排序函数 + directoryNameSet.forEach { + dirBeans.add(File(it)) + } + + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + + //绑定数据 + directoryAdapter = object : MediaDirAdapter(this, dirBeans) { + override fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) { + val videoPlayer = child.getView(R.id.videoPlayer) + videoPlayer.titleTextView.visibility = View.GONE + videoPlayer.backButton.visibility = View.GONE + lifecycleScope.launch(Dispatchers.Main) { + try { + val drawable = withContext(Dispatchers.IO) { + Glide.with(context) + .load(item) + .submit() + .get() + } + val coverImg = ImageView(context) + coverImg.setImageDrawable(drawable) + videoPlayer.thumbImageView = coverImg + } catch (e: Exception) { + e.printStackTrace() + } + } + videoPlayer.setUp(item.absolutePath, true, "") + videoPlayer.fullscreenButton.setOnClickListener { + videoPlayer.startWindowFullscreen(context, false, true) + } + //防止错位设置 + videoPlayer.playTag = System.currentTimeMillis().toString() + videoPlayer.playPosition = childPos + //是否根据视频尺寸,自动选择竖屏全屏或者横屏全屏 + videoPlayer.isAutoFullWithSize = true + //音频焦点冲突时是否释放 + videoPlayer.isReleaseWhenLossAudio = false + //全屏动画 + videoPlayer.isShowFullAnimation = true + } + } + val offset = 10.dp2px(this) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(offset, offset, offset, offset) + ) + binding.recyclerView.adapter = directoryAdapter } override fun initViewBinding(): ActivityAlbumBinding { @@ -44,4 +139,19 @@ binding.rootView.setPadding(0, statusBarHeight, 0, 0) binding.rootView.requestLayout() } + + override fun onPause() { + super.onPause() + GSYVideoManager.onPause() + } + + override fun onResume() { + super.onResume() + GSYVideoManager.onResume() + } + + override fun onDestroy() { + super.onDestroy() + GSYVideoManager.releaseAllVideos() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt new file mode 100644 index 0000000..c0aa2b3 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt @@ -0,0 +1,90 @@ +package com.casic.endoscope.view + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.databinding.ActivityBigImageBinding +import com.casic.endoscope.extensions.initImmersionBar +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant + +class BigImageActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityBigImageBinding { + return ActivityBigImageBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + binding.rootView.initImmersionBar(this, false, R.color.black) + binding.leftBackView.setOnClickListener { finish() } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + val index = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + binding.pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + binding.imagePagerView.adapter = BigImageAdapter(this, urls) + binding.imagePagerView.currentItem = index + binding.imagePagerView.offscreenPageLimit = imageSize + binding.imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + binding.pageNumberView.text = + String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt index 8c1a5dd..d05c4c5 100644 --- a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt @@ -14,6 +14,7 @@ import com.casic.endoscope.adapter.CameraPointAdapter import com.casic.endoscope.bean.CameraPointBean import com.casic.endoscope.databinding.ActivityMainBinding +import com.casic.endoscope.extensions.createImageFileDir import com.casic.endoscope.extensions.createVideoFileDir import com.casic.endoscope.extensions.getChannel import com.casic.endoscope.extensions.toTime @@ -28,7 +29,6 @@ import com.hikvision.netsdk.NET_DVR_PREVIEWINFO import com.hikvision.netsdk.PTZCommand import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir import com.pengxh.kt.lite.extensions.getStatusBarHeight import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show diff --git a/app/src/main/res/anim/activity_in.xml b/app/src/main/res/anim/activity_in.xml new file mode 100644 index 0000000..f2696ba --- /dev/null +++ b/app/src/main/res/anim/activity_in.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/activity_out.xml b/app/src/main/res/anim/activity_out.xml new file mode 100644 index 0000000..1e424a5 --- /dev/null +++ b/app/src/main/res/anim/activity_out.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3336534..b4fb060 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,5 +33,10 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt new file mode 100644 index 0000000..28e22c9 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -0,0 +1,75 @@ +package com.casic.endoscope.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Environment +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.casic.endoscope.view.BigImageActivity +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.navigatePageTo +import java.io.File + +abstract class MediaDirAdapter( + private val context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val kTag = "MediaDirAdapter" + private var fileBeans = ArrayList() + private lateinit var fileAdapter: MediaFileAdapter + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(context).inflate(R.layout.item_dir_list_rv, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) { + val date = dataRows[position].name + holder.setText(R.id.dateView, date) + + //根据不同的日期显示不同的改日期下的九宫格形式子文件 + val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) + videoDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) + imageDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val realPaths = ArrayList() + fileBeans.forEach { + val absolutePath = it.absolutePath + if (!absolutePath.endsWith(".mp4")) { + realPaths.add(absolutePath) + } + } + + fileAdapter = object : MediaFileAdapter(context, fileBeans) { + override fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) { + bindChildVideoRes(child, childPos, item) + } + + override fun bindImageRes(child: ViewHolder, item: File) { + child.setImageResource(R.id.imageView, item.absolutePath) + } + } + val recyclerView = holder.getView(R.id.recyclerView) + recyclerView.adapter = fileAdapter + fileAdapter.setOnItemClickedListener(object : MediaFileAdapter.OnItemClickedListener { + override fun onItemClicked(item: File) { + if (!item.name.endsWith(".mp4")) { + context.navigatePageTo(position, realPaths) + } + } + }) + } + + abstract fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt new file mode 100644 index 0000000..e447913 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt @@ -0,0 +1,62 @@ +package com.casic.endoscope.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.pengxh.kt.lite.adapter.ViewHolder +import java.io.File + +abstract class MediaFileAdapter( + context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val inflater: LayoutInflater = LayoutInflater.from(context) + private val TYPE_VIDEO = 0 + private val TYPE_IMAGE = 1 + + override fun getItemCount(): Int = dataRows.size + + override fun getItemViewType(position: Int): Int { + return if (dataRows[position].name.endsWith(".mp4")) { + TYPE_VIDEO + } else { + TYPE_IMAGE + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return if (viewType == TYPE_VIDEO) { + ViewHolder(inflater.inflate(R.layout.item_video_list_gv, parent, false)) + } else { + ViewHolder(inflater.inflate(R.layout.item_image_list_gv, parent, false)) + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val file = dataRows[position] + if (holder.itemViewType == TYPE_VIDEO) { + bindVideoRes(holder, position, dataRows[position]) + } else { + bindImageRes(holder, dataRows[position]) + } + + holder.itemView.setOnClickListener { + itemClickedListener?.onItemClicked(file) + } + } + + abstract fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) + abstract fun bindImageRes(child: ViewHolder, item: File) + + private var itemClickedListener: OnItemClickedListener? = null + + interface OnItemClickedListener { + fun onItemClicked(item: File) + } + + fun setOnItemClickedListener(listener: OnItemClickedListener) { + itemClickedListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/extensions/Context.kt b/app/src/main/java/com/casic/endoscope/extensions/Context.kt index 0afcb27..a301aab 100644 --- a/app/src/main/java/com/casic/endoscope/extensions/Context.kt +++ b/app/src/main/java/com/casic/endoscope/extensions/Context.kt @@ -2,13 +2,22 @@ import android.content.Context import android.os.Environment +import com.pengxh.kt.lite.extensions.timestampToDate import java.io.File //扩展函数 fun Context.createVideoFileDir(): File { - val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), System.currentTimeMillis().timestampToDate()) if (!videoDir.exists()) { videoDir.mkdir() } return videoDir +} + +fun Context.createImageFileDir(): File { + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis().timestampToDate()) + if (!imageDir.exists()) { + imageDir.mkdir() + } + return imageDir } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt index c0020ec..8c4b495 100644 --- a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt @@ -1,32 +1,127 @@ package com.casic.endoscope.view +import android.annotation.SuppressLint +import android.content.pm.ActivityInfo import android.os.Bundle -import android.util.Log +import android.os.Environment +import android.view.View +import android.widget.ImageView +import androidx.activity.OnBackPressedCallback +import androidx.lifecycle.lifecycleScope +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.adapter.MediaDirAdapter import com.casic.endoscope.databinding.ActivityAlbumBinding -import com.casic.endoscope.extensions.createVideoFileDir import com.gyf.immersionbar.ImmersionBar +import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getStatusBarHeight +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File class AlbumActivity : KotlinBaseActivity() { private val kTag = "AlbumActivity" + private val context = this@AlbumActivity + //子文件夹集合 + private var dirBeans = ArrayList() + private lateinit var directoryAdapter: MediaDirAdapter + + @SuppressLint("NotifyDataSetChanged") override fun initEvent() { + binding.ascButton.setOnClickListener { + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + binding.decButton.setOnClickListener { + //升序 + dirBeans.sortBy { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + + //替换onBackPressed + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + GSYVideoManager.backFromWindowFull(context) + //解决退出全屏后会被强制竖屏的问题 + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { - val videoDir = createVideoFileDir() - videoDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val temp = ArrayList() + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + videoDir.list()?.forEach { + temp.add(it) } - val imageDir = createImageFileDir() - imageDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + imageDir.list()?.forEach { + temp.add(it) } + + //去重 + val directoryNameSet = HashSet(temp) + + //全部转为File类型,方便是用自带的排序函数 + directoryNameSet.forEach { + dirBeans.add(File(it)) + } + + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + + //绑定数据 + directoryAdapter = object : MediaDirAdapter(this, dirBeans) { + override fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) { + val videoPlayer = child.getView(R.id.videoPlayer) + videoPlayer.titleTextView.visibility = View.GONE + videoPlayer.backButton.visibility = View.GONE + lifecycleScope.launch(Dispatchers.Main) { + try { + val drawable = withContext(Dispatchers.IO) { + Glide.with(context) + .load(item) + .submit() + .get() + } + val coverImg = ImageView(context) + coverImg.setImageDrawable(drawable) + videoPlayer.thumbImageView = coverImg + } catch (e: Exception) { + e.printStackTrace() + } + } + videoPlayer.setUp(item.absolutePath, true, "") + videoPlayer.fullscreenButton.setOnClickListener { + videoPlayer.startWindowFullscreen(context, false, true) + } + //防止错位设置 + videoPlayer.playTag = System.currentTimeMillis().toString() + videoPlayer.playPosition = childPos + //是否根据视频尺寸,自动选择竖屏全屏或者横屏全屏 + videoPlayer.isAutoFullWithSize = true + //音频焦点冲突时是否释放 + videoPlayer.isReleaseWhenLossAudio = false + //全屏动画 + videoPlayer.isShowFullAnimation = true + } + } + val offset = 10.dp2px(this) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(offset, offset, offset, offset) + ) + binding.recyclerView.adapter = directoryAdapter } override fun initViewBinding(): ActivityAlbumBinding { @@ -44,4 +139,19 @@ binding.rootView.setPadding(0, statusBarHeight, 0, 0) binding.rootView.requestLayout() } + + override fun onPause() { + super.onPause() + GSYVideoManager.onPause() + } + + override fun onResume() { + super.onResume() + GSYVideoManager.onResume() + } + + override fun onDestroy() { + super.onDestroy() + GSYVideoManager.releaseAllVideos() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt new file mode 100644 index 0000000..c0aa2b3 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt @@ -0,0 +1,90 @@ +package com.casic.endoscope.view + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.databinding.ActivityBigImageBinding +import com.casic.endoscope.extensions.initImmersionBar +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant + +class BigImageActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityBigImageBinding { + return ActivityBigImageBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + binding.rootView.initImmersionBar(this, false, R.color.black) + binding.leftBackView.setOnClickListener { finish() } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + val index = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + binding.pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + binding.imagePagerView.adapter = BigImageAdapter(this, urls) + binding.imagePagerView.currentItem = index + binding.imagePagerView.offscreenPageLimit = imageSize + binding.imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + binding.pageNumberView.text = + String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt index 8c1a5dd..d05c4c5 100644 --- a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt @@ -14,6 +14,7 @@ import com.casic.endoscope.adapter.CameraPointAdapter import com.casic.endoscope.bean.CameraPointBean import com.casic.endoscope.databinding.ActivityMainBinding +import com.casic.endoscope.extensions.createImageFileDir import com.casic.endoscope.extensions.createVideoFileDir import com.casic.endoscope.extensions.getChannel import com.casic.endoscope.extensions.toTime @@ -28,7 +29,6 @@ import com.hikvision.netsdk.NET_DVR_PREVIEWINFO import com.hikvision.netsdk.PTZCommand import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir import com.pengxh.kt.lite.extensions.getStatusBarHeight import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show diff --git a/app/src/main/res/anim/activity_in.xml b/app/src/main/res/anim/activity_in.xml new file mode 100644 index 0000000..f2696ba --- /dev/null +++ b/app/src/main/res/anim/activity_in.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/activity_out.xml b/app/src/main/res/anim/activity_out.xml new file mode 100644 index 0000000..1e424a5 --- /dev/null +++ b/app/src/main/res/anim/activity_out.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_album.xml b/app/src/main/res/layout/activity_album.xml index 38360ea..cf06f5a 100644 --- a/app/src/main/res/layout/activity_album.xml +++ b/app/src/main/res/layout/activity_album.xml @@ -51,7 +51,7 @@ android:orientation="horizontal"> + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt new file mode 100644 index 0000000..28e22c9 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -0,0 +1,75 @@ +package com.casic.endoscope.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Environment +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.casic.endoscope.view.BigImageActivity +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.navigatePageTo +import java.io.File + +abstract class MediaDirAdapter( + private val context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val kTag = "MediaDirAdapter" + private var fileBeans = ArrayList() + private lateinit var fileAdapter: MediaFileAdapter + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(context).inflate(R.layout.item_dir_list_rv, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) { + val date = dataRows[position].name + holder.setText(R.id.dateView, date) + + //根据不同的日期显示不同的改日期下的九宫格形式子文件 + val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) + videoDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) + imageDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val realPaths = ArrayList() + fileBeans.forEach { + val absolutePath = it.absolutePath + if (!absolutePath.endsWith(".mp4")) { + realPaths.add(absolutePath) + } + } + + fileAdapter = object : MediaFileAdapter(context, fileBeans) { + override fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) { + bindChildVideoRes(child, childPos, item) + } + + override fun bindImageRes(child: ViewHolder, item: File) { + child.setImageResource(R.id.imageView, item.absolutePath) + } + } + val recyclerView = holder.getView(R.id.recyclerView) + recyclerView.adapter = fileAdapter + fileAdapter.setOnItemClickedListener(object : MediaFileAdapter.OnItemClickedListener { + override fun onItemClicked(item: File) { + if (!item.name.endsWith(".mp4")) { + context.navigatePageTo(position, realPaths) + } + } + }) + } + + abstract fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt new file mode 100644 index 0000000..e447913 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt @@ -0,0 +1,62 @@ +package com.casic.endoscope.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.pengxh.kt.lite.adapter.ViewHolder +import java.io.File + +abstract class MediaFileAdapter( + context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val inflater: LayoutInflater = LayoutInflater.from(context) + private val TYPE_VIDEO = 0 + private val TYPE_IMAGE = 1 + + override fun getItemCount(): Int = dataRows.size + + override fun getItemViewType(position: Int): Int { + return if (dataRows[position].name.endsWith(".mp4")) { + TYPE_VIDEO + } else { + TYPE_IMAGE + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return if (viewType == TYPE_VIDEO) { + ViewHolder(inflater.inflate(R.layout.item_video_list_gv, parent, false)) + } else { + ViewHolder(inflater.inflate(R.layout.item_image_list_gv, parent, false)) + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val file = dataRows[position] + if (holder.itemViewType == TYPE_VIDEO) { + bindVideoRes(holder, position, dataRows[position]) + } else { + bindImageRes(holder, dataRows[position]) + } + + holder.itemView.setOnClickListener { + itemClickedListener?.onItemClicked(file) + } + } + + abstract fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) + abstract fun bindImageRes(child: ViewHolder, item: File) + + private var itemClickedListener: OnItemClickedListener? = null + + interface OnItemClickedListener { + fun onItemClicked(item: File) + } + + fun setOnItemClickedListener(listener: OnItemClickedListener) { + itemClickedListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/extensions/Context.kt b/app/src/main/java/com/casic/endoscope/extensions/Context.kt index 0afcb27..a301aab 100644 --- a/app/src/main/java/com/casic/endoscope/extensions/Context.kt +++ b/app/src/main/java/com/casic/endoscope/extensions/Context.kt @@ -2,13 +2,22 @@ import android.content.Context import android.os.Environment +import com.pengxh.kt.lite.extensions.timestampToDate import java.io.File //扩展函数 fun Context.createVideoFileDir(): File { - val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), System.currentTimeMillis().timestampToDate()) if (!videoDir.exists()) { videoDir.mkdir() } return videoDir +} + +fun Context.createImageFileDir(): File { + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis().timestampToDate()) + if (!imageDir.exists()) { + imageDir.mkdir() + } + return imageDir } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt index c0020ec..8c4b495 100644 --- a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt @@ -1,32 +1,127 @@ package com.casic.endoscope.view +import android.annotation.SuppressLint +import android.content.pm.ActivityInfo import android.os.Bundle -import android.util.Log +import android.os.Environment +import android.view.View +import android.widget.ImageView +import androidx.activity.OnBackPressedCallback +import androidx.lifecycle.lifecycleScope +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.adapter.MediaDirAdapter import com.casic.endoscope.databinding.ActivityAlbumBinding -import com.casic.endoscope.extensions.createVideoFileDir import com.gyf.immersionbar.ImmersionBar +import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getStatusBarHeight +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File class AlbumActivity : KotlinBaseActivity() { private val kTag = "AlbumActivity" + private val context = this@AlbumActivity + //子文件夹集合 + private var dirBeans = ArrayList() + private lateinit var directoryAdapter: MediaDirAdapter + + @SuppressLint("NotifyDataSetChanged") override fun initEvent() { + binding.ascButton.setOnClickListener { + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + binding.decButton.setOnClickListener { + //升序 + dirBeans.sortBy { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + + //替换onBackPressed + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + GSYVideoManager.backFromWindowFull(context) + //解决退出全屏后会被强制竖屏的问题 + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { - val videoDir = createVideoFileDir() - videoDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val temp = ArrayList() + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + videoDir.list()?.forEach { + temp.add(it) } - val imageDir = createImageFileDir() - imageDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + imageDir.list()?.forEach { + temp.add(it) } + + //去重 + val directoryNameSet = HashSet(temp) + + //全部转为File类型,方便是用自带的排序函数 + directoryNameSet.forEach { + dirBeans.add(File(it)) + } + + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + + //绑定数据 + directoryAdapter = object : MediaDirAdapter(this, dirBeans) { + override fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) { + val videoPlayer = child.getView(R.id.videoPlayer) + videoPlayer.titleTextView.visibility = View.GONE + videoPlayer.backButton.visibility = View.GONE + lifecycleScope.launch(Dispatchers.Main) { + try { + val drawable = withContext(Dispatchers.IO) { + Glide.with(context) + .load(item) + .submit() + .get() + } + val coverImg = ImageView(context) + coverImg.setImageDrawable(drawable) + videoPlayer.thumbImageView = coverImg + } catch (e: Exception) { + e.printStackTrace() + } + } + videoPlayer.setUp(item.absolutePath, true, "") + videoPlayer.fullscreenButton.setOnClickListener { + videoPlayer.startWindowFullscreen(context, false, true) + } + //防止错位设置 + videoPlayer.playTag = System.currentTimeMillis().toString() + videoPlayer.playPosition = childPos + //是否根据视频尺寸,自动选择竖屏全屏或者横屏全屏 + videoPlayer.isAutoFullWithSize = true + //音频焦点冲突时是否释放 + videoPlayer.isReleaseWhenLossAudio = false + //全屏动画 + videoPlayer.isShowFullAnimation = true + } + } + val offset = 10.dp2px(this) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(offset, offset, offset, offset) + ) + binding.recyclerView.adapter = directoryAdapter } override fun initViewBinding(): ActivityAlbumBinding { @@ -44,4 +139,19 @@ binding.rootView.setPadding(0, statusBarHeight, 0, 0) binding.rootView.requestLayout() } + + override fun onPause() { + super.onPause() + GSYVideoManager.onPause() + } + + override fun onResume() { + super.onResume() + GSYVideoManager.onResume() + } + + override fun onDestroy() { + super.onDestroy() + GSYVideoManager.releaseAllVideos() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt new file mode 100644 index 0000000..c0aa2b3 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt @@ -0,0 +1,90 @@ +package com.casic.endoscope.view + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.databinding.ActivityBigImageBinding +import com.casic.endoscope.extensions.initImmersionBar +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant + +class BigImageActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityBigImageBinding { + return ActivityBigImageBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + binding.rootView.initImmersionBar(this, false, R.color.black) + binding.leftBackView.setOnClickListener { finish() } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + val index = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + binding.pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + binding.imagePagerView.adapter = BigImageAdapter(this, urls) + binding.imagePagerView.currentItem = index + binding.imagePagerView.offscreenPageLimit = imageSize + binding.imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + binding.pageNumberView.text = + String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt index 8c1a5dd..d05c4c5 100644 --- a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt @@ -14,6 +14,7 @@ import com.casic.endoscope.adapter.CameraPointAdapter import com.casic.endoscope.bean.CameraPointBean import com.casic.endoscope.databinding.ActivityMainBinding +import com.casic.endoscope.extensions.createImageFileDir import com.casic.endoscope.extensions.createVideoFileDir import com.casic.endoscope.extensions.getChannel import com.casic.endoscope.extensions.toTime @@ -28,7 +29,6 @@ import com.hikvision.netsdk.NET_DVR_PREVIEWINFO import com.hikvision.netsdk.PTZCommand import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir import com.pengxh.kt.lite.extensions.getStatusBarHeight import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show diff --git a/app/src/main/res/anim/activity_in.xml b/app/src/main/res/anim/activity_in.xml new file mode 100644 index 0000000..f2696ba --- /dev/null +++ b/app/src/main/res/anim/activity_in.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/activity_out.xml b/app/src/main/res/anim/activity_out.xml new file mode 100644 index 0000000..1e424a5 --- /dev/null +++ b/app/src/main/res/anim/activity_out.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_album.xml b/app/src/main/res/layout/activity_album.xml index 38360ea..cf06f5a 100644 --- a/app/src/main/res/layout/activity_album.xml +++ b/app/src/main/res/layout/activity_album.xml @@ -51,7 +51,7 @@ android:orientation="horizontal"> + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3336534..b4fb060 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,5 +33,10 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt new file mode 100644 index 0000000..28e22c9 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -0,0 +1,75 @@ +package com.casic.endoscope.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Environment +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.casic.endoscope.view.BigImageActivity +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.navigatePageTo +import java.io.File + +abstract class MediaDirAdapter( + private val context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val kTag = "MediaDirAdapter" + private var fileBeans = ArrayList() + private lateinit var fileAdapter: MediaFileAdapter + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(context).inflate(R.layout.item_dir_list_rv, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) { + val date = dataRows[position].name + holder.setText(R.id.dateView, date) + + //根据不同的日期显示不同的改日期下的九宫格形式子文件 + val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) + videoDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) + imageDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val realPaths = ArrayList() + fileBeans.forEach { + val absolutePath = it.absolutePath + if (!absolutePath.endsWith(".mp4")) { + realPaths.add(absolutePath) + } + } + + fileAdapter = object : MediaFileAdapter(context, fileBeans) { + override fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) { + bindChildVideoRes(child, childPos, item) + } + + override fun bindImageRes(child: ViewHolder, item: File) { + child.setImageResource(R.id.imageView, item.absolutePath) + } + } + val recyclerView = holder.getView(R.id.recyclerView) + recyclerView.adapter = fileAdapter + fileAdapter.setOnItemClickedListener(object : MediaFileAdapter.OnItemClickedListener { + override fun onItemClicked(item: File) { + if (!item.name.endsWith(".mp4")) { + context.navigatePageTo(position, realPaths) + } + } + }) + } + + abstract fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt new file mode 100644 index 0000000..e447913 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt @@ -0,0 +1,62 @@ +package com.casic.endoscope.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.pengxh.kt.lite.adapter.ViewHolder +import java.io.File + +abstract class MediaFileAdapter( + context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val inflater: LayoutInflater = LayoutInflater.from(context) + private val TYPE_VIDEO = 0 + private val TYPE_IMAGE = 1 + + override fun getItemCount(): Int = dataRows.size + + override fun getItemViewType(position: Int): Int { + return if (dataRows[position].name.endsWith(".mp4")) { + TYPE_VIDEO + } else { + TYPE_IMAGE + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return if (viewType == TYPE_VIDEO) { + ViewHolder(inflater.inflate(R.layout.item_video_list_gv, parent, false)) + } else { + ViewHolder(inflater.inflate(R.layout.item_image_list_gv, parent, false)) + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val file = dataRows[position] + if (holder.itemViewType == TYPE_VIDEO) { + bindVideoRes(holder, position, dataRows[position]) + } else { + bindImageRes(holder, dataRows[position]) + } + + holder.itemView.setOnClickListener { + itemClickedListener?.onItemClicked(file) + } + } + + abstract fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) + abstract fun bindImageRes(child: ViewHolder, item: File) + + private var itemClickedListener: OnItemClickedListener? = null + + interface OnItemClickedListener { + fun onItemClicked(item: File) + } + + fun setOnItemClickedListener(listener: OnItemClickedListener) { + itemClickedListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/extensions/Context.kt b/app/src/main/java/com/casic/endoscope/extensions/Context.kt index 0afcb27..a301aab 100644 --- a/app/src/main/java/com/casic/endoscope/extensions/Context.kt +++ b/app/src/main/java/com/casic/endoscope/extensions/Context.kt @@ -2,13 +2,22 @@ import android.content.Context import android.os.Environment +import com.pengxh.kt.lite.extensions.timestampToDate import java.io.File //扩展函数 fun Context.createVideoFileDir(): File { - val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), System.currentTimeMillis().timestampToDate()) if (!videoDir.exists()) { videoDir.mkdir() } return videoDir +} + +fun Context.createImageFileDir(): File { + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis().timestampToDate()) + if (!imageDir.exists()) { + imageDir.mkdir() + } + return imageDir } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt index c0020ec..8c4b495 100644 --- a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt @@ -1,32 +1,127 @@ package com.casic.endoscope.view +import android.annotation.SuppressLint +import android.content.pm.ActivityInfo import android.os.Bundle -import android.util.Log +import android.os.Environment +import android.view.View +import android.widget.ImageView +import androidx.activity.OnBackPressedCallback +import androidx.lifecycle.lifecycleScope +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.adapter.MediaDirAdapter import com.casic.endoscope.databinding.ActivityAlbumBinding -import com.casic.endoscope.extensions.createVideoFileDir import com.gyf.immersionbar.ImmersionBar +import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getStatusBarHeight +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File class AlbumActivity : KotlinBaseActivity() { private val kTag = "AlbumActivity" + private val context = this@AlbumActivity + //子文件夹集合 + private var dirBeans = ArrayList() + private lateinit var directoryAdapter: MediaDirAdapter + + @SuppressLint("NotifyDataSetChanged") override fun initEvent() { + binding.ascButton.setOnClickListener { + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + binding.decButton.setOnClickListener { + //升序 + dirBeans.sortBy { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + + //替换onBackPressed + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + GSYVideoManager.backFromWindowFull(context) + //解决退出全屏后会被强制竖屏的问题 + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { - val videoDir = createVideoFileDir() - videoDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val temp = ArrayList() + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + videoDir.list()?.forEach { + temp.add(it) } - val imageDir = createImageFileDir() - imageDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + imageDir.list()?.forEach { + temp.add(it) } + + //去重 + val directoryNameSet = HashSet(temp) + + //全部转为File类型,方便是用自带的排序函数 + directoryNameSet.forEach { + dirBeans.add(File(it)) + } + + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + + //绑定数据 + directoryAdapter = object : MediaDirAdapter(this, dirBeans) { + override fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) { + val videoPlayer = child.getView(R.id.videoPlayer) + videoPlayer.titleTextView.visibility = View.GONE + videoPlayer.backButton.visibility = View.GONE + lifecycleScope.launch(Dispatchers.Main) { + try { + val drawable = withContext(Dispatchers.IO) { + Glide.with(context) + .load(item) + .submit() + .get() + } + val coverImg = ImageView(context) + coverImg.setImageDrawable(drawable) + videoPlayer.thumbImageView = coverImg + } catch (e: Exception) { + e.printStackTrace() + } + } + videoPlayer.setUp(item.absolutePath, true, "") + videoPlayer.fullscreenButton.setOnClickListener { + videoPlayer.startWindowFullscreen(context, false, true) + } + //防止错位设置 + videoPlayer.playTag = System.currentTimeMillis().toString() + videoPlayer.playPosition = childPos + //是否根据视频尺寸,自动选择竖屏全屏或者横屏全屏 + videoPlayer.isAutoFullWithSize = true + //音频焦点冲突时是否释放 + videoPlayer.isReleaseWhenLossAudio = false + //全屏动画 + videoPlayer.isShowFullAnimation = true + } + } + val offset = 10.dp2px(this) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(offset, offset, offset, offset) + ) + binding.recyclerView.adapter = directoryAdapter } override fun initViewBinding(): ActivityAlbumBinding { @@ -44,4 +139,19 @@ binding.rootView.setPadding(0, statusBarHeight, 0, 0) binding.rootView.requestLayout() } + + override fun onPause() { + super.onPause() + GSYVideoManager.onPause() + } + + override fun onResume() { + super.onResume() + GSYVideoManager.onResume() + } + + override fun onDestroy() { + super.onDestroy() + GSYVideoManager.releaseAllVideos() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt new file mode 100644 index 0000000..c0aa2b3 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt @@ -0,0 +1,90 @@ +package com.casic.endoscope.view + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.databinding.ActivityBigImageBinding +import com.casic.endoscope.extensions.initImmersionBar +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant + +class BigImageActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityBigImageBinding { + return ActivityBigImageBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + binding.rootView.initImmersionBar(this, false, R.color.black) + binding.leftBackView.setOnClickListener { finish() } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + val index = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + binding.pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + binding.imagePagerView.adapter = BigImageAdapter(this, urls) + binding.imagePagerView.currentItem = index + binding.imagePagerView.offscreenPageLimit = imageSize + binding.imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + binding.pageNumberView.text = + String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt index 8c1a5dd..d05c4c5 100644 --- a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt @@ -14,6 +14,7 @@ import com.casic.endoscope.adapter.CameraPointAdapter import com.casic.endoscope.bean.CameraPointBean import com.casic.endoscope.databinding.ActivityMainBinding +import com.casic.endoscope.extensions.createImageFileDir import com.casic.endoscope.extensions.createVideoFileDir import com.casic.endoscope.extensions.getChannel import com.casic.endoscope.extensions.toTime @@ -28,7 +29,6 @@ import com.hikvision.netsdk.NET_DVR_PREVIEWINFO import com.hikvision.netsdk.PTZCommand import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir import com.pengxh.kt.lite.extensions.getStatusBarHeight import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show diff --git a/app/src/main/res/anim/activity_in.xml b/app/src/main/res/anim/activity_in.xml new file mode 100644 index 0000000..f2696ba --- /dev/null +++ b/app/src/main/res/anim/activity_in.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/activity_out.xml b/app/src/main/res/anim/activity_out.xml new file mode 100644 index 0000000..1e424a5 --- /dev/null +++ b/app/src/main/res/anim/activity_out.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_album.xml b/app/src/main/res/layout/activity_album.xml index 38360ea..cf06f5a 100644 --- a/app/src/main/res/layout/activity_album.xml +++ b/app/src/main/res/layout/activity_album.xml @@ -51,7 +51,7 @@ android:orientation="horizontal"> + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_big_picture.xml b/app/src/main/res/layout/item_big_picture.xml new file mode 100644 index 0000000..d90eb44 --- /dev/null +++ b/app/src/main/res/layout/item_big_picture.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3336534..b4fb060 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,5 +33,10 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt new file mode 100644 index 0000000..28e22c9 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -0,0 +1,75 @@ +package com.casic.endoscope.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Environment +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.casic.endoscope.view.BigImageActivity +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.navigatePageTo +import java.io.File + +abstract class MediaDirAdapter( + private val context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val kTag = "MediaDirAdapter" + private var fileBeans = ArrayList() + private lateinit var fileAdapter: MediaFileAdapter + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(context).inflate(R.layout.item_dir_list_rv, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) { + val date = dataRows[position].name + holder.setText(R.id.dateView, date) + + //根据不同的日期显示不同的改日期下的九宫格形式子文件 + val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) + videoDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) + imageDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val realPaths = ArrayList() + fileBeans.forEach { + val absolutePath = it.absolutePath + if (!absolutePath.endsWith(".mp4")) { + realPaths.add(absolutePath) + } + } + + fileAdapter = object : MediaFileAdapter(context, fileBeans) { + override fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) { + bindChildVideoRes(child, childPos, item) + } + + override fun bindImageRes(child: ViewHolder, item: File) { + child.setImageResource(R.id.imageView, item.absolutePath) + } + } + val recyclerView = holder.getView(R.id.recyclerView) + recyclerView.adapter = fileAdapter + fileAdapter.setOnItemClickedListener(object : MediaFileAdapter.OnItemClickedListener { + override fun onItemClicked(item: File) { + if (!item.name.endsWith(".mp4")) { + context.navigatePageTo(position, realPaths) + } + } + }) + } + + abstract fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt new file mode 100644 index 0000000..e447913 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt @@ -0,0 +1,62 @@ +package com.casic.endoscope.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.pengxh.kt.lite.adapter.ViewHolder +import java.io.File + +abstract class MediaFileAdapter( + context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val inflater: LayoutInflater = LayoutInflater.from(context) + private val TYPE_VIDEO = 0 + private val TYPE_IMAGE = 1 + + override fun getItemCount(): Int = dataRows.size + + override fun getItemViewType(position: Int): Int { + return if (dataRows[position].name.endsWith(".mp4")) { + TYPE_VIDEO + } else { + TYPE_IMAGE + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return if (viewType == TYPE_VIDEO) { + ViewHolder(inflater.inflate(R.layout.item_video_list_gv, parent, false)) + } else { + ViewHolder(inflater.inflate(R.layout.item_image_list_gv, parent, false)) + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val file = dataRows[position] + if (holder.itemViewType == TYPE_VIDEO) { + bindVideoRes(holder, position, dataRows[position]) + } else { + bindImageRes(holder, dataRows[position]) + } + + holder.itemView.setOnClickListener { + itemClickedListener?.onItemClicked(file) + } + } + + abstract fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) + abstract fun bindImageRes(child: ViewHolder, item: File) + + private var itemClickedListener: OnItemClickedListener? = null + + interface OnItemClickedListener { + fun onItemClicked(item: File) + } + + fun setOnItemClickedListener(listener: OnItemClickedListener) { + itemClickedListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/extensions/Context.kt b/app/src/main/java/com/casic/endoscope/extensions/Context.kt index 0afcb27..a301aab 100644 --- a/app/src/main/java/com/casic/endoscope/extensions/Context.kt +++ b/app/src/main/java/com/casic/endoscope/extensions/Context.kt @@ -2,13 +2,22 @@ import android.content.Context import android.os.Environment +import com.pengxh.kt.lite.extensions.timestampToDate import java.io.File //扩展函数 fun Context.createVideoFileDir(): File { - val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), System.currentTimeMillis().timestampToDate()) if (!videoDir.exists()) { videoDir.mkdir() } return videoDir +} + +fun Context.createImageFileDir(): File { + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis().timestampToDate()) + if (!imageDir.exists()) { + imageDir.mkdir() + } + return imageDir } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt index c0020ec..8c4b495 100644 --- a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt @@ -1,32 +1,127 @@ package com.casic.endoscope.view +import android.annotation.SuppressLint +import android.content.pm.ActivityInfo import android.os.Bundle -import android.util.Log +import android.os.Environment +import android.view.View +import android.widget.ImageView +import androidx.activity.OnBackPressedCallback +import androidx.lifecycle.lifecycleScope +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.adapter.MediaDirAdapter import com.casic.endoscope.databinding.ActivityAlbumBinding -import com.casic.endoscope.extensions.createVideoFileDir import com.gyf.immersionbar.ImmersionBar +import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getStatusBarHeight +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File class AlbumActivity : KotlinBaseActivity() { private val kTag = "AlbumActivity" + private val context = this@AlbumActivity + //子文件夹集合 + private var dirBeans = ArrayList() + private lateinit var directoryAdapter: MediaDirAdapter + + @SuppressLint("NotifyDataSetChanged") override fun initEvent() { + binding.ascButton.setOnClickListener { + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + binding.decButton.setOnClickListener { + //升序 + dirBeans.sortBy { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + + //替换onBackPressed + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + GSYVideoManager.backFromWindowFull(context) + //解决退出全屏后会被强制竖屏的问题 + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { - val videoDir = createVideoFileDir() - videoDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val temp = ArrayList() + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + videoDir.list()?.forEach { + temp.add(it) } - val imageDir = createImageFileDir() - imageDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + imageDir.list()?.forEach { + temp.add(it) } + + //去重 + val directoryNameSet = HashSet(temp) + + //全部转为File类型,方便是用自带的排序函数 + directoryNameSet.forEach { + dirBeans.add(File(it)) + } + + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + + //绑定数据 + directoryAdapter = object : MediaDirAdapter(this, dirBeans) { + override fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) { + val videoPlayer = child.getView(R.id.videoPlayer) + videoPlayer.titleTextView.visibility = View.GONE + videoPlayer.backButton.visibility = View.GONE + lifecycleScope.launch(Dispatchers.Main) { + try { + val drawable = withContext(Dispatchers.IO) { + Glide.with(context) + .load(item) + .submit() + .get() + } + val coverImg = ImageView(context) + coverImg.setImageDrawable(drawable) + videoPlayer.thumbImageView = coverImg + } catch (e: Exception) { + e.printStackTrace() + } + } + videoPlayer.setUp(item.absolutePath, true, "") + videoPlayer.fullscreenButton.setOnClickListener { + videoPlayer.startWindowFullscreen(context, false, true) + } + //防止错位设置 + videoPlayer.playTag = System.currentTimeMillis().toString() + videoPlayer.playPosition = childPos + //是否根据视频尺寸,自动选择竖屏全屏或者横屏全屏 + videoPlayer.isAutoFullWithSize = true + //音频焦点冲突时是否释放 + videoPlayer.isReleaseWhenLossAudio = false + //全屏动画 + videoPlayer.isShowFullAnimation = true + } + } + val offset = 10.dp2px(this) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(offset, offset, offset, offset) + ) + binding.recyclerView.adapter = directoryAdapter } override fun initViewBinding(): ActivityAlbumBinding { @@ -44,4 +139,19 @@ binding.rootView.setPadding(0, statusBarHeight, 0, 0) binding.rootView.requestLayout() } + + override fun onPause() { + super.onPause() + GSYVideoManager.onPause() + } + + override fun onResume() { + super.onResume() + GSYVideoManager.onResume() + } + + override fun onDestroy() { + super.onDestroy() + GSYVideoManager.releaseAllVideos() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt new file mode 100644 index 0000000..c0aa2b3 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt @@ -0,0 +1,90 @@ +package com.casic.endoscope.view + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.databinding.ActivityBigImageBinding +import com.casic.endoscope.extensions.initImmersionBar +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant + +class BigImageActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityBigImageBinding { + return ActivityBigImageBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + binding.rootView.initImmersionBar(this, false, R.color.black) + binding.leftBackView.setOnClickListener { finish() } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + val index = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + binding.pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + binding.imagePagerView.adapter = BigImageAdapter(this, urls) + binding.imagePagerView.currentItem = index + binding.imagePagerView.offscreenPageLimit = imageSize + binding.imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + binding.pageNumberView.text = + String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt index 8c1a5dd..d05c4c5 100644 --- a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt @@ -14,6 +14,7 @@ import com.casic.endoscope.adapter.CameraPointAdapter import com.casic.endoscope.bean.CameraPointBean import com.casic.endoscope.databinding.ActivityMainBinding +import com.casic.endoscope.extensions.createImageFileDir import com.casic.endoscope.extensions.createVideoFileDir import com.casic.endoscope.extensions.getChannel import com.casic.endoscope.extensions.toTime @@ -28,7 +29,6 @@ import com.hikvision.netsdk.NET_DVR_PREVIEWINFO import com.hikvision.netsdk.PTZCommand import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir import com.pengxh.kt.lite.extensions.getStatusBarHeight import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show diff --git a/app/src/main/res/anim/activity_in.xml b/app/src/main/res/anim/activity_in.xml new file mode 100644 index 0000000..f2696ba --- /dev/null +++ b/app/src/main/res/anim/activity_in.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/activity_out.xml b/app/src/main/res/anim/activity_out.xml new file mode 100644 index 0000000..1e424a5 --- /dev/null +++ b/app/src/main/res/anim/activity_out.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_album.xml b/app/src/main/res/layout/activity_album.xml index 38360ea..cf06f5a 100644 --- a/app/src/main/res/layout/activity_album.xml +++ b/app/src/main/res/layout/activity_album.xml @@ -51,7 +51,7 @@ android:orientation="horizontal"> + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_big_picture.xml b/app/src/main/res/layout/item_big_picture.xml new file mode 100644 index 0000000..d90eb44 --- /dev/null +++ b/app/src/main/res/layout/item_big_picture.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_dir_list_rv.xml b/app/src/main/res/layout/item_dir_list_rv.xml new file mode 100644 index 0000000..f7b7597 --- /dev/null +++ b/app/src/main/res/layout/item_dir_list_rv.xml @@ -0,0 +1,31 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3336534..b4fb060 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,5 +33,10 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt new file mode 100644 index 0000000..28e22c9 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -0,0 +1,75 @@ +package com.casic.endoscope.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Environment +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.casic.endoscope.view.BigImageActivity +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.navigatePageTo +import java.io.File + +abstract class MediaDirAdapter( + private val context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val kTag = "MediaDirAdapter" + private var fileBeans = ArrayList() + private lateinit var fileAdapter: MediaFileAdapter + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(context).inflate(R.layout.item_dir_list_rv, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) { + val date = dataRows[position].name + holder.setText(R.id.dateView, date) + + //根据不同的日期显示不同的改日期下的九宫格形式子文件 + val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) + videoDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) + imageDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val realPaths = ArrayList() + fileBeans.forEach { + val absolutePath = it.absolutePath + if (!absolutePath.endsWith(".mp4")) { + realPaths.add(absolutePath) + } + } + + fileAdapter = object : MediaFileAdapter(context, fileBeans) { + override fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) { + bindChildVideoRes(child, childPos, item) + } + + override fun bindImageRes(child: ViewHolder, item: File) { + child.setImageResource(R.id.imageView, item.absolutePath) + } + } + val recyclerView = holder.getView(R.id.recyclerView) + recyclerView.adapter = fileAdapter + fileAdapter.setOnItemClickedListener(object : MediaFileAdapter.OnItemClickedListener { + override fun onItemClicked(item: File) { + if (!item.name.endsWith(".mp4")) { + context.navigatePageTo(position, realPaths) + } + } + }) + } + + abstract fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt new file mode 100644 index 0000000..e447913 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt @@ -0,0 +1,62 @@ +package com.casic.endoscope.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.pengxh.kt.lite.adapter.ViewHolder +import java.io.File + +abstract class MediaFileAdapter( + context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val inflater: LayoutInflater = LayoutInflater.from(context) + private val TYPE_VIDEO = 0 + private val TYPE_IMAGE = 1 + + override fun getItemCount(): Int = dataRows.size + + override fun getItemViewType(position: Int): Int { + return if (dataRows[position].name.endsWith(".mp4")) { + TYPE_VIDEO + } else { + TYPE_IMAGE + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return if (viewType == TYPE_VIDEO) { + ViewHolder(inflater.inflate(R.layout.item_video_list_gv, parent, false)) + } else { + ViewHolder(inflater.inflate(R.layout.item_image_list_gv, parent, false)) + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val file = dataRows[position] + if (holder.itemViewType == TYPE_VIDEO) { + bindVideoRes(holder, position, dataRows[position]) + } else { + bindImageRes(holder, dataRows[position]) + } + + holder.itemView.setOnClickListener { + itemClickedListener?.onItemClicked(file) + } + } + + abstract fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) + abstract fun bindImageRes(child: ViewHolder, item: File) + + private var itemClickedListener: OnItemClickedListener? = null + + interface OnItemClickedListener { + fun onItemClicked(item: File) + } + + fun setOnItemClickedListener(listener: OnItemClickedListener) { + itemClickedListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/extensions/Context.kt b/app/src/main/java/com/casic/endoscope/extensions/Context.kt index 0afcb27..a301aab 100644 --- a/app/src/main/java/com/casic/endoscope/extensions/Context.kt +++ b/app/src/main/java/com/casic/endoscope/extensions/Context.kt @@ -2,13 +2,22 @@ import android.content.Context import android.os.Environment +import com.pengxh.kt.lite.extensions.timestampToDate import java.io.File //扩展函数 fun Context.createVideoFileDir(): File { - val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), System.currentTimeMillis().timestampToDate()) if (!videoDir.exists()) { videoDir.mkdir() } return videoDir +} + +fun Context.createImageFileDir(): File { + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis().timestampToDate()) + if (!imageDir.exists()) { + imageDir.mkdir() + } + return imageDir } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt index c0020ec..8c4b495 100644 --- a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt @@ -1,32 +1,127 @@ package com.casic.endoscope.view +import android.annotation.SuppressLint +import android.content.pm.ActivityInfo import android.os.Bundle -import android.util.Log +import android.os.Environment +import android.view.View +import android.widget.ImageView +import androidx.activity.OnBackPressedCallback +import androidx.lifecycle.lifecycleScope +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.adapter.MediaDirAdapter import com.casic.endoscope.databinding.ActivityAlbumBinding -import com.casic.endoscope.extensions.createVideoFileDir import com.gyf.immersionbar.ImmersionBar +import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getStatusBarHeight +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File class AlbumActivity : KotlinBaseActivity() { private val kTag = "AlbumActivity" + private val context = this@AlbumActivity + //子文件夹集合 + private var dirBeans = ArrayList() + private lateinit var directoryAdapter: MediaDirAdapter + + @SuppressLint("NotifyDataSetChanged") override fun initEvent() { + binding.ascButton.setOnClickListener { + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + binding.decButton.setOnClickListener { + //升序 + dirBeans.sortBy { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + + //替换onBackPressed + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + GSYVideoManager.backFromWindowFull(context) + //解决退出全屏后会被强制竖屏的问题 + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { - val videoDir = createVideoFileDir() - videoDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val temp = ArrayList() + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + videoDir.list()?.forEach { + temp.add(it) } - val imageDir = createImageFileDir() - imageDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + imageDir.list()?.forEach { + temp.add(it) } + + //去重 + val directoryNameSet = HashSet(temp) + + //全部转为File类型,方便是用自带的排序函数 + directoryNameSet.forEach { + dirBeans.add(File(it)) + } + + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + + //绑定数据 + directoryAdapter = object : MediaDirAdapter(this, dirBeans) { + override fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) { + val videoPlayer = child.getView(R.id.videoPlayer) + videoPlayer.titleTextView.visibility = View.GONE + videoPlayer.backButton.visibility = View.GONE + lifecycleScope.launch(Dispatchers.Main) { + try { + val drawable = withContext(Dispatchers.IO) { + Glide.with(context) + .load(item) + .submit() + .get() + } + val coverImg = ImageView(context) + coverImg.setImageDrawable(drawable) + videoPlayer.thumbImageView = coverImg + } catch (e: Exception) { + e.printStackTrace() + } + } + videoPlayer.setUp(item.absolutePath, true, "") + videoPlayer.fullscreenButton.setOnClickListener { + videoPlayer.startWindowFullscreen(context, false, true) + } + //防止错位设置 + videoPlayer.playTag = System.currentTimeMillis().toString() + videoPlayer.playPosition = childPos + //是否根据视频尺寸,自动选择竖屏全屏或者横屏全屏 + videoPlayer.isAutoFullWithSize = true + //音频焦点冲突时是否释放 + videoPlayer.isReleaseWhenLossAudio = false + //全屏动画 + videoPlayer.isShowFullAnimation = true + } + } + val offset = 10.dp2px(this) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(offset, offset, offset, offset) + ) + binding.recyclerView.adapter = directoryAdapter } override fun initViewBinding(): ActivityAlbumBinding { @@ -44,4 +139,19 @@ binding.rootView.setPadding(0, statusBarHeight, 0, 0) binding.rootView.requestLayout() } + + override fun onPause() { + super.onPause() + GSYVideoManager.onPause() + } + + override fun onResume() { + super.onResume() + GSYVideoManager.onResume() + } + + override fun onDestroy() { + super.onDestroy() + GSYVideoManager.releaseAllVideos() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt new file mode 100644 index 0000000..c0aa2b3 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt @@ -0,0 +1,90 @@ +package com.casic.endoscope.view + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.databinding.ActivityBigImageBinding +import com.casic.endoscope.extensions.initImmersionBar +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant + +class BigImageActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityBigImageBinding { + return ActivityBigImageBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + binding.rootView.initImmersionBar(this, false, R.color.black) + binding.leftBackView.setOnClickListener { finish() } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + val index = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + binding.pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + binding.imagePagerView.adapter = BigImageAdapter(this, urls) + binding.imagePagerView.currentItem = index + binding.imagePagerView.offscreenPageLimit = imageSize + binding.imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + binding.pageNumberView.text = + String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt index 8c1a5dd..d05c4c5 100644 --- a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt @@ -14,6 +14,7 @@ import com.casic.endoscope.adapter.CameraPointAdapter import com.casic.endoscope.bean.CameraPointBean import com.casic.endoscope.databinding.ActivityMainBinding +import com.casic.endoscope.extensions.createImageFileDir import com.casic.endoscope.extensions.createVideoFileDir import com.casic.endoscope.extensions.getChannel import com.casic.endoscope.extensions.toTime @@ -28,7 +29,6 @@ import com.hikvision.netsdk.NET_DVR_PREVIEWINFO import com.hikvision.netsdk.PTZCommand import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir import com.pengxh.kt.lite.extensions.getStatusBarHeight import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show diff --git a/app/src/main/res/anim/activity_in.xml b/app/src/main/res/anim/activity_in.xml new file mode 100644 index 0000000..f2696ba --- /dev/null +++ b/app/src/main/res/anim/activity_in.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/activity_out.xml b/app/src/main/res/anim/activity_out.xml new file mode 100644 index 0000000..1e424a5 --- /dev/null +++ b/app/src/main/res/anim/activity_out.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_album.xml b/app/src/main/res/layout/activity_album.xml index 38360ea..cf06f5a 100644 --- a/app/src/main/res/layout/activity_album.xml +++ b/app/src/main/res/layout/activity_album.xml @@ -51,7 +51,7 @@ android:orientation="horizontal"> + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_big_picture.xml b/app/src/main/res/layout/item_big_picture.xml new file mode 100644 index 0000000..d90eb44 --- /dev/null +++ b/app/src/main/res/layout/item_big_picture.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_dir_list_rv.xml b/app/src/main/res/layout/item_dir_list_rv.xml new file mode 100644 index 0000000..f7b7597 --- /dev/null +++ b/app/src/main/res/layout/item_dir_list_rv.xml @@ -0,0 +1,31 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_image_list_gv.xml b/app/src/main/res/layout/item_image_list_gv.xml new file mode 100644 index 0000000..32fb2bd --- /dev/null +++ b/app/src/main/res/layout/item_image_list_gv.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3336534..b4fb060 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,5 +33,10 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt new file mode 100644 index 0000000..28e22c9 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -0,0 +1,75 @@ +package com.casic.endoscope.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Environment +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.casic.endoscope.view.BigImageActivity +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.navigatePageTo +import java.io.File + +abstract class MediaDirAdapter( + private val context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val kTag = "MediaDirAdapter" + private var fileBeans = ArrayList() + private lateinit var fileAdapter: MediaFileAdapter + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(context).inflate(R.layout.item_dir_list_rv, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) { + val date = dataRows[position].name + holder.setText(R.id.dateView, date) + + //根据不同的日期显示不同的改日期下的九宫格形式子文件 + val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) + videoDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) + imageDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val realPaths = ArrayList() + fileBeans.forEach { + val absolutePath = it.absolutePath + if (!absolutePath.endsWith(".mp4")) { + realPaths.add(absolutePath) + } + } + + fileAdapter = object : MediaFileAdapter(context, fileBeans) { + override fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) { + bindChildVideoRes(child, childPos, item) + } + + override fun bindImageRes(child: ViewHolder, item: File) { + child.setImageResource(R.id.imageView, item.absolutePath) + } + } + val recyclerView = holder.getView(R.id.recyclerView) + recyclerView.adapter = fileAdapter + fileAdapter.setOnItemClickedListener(object : MediaFileAdapter.OnItemClickedListener { + override fun onItemClicked(item: File) { + if (!item.name.endsWith(".mp4")) { + context.navigatePageTo(position, realPaths) + } + } + }) + } + + abstract fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt new file mode 100644 index 0000000..e447913 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt @@ -0,0 +1,62 @@ +package com.casic.endoscope.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.pengxh.kt.lite.adapter.ViewHolder +import java.io.File + +abstract class MediaFileAdapter( + context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val inflater: LayoutInflater = LayoutInflater.from(context) + private val TYPE_VIDEO = 0 + private val TYPE_IMAGE = 1 + + override fun getItemCount(): Int = dataRows.size + + override fun getItemViewType(position: Int): Int { + return if (dataRows[position].name.endsWith(".mp4")) { + TYPE_VIDEO + } else { + TYPE_IMAGE + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return if (viewType == TYPE_VIDEO) { + ViewHolder(inflater.inflate(R.layout.item_video_list_gv, parent, false)) + } else { + ViewHolder(inflater.inflate(R.layout.item_image_list_gv, parent, false)) + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val file = dataRows[position] + if (holder.itemViewType == TYPE_VIDEO) { + bindVideoRes(holder, position, dataRows[position]) + } else { + bindImageRes(holder, dataRows[position]) + } + + holder.itemView.setOnClickListener { + itemClickedListener?.onItemClicked(file) + } + } + + abstract fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) + abstract fun bindImageRes(child: ViewHolder, item: File) + + private var itemClickedListener: OnItemClickedListener? = null + + interface OnItemClickedListener { + fun onItemClicked(item: File) + } + + fun setOnItemClickedListener(listener: OnItemClickedListener) { + itemClickedListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/extensions/Context.kt b/app/src/main/java/com/casic/endoscope/extensions/Context.kt index 0afcb27..a301aab 100644 --- a/app/src/main/java/com/casic/endoscope/extensions/Context.kt +++ b/app/src/main/java/com/casic/endoscope/extensions/Context.kt @@ -2,13 +2,22 @@ import android.content.Context import android.os.Environment +import com.pengxh.kt.lite.extensions.timestampToDate import java.io.File //扩展函数 fun Context.createVideoFileDir(): File { - val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), System.currentTimeMillis().timestampToDate()) if (!videoDir.exists()) { videoDir.mkdir() } return videoDir +} + +fun Context.createImageFileDir(): File { + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis().timestampToDate()) + if (!imageDir.exists()) { + imageDir.mkdir() + } + return imageDir } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt index c0020ec..8c4b495 100644 --- a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt @@ -1,32 +1,127 @@ package com.casic.endoscope.view +import android.annotation.SuppressLint +import android.content.pm.ActivityInfo import android.os.Bundle -import android.util.Log +import android.os.Environment +import android.view.View +import android.widget.ImageView +import androidx.activity.OnBackPressedCallback +import androidx.lifecycle.lifecycleScope +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.adapter.MediaDirAdapter import com.casic.endoscope.databinding.ActivityAlbumBinding -import com.casic.endoscope.extensions.createVideoFileDir import com.gyf.immersionbar.ImmersionBar +import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getStatusBarHeight +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File class AlbumActivity : KotlinBaseActivity() { private val kTag = "AlbumActivity" + private val context = this@AlbumActivity + //子文件夹集合 + private var dirBeans = ArrayList() + private lateinit var directoryAdapter: MediaDirAdapter + + @SuppressLint("NotifyDataSetChanged") override fun initEvent() { + binding.ascButton.setOnClickListener { + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + binding.decButton.setOnClickListener { + //升序 + dirBeans.sortBy { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + + //替换onBackPressed + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + GSYVideoManager.backFromWindowFull(context) + //解决退出全屏后会被强制竖屏的问题 + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { - val videoDir = createVideoFileDir() - videoDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val temp = ArrayList() + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + videoDir.list()?.forEach { + temp.add(it) } - val imageDir = createImageFileDir() - imageDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + imageDir.list()?.forEach { + temp.add(it) } + + //去重 + val directoryNameSet = HashSet(temp) + + //全部转为File类型,方便是用自带的排序函数 + directoryNameSet.forEach { + dirBeans.add(File(it)) + } + + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + + //绑定数据 + directoryAdapter = object : MediaDirAdapter(this, dirBeans) { + override fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) { + val videoPlayer = child.getView(R.id.videoPlayer) + videoPlayer.titleTextView.visibility = View.GONE + videoPlayer.backButton.visibility = View.GONE + lifecycleScope.launch(Dispatchers.Main) { + try { + val drawable = withContext(Dispatchers.IO) { + Glide.with(context) + .load(item) + .submit() + .get() + } + val coverImg = ImageView(context) + coverImg.setImageDrawable(drawable) + videoPlayer.thumbImageView = coverImg + } catch (e: Exception) { + e.printStackTrace() + } + } + videoPlayer.setUp(item.absolutePath, true, "") + videoPlayer.fullscreenButton.setOnClickListener { + videoPlayer.startWindowFullscreen(context, false, true) + } + //防止错位设置 + videoPlayer.playTag = System.currentTimeMillis().toString() + videoPlayer.playPosition = childPos + //是否根据视频尺寸,自动选择竖屏全屏或者横屏全屏 + videoPlayer.isAutoFullWithSize = true + //音频焦点冲突时是否释放 + videoPlayer.isReleaseWhenLossAudio = false + //全屏动画 + videoPlayer.isShowFullAnimation = true + } + } + val offset = 10.dp2px(this) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(offset, offset, offset, offset) + ) + binding.recyclerView.adapter = directoryAdapter } override fun initViewBinding(): ActivityAlbumBinding { @@ -44,4 +139,19 @@ binding.rootView.setPadding(0, statusBarHeight, 0, 0) binding.rootView.requestLayout() } + + override fun onPause() { + super.onPause() + GSYVideoManager.onPause() + } + + override fun onResume() { + super.onResume() + GSYVideoManager.onResume() + } + + override fun onDestroy() { + super.onDestroy() + GSYVideoManager.releaseAllVideos() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt new file mode 100644 index 0000000..c0aa2b3 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt @@ -0,0 +1,90 @@ +package com.casic.endoscope.view + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.databinding.ActivityBigImageBinding +import com.casic.endoscope.extensions.initImmersionBar +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant + +class BigImageActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityBigImageBinding { + return ActivityBigImageBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + binding.rootView.initImmersionBar(this, false, R.color.black) + binding.leftBackView.setOnClickListener { finish() } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + val index = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + binding.pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + binding.imagePagerView.adapter = BigImageAdapter(this, urls) + binding.imagePagerView.currentItem = index + binding.imagePagerView.offscreenPageLimit = imageSize + binding.imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + binding.pageNumberView.text = + String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt index 8c1a5dd..d05c4c5 100644 --- a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt @@ -14,6 +14,7 @@ import com.casic.endoscope.adapter.CameraPointAdapter import com.casic.endoscope.bean.CameraPointBean import com.casic.endoscope.databinding.ActivityMainBinding +import com.casic.endoscope.extensions.createImageFileDir import com.casic.endoscope.extensions.createVideoFileDir import com.casic.endoscope.extensions.getChannel import com.casic.endoscope.extensions.toTime @@ -28,7 +29,6 @@ import com.hikvision.netsdk.NET_DVR_PREVIEWINFO import com.hikvision.netsdk.PTZCommand import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir import com.pengxh.kt.lite.extensions.getStatusBarHeight import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show diff --git a/app/src/main/res/anim/activity_in.xml b/app/src/main/res/anim/activity_in.xml new file mode 100644 index 0000000..f2696ba --- /dev/null +++ b/app/src/main/res/anim/activity_in.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/activity_out.xml b/app/src/main/res/anim/activity_out.xml new file mode 100644 index 0000000..1e424a5 --- /dev/null +++ b/app/src/main/res/anim/activity_out.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_album.xml b/app/src/main/res/layout/activity_album.xml index 38360ea..cf06f5a 100644 --- a/app/src/main/res/layout/activity_album.xml +++ b/app/src/main/res/layout/activity_album.xml @@ -51,7 +51,7 @@ android:orientation="horizontal"> + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_big_picture.xml b/app/src/main/res/layout/item_big_picture.xml new file mode 100644 index 0000000..d90eb44 --- /dev/null +++ b/app/src/main/res/layout/item_big_picture.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_dir_list_rv.xml b/app/src/main/res/layout/item_dir_list_rv.xml new file mode 100644 index 0000000..f7b7597 --- /dev/null +++ b/app/src/main/res/layout/item_dir_list_rv.xml @@ -0,0 +1,31 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_image_list_gv.xml b/app/src/main/res/layout/item_image_list_gv.xml new file mode 100644 index 0000000..32fb2bd --- /dev/null +++ b/app/src/main/res/layout/item_image_list_gv.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_video_list_gv.xml b/app/src/main/res/layout/item_video_list_gv.xml new file mode 100644 index 0000000..e879ef5 --- /dev/null +++ b/app/src/main/res/layout/item_video_list_gv.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3336534..b4fb060 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,5 +33,10 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt new file mode 100644 index 0000000..28e22c9 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -0,0 +1,75 @@ +package com.casic.endoscope.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Environment +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.casic.endoscope.view.BigImageActivity +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.navigatePageTo +import java.io.File + +abstract class MediaDirAdapter( + private val context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val kTag = "MediaDirAdapter" + private var fileBeans = ArrayList() + private lateinit var fileAdapter: MediaFileAdapter + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(context).inflate(R.layout.item_dir_list_rv, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) { + val date = dataRows[position].name + holder.setText(R.id.dateView, date) + + //根据不同的日期显示不同的改日期下的九宫格形式子文件 + val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) + videoDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) + imageDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val realPaths = ArrayList() + fileBeans.forEach { + val absolutePath = it.absolutePath + if (!absolutePath.endsWith(".mp4")) { + realPaths.add(absolutePath) + } + } + + fileAdapter = object : MediaFileAdapter(context, fileBeans) { + override fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) { + bindChildVideoRes(child, childPos, item) + } + + override fun bindImageRes(child: ViewHolder, item: File) { + child.setImageResource(R.id.imageView, item.absolutePath) + } + } + val recyclerView = holder.getView(R.id.recyclerView) + recyclerView.adapter = fileAdapter + fileAdapter.setOnItemClickedListener(object : MediaFileAdapter.OnItemClickedListener { + override fun onItemClicked(item: File) { + if (!item.name.endsWith(".mp4")) { + context.navigatePageTo(position, realPaths) + } + } + }) + } + + abstract fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt new file mode 100644 index 0000000..e447913 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt @@ -0,0 +1,62 @@ +package com.casic.endoscope.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.pengxh.kt.lite.adapter.ViewHolder +import java.io.File + +abstract class MediaFileAdapter( + context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val inflater: LayoutInflater = LayoutInflater.from(context) + private val TYPE_VIDEO = 0 + private val TYPE_IMAGE = 1 + + override fun getItemCount(): Int = dataRows.size + + override fun getItemViewType(position: Int): Int { + return if (dataRows[position].name.endsWith(".mp4")) { + TYPE_VIDEO + } else { + TYPE_IMAGE + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return if (viewType == TYPE_VIDEO) { + ViewHolder(inflater.inflate(R.layout.item_video_list_gv, parent, false)) + } else { + ViewHolder(inflater.inflate(R.layout.item_image_list_gv, parent, false)) + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val file = dataRows[position] + if (holder.itemViewType == TYPE_VIDEO) { + bindVideoRes(holder, position, dataRows[position]) + } else { + bindImageRes(holder, dataRows[position]) + } + + holder.itemView.setOnClickListener { + itemClickedListener?.onItemClicked(file) + } + } + + abstract fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) + abstract fun bindImageRes(child: ViewHolder, item: File) + + private var itemClickedListener: OnItemClickedListener? = null + + interface OnItemClickedListener { + fun onItemClicked(item: File) + } + + fun setOnItemClickedListener(listener: OnItemClickedListener) { + itemClickedListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/extensions/Context.kt b/app/src/main/java/com/casic/endoscope/extensions/Context.kt index 0afcb27..a301aab 100644 --- a/app/src/main/java/com/casic/endoscope/extensions/Context.kt +++ b/app/src/main/java/com/casic/endoscope/extensions/Context.kt @@ -2,13 +2,22 @@ import android.content.Context import android.os.Environment +import com.pengxh.kt.lite.extensions.timestampToDate import java.io.File //扩展函数 fun Context.createVideoFileDir(): File { - val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), System.currentTimeMillis().timestampToDate()) if (!videoDir.exists()) { videoDir.mkdir() } return videoDir +} + +fun Context.createImageFileDir(): File { + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis().timestampToDate()) + if (!imageDir.exists()) { + imageDir.mkdir() + } + return imageDir } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt index c0020ec..8c4b495 100644 --- a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt @@ -1,32 +1,127 @@ package com.casic.endoscope.view +import android.annotation.SuppressLint +import android.content.pm.ActivityInfo import android.os.Bundle -import android.util.Log +import android.os.Environment +import android.view.View +import android.widget.ImageView +import androidx.activity.OnBackPressedCallback +import androidx.lifecycle.lifecycleScope +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.adapter.MediaDirAdapter import com.casic.endoscope.databinding.ActivityAlbumBinding -import com.casic.endoscope.extensions.createVideoFileDir import com.gyf.immersionbar.ImmersionBar +import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getStatusBarHeight +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File class AlbumActivity : KotlinBaseActivity() { private val kTag = "AlbumActivity" + private val context = this@AlbumActivity + //子文件夹集合 + private var dirBeans = ArrayList() + private lateinit var directoryAdapter: MediaDirAdapter + + @SuppressLint("NotifyDataSetChanged") override fun initEvent() { + binding.ascButton.setOnClickListener { + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + binding.decButton.setOnClickListener { + //升序 + dirBeans.sortBy { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + + //替换onBackPressed + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + GSYVideoManager.backFromWindowFull(context) + //解决退出全屏后会被强制竖屏的问题 + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { - val videoDir = createVideoFileDir() - videoDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val temp = ArrayList() + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + videoDir.list()?.forEach { + temp.add(it) } - val imageDir = createImageFileDir() - imageDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + imageDir.list()?.forEach { + temp.add(it) } + + //去重 + val directoryNameSet = HashSet(temp) + + //全部转为File类型,方便是用自带的排序函数 + directoryNameSet.forEach { + dirBeans.add(File(it)) + } + + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + + //绑定数据 + directoryAdapter = object : MediaDirAdapter(this, dirBeans) { + override fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) { + val videoPlayer = child.getView(R.id.videoPlayer) + videoPlayer.titleTextView.visibility = View.GONE + videoPlayer.backButton.visibility = View.GONE + lifecycleScope.launch(Dispatchers.Main) { + try { + val drawable = withContext(Dispatchers.IO) { + Glide.with(context) + .load(item) + .submit() + .get() + } + val coverImg = ImageView(context) + coverImg.setImageDrawable(drawable) + videoPlayer.thumbImageView = coverImg + } catch (e: Exception) { + e.printStackTrace() + } + } + videoPlayer.setUp(item.absolutePath, true, "") + videoPlayer.fullscreenButton.setOnClickListener { + videoPlayer.startWindowFullscreen(context, false, true) + } + //防止错位设置 + videoPlayer.playTag = System.currentTimeMillis().toString() + videoPlayer.playPosition = childPos + //是否根据视频尺寸,自动选择竖屏全屏或者横屏全屏 + videoPlayer.isAutoFullWithSize = true + //音频焦点冲突时是否释放 + videoPlayer.isReleaseWhenLossAudio = false + //全屏动画 + videoPlayer.isShowFullAnimation = true + } + } + val offset = 10.dp2px(this) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(offset, offset, offset, offset) + ) + binding.recyclerView.adapter = directoryAdapter } override fun initViewBinding(): ActivityAlbumBinding { @@ -44,4 +139,19 @@ binding.rootView.setPadding(0, statusBarHeight, 0, 0) binding.rootView.requestLayout() } + + override fun onPause() { + super.onPause() + GSYVideoManager.onPause() + } + + override fun onResume() { + super.onResume() + GSYVideoManager.onResume() + } + + override fun onDestroy() { + super.onDestroy() + GSYVideoManager.releaseAllVideos() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt new file mode 100644 index 0000000..c0aa2b3 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt @@ -0,0 +1,90 @@ +package com.casic.endoscope.view + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.databinding.ActivityBigImageBinding +import com.casic.endoscope.extensions.initImmersionBar +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant + +class BigImageActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityBigImageBinding { + return ActivityBigImageBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + binding.rootView.initImmersionBar(this, false, R.color.black) + binding.leftBackView.setOnClickListener { finish() } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + val index = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + binding.pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + binding.imagePagerView.adapter = BigImageAdapter(this, urls) + binding.imagePagerView.currentItem = index + binding.imagePagerView.offscreenPageLimit = imageSize + binding.imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + binding.pageNumberView.text = + String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt index 8c1a5dd..d05c4c5 100644 --- a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt @@ -14,6 +14,7 @@ import com.casic.endoscope.adapter.CameraPointAdapter import com.casic.endoscope.bean.CameraPointBean import com.casic.endoscope.databinding.ActivityMainBinding +import com.casic.endoscope.extensions.createImageFileDir import com.casic.endoscope.extensions.createVideoFileDir import com.casic.endoscope.extensions.getChannel import com.casic.endoscope.extensions.toTime @@ -28,7 +29,6 @@ import com.hikvision.netsdk.NET_DVR_PREVIEWINFO import com.hikvision.netsdk.PTZCommand import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir import com.pengxh.kt.lite.extensions.getStatusBarHeight import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show diff --git a/app/src/main/res/anim/activity_in.xml b/app/src/main/res/anim/activity_in.xml new file mode 100644 index 0000000..f2696ba --- /dev/null +++ b/app/src/main/res/anim/activity_in.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/activity_out.xml b/app/src/main/res/anim/activity_out.xml new file mode 100644 index 0000000..1e424a5 --- /dev/null +++ b/app/src/main/res/anim/activity_out.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_album.xml b/app/src/main/res/layout/activity_album.xml index 38360ea..cf06f5a 100644 --- a/app/src/main/res/layout/activity_album.xml +++ b/app/src/main/res/layout/activity_album.xml @@ -51,7 +51,7 @@ android:orientation="horizontal"> + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_big_picture.xml b/app/src/main/res/layout/item_big_picture.xml new file mode 100644 index 0000000..d90eb44 --- /dev/null +++ b/app/src/main/res/layout/item_big_picture.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_dir_list_rv.xml b/app/src/main/res/layout/item_dir_list_rv.xml new file mode 100644 index 0000000..f7b7597 --- /dev/null +++ b/app/src/main/res/layout/item_dir_list_rv.xml @@ -0,0 +1,31 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_image_list_gv.xml b/app/src/main/res/layout/item_image_list_gv.xml new file mode 100644 index 0000000..32fb2bd --- /dev/null +++ b/app/src/main/res/layout/item_image_list_gv.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_video_list_gv.xml b/app/src/main/res/layout/item_video_list_gv.xml new file mode 100644 index 0000000..e879ef5 --- /dev/null +++ b/app/src/main/res/layout/item_video_list_gv.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index e0708ab..184d22d 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -32,6 +32,9 @@ 75dp 80dp 100dp + 110dp + 115dp + 120dp 125dp 150dp 180dp diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3336534..b4fb060 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,5 +33,10 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt new file mode 100644 index 0000000..28e22c9 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -0,0 +1,75 @@ +package com.casic.endoscope.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Environment +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.casic.endoscope.view.BigImageActivity +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.navigatePageTo +import java.io.File + +abstract class MediaDirAdapter( + private val context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val kTag = "MediaDirAdapter" + private var fileBeans = ArrayList() + private lateinit var fileAdapter: MediaFileAdapter + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(context).inflate(R.layout.item_dir_list_rv, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) { + val date = dataRows[position].name + holder.setText(R.id.dateView, date) + + //根据不同的日期显示不同的改日期下的九宫格形式子文件 + val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) + videoDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) + imageDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val realPaths = ArrayList() + fileBeans.forEach { + val absolutePath = it.absolutePath + if (!absolutePath.endsWith(".mp4")) { + realPaths.add(absolutePath) + } + } + + fileAdapter = object : MediaFileAdapter(context, fileBeans) { + override fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) { + bindChildVideoRes(child, childPos, item) + } + + override fun bindImageRes(child: ViewHolder, item: File) { + child.setImageResource(R.id.imageView, item.absolutePath) + } + } + val recyclerView = holder.getView(R.id.recyclerView) + recyclerView.adapter = fileAdapter + fileAdapter.setOnItemClickedListener(object : MediaFileAdapter.OnItemClickedListener { + override fun onItemClicked(item: File) { + if (!item.name.endsWith(".mp4")) { + context.navigatePageTo(position, realPaths) + } + } + }) + } + + abstract fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt new file mode 100644 index 0000000..e447913 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt @@ -0,0 +1,62 @@ +package com.casic.endoscope.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.pengxh.kt.lite.adapter.ViewHolder +import java.io.File + +abstract class MediaFileAdapter( + context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val inflater: LayoutInflater = LayoutInflater.from(context) + private val TYPE_VIDEO = 0 + private val TYPE_IMAGE = 1 + + override fun getItemCount(): Int = dataRows.size + + override fun getItemViewType(position: Int): Int { + return if (dataRows[position].name.endsWith(".mp4")) { + TYPE_VIDEO + } else { + TYPE_IMAGE + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return if (viewType == TYPE_VIDEO) { + ViewHolder(inflater.inflate(R.layout.item_video_list_gv, parent, false)) + } else { + ViewHolder(inflater.inflate(R.layout.item_image_list_gv, parent, false)) + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val file = dataRows[position] + if (holder.itemViewType == TYPE_VIDEO) { + bindVideoRes(holder, position, dataRows[position]) + } else { + bindImageRes(holder, dataRows[position]) + } + + holder.itemView.setOnClickListener { + itemClickedListener?.onItemClicked(file) + } + } + + abstract fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) + abstract fun bindImageRes(child: ViewHolder, item: File) + + private var itemClickedListener: OnItemClickedListener? = null + + interface OnItemClickedListener { + fun onItemClicked(item: File) + } + + fun setOnItemClickedListener(listener: OnItemClickedListener) { + itemClickedListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/extensions/Context.kt b/app/src/main/java/com/casic/endoscope/extensions/Context.kt index 0afcb27..a301aab 100644 --- a/app/src/main/java/com/casic/endoscope/extensions/Context.kt +++ b/app/src/main/java/com/casic/endoscope/extensions/Context.kt @@ -2,13 +2,22 @@ import android.content.Context import android.os.Environment +import com.pengxh.kt.lite.extensions.timestampToDate import java.io.File //扩展函数 fun Context.createVideoFileDir(): File { - val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), System.currentTimeMillis().timestampToDate()) if (!videoDir.exists()) { videoDir.mkdir() } return videoDir +} + +fun Context.createImageFileDir(): File { + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis().timestampToDate()) + if (!imageDir.exists()) { + imageDir.mkdir() + } + return imageDir } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt index c0020ec..8c4b495 100644 --- a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt @@ -1,32 +1,127 @@ package com.casic.endoscope.view +import android.annotation.SuppressLint +import android.content.pm.ActivityInfo import android.os.Bundle -import android.util.Log +import android.os.Environment +import android.view.View +import android.widget.ImageView +import androidx.activity.OnBackPressedCallback +import androidx.lifecycle.lifecycleScope +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.adapter.MediaDirAdapter import com.casic.endoscope.databinding.ActivityAlbumBinding -import com.casic.endoscope.extensions.createVideoFileDir import com.gyf.immersionbar.ImmersionBar +import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getStatusBarHeight +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File class AlbumActivity : KotlinBaseActivity() { private val kTag = "AlbumActivity" + private val context = this@AlbumActivity + //子文件夹集合 + private var dirBeans = ArrayList() + private lateinit var directoryAdapter: MediaDirAdapter + + @SuppressLint("NotifyDataSetChanged") override fun initEvent() { + binding.ascButton.setOnClickListener { + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + binding.decButton.setOnClickListener { + //升序 + dirBeans.sortBy { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + + //替换onBackPressed + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + GSYVideoManager.backFromWindowFull(context) + //解决退出全屏后会被强制竖屏的问题 + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { - val videoDir = createVideoFileDir() - videoDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val temp = ArrayList() + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + videoDir.list()?.forEach { + temp.add(it) } - val imageDir = createImageFileDir() - imageDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + imageDir.list()?.forEach { + temp.add(it) } + + //去重 + val directoryNameSet = HashSet(temp) + + //全部转为File类型,方便是用自带的排序函数 + directoryNameSet.forEach { + dirBeans.add(File(it)) + } + + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + + //绑定数据 + directoryAdapter = object : MediaDirAdapter(this, dirBeans) { + override fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) { + val videoPlayer = child.getView(R.id.videoPlayer) + videoPlayer.titleTextView.visibility = View.GONE + videoPlayer.backButton.visibility = View.GONE + lifecycleScope.launch(Dispatchers.Main) { + try { + val drawable = withContext(Dispatchers.IO) { + Glide.with(context) + .load(item) + .submit() + .get() + } + val coverImg = ImageView(context) + coverImg.setImageDrawable(drawable) + videoPlayer.thumbImageView = coverImg + } catch (e: Exception) { + e.printStackTrace() + } + } + videoPlayer.setUp(item.absolutePath, true, "") + videoPlayer.fullscreenButton.setOnClickListener { + videoPlayer.startWindowFullscreen(context, false, true) + } + //防止错位设置 + videoPlayer.playTag = System.currentTimeMillis().toString() + videoPlayer.playPosition = childPos + //是否根据视频尺寸,自动选择竖屏全屏或者横屏全屏 + videoPlayer.isAutoFullWithSize = true + //音频焦点冲突时是否释放 + videoPlayer.isReleaseWhenLossAudio = false + //全屏动画 + videoPlayer.isShowFullAnimation = true + } + } + val offset = 10.dp2px(this) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(offset, offset, offset, offset) + ) + binding.recyclerView.adapter = directoryAdapter } override fun initViewBinding(): ActivityAlbumBinding { @@ -44,4 +139,19 @@ binding.rootView.setPadding(0, statusBarHeight, 0, 0) binding.rootView.requestLayout() } + + override fun onPause() { + super.onPause() + GSYVideoManager.onPause() + } + + override fun onResume() { + super.onResume() + GSYVideoManager.onResume() + } + + override fun onDestroy() { + super.onDestroy() + GSYVideoManager.releaseAllVideos() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt new file mode 100644 index 0000000..c0aa2b3 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt @@ -0,0 +1,90 @@ +package com.casic.endoscope.view + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.databinding.ActivityBigImageBinding +import com.casic.endoscope.extensions.initImmersionBar +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant + +class BigImageActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityBigImageBinding { + return ActivityBigImageBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + binding.rootView.initImmersionBar(this, false, R.color.black) + binding.leftBackView.setOnClickListener { finish() } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + val index = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + binding.pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + binding.imagePagerView.adapter = BigImageAdapter(this, urls) + binding.imagePagerView.currentItem = index + binding.imagePagerView.offscreenPageLimit = imageSize + binding.imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + binding.pageNumberView.text = + String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt index 8c1a5dd..d05c4c5 100644 --- a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt @@ -14,6 +14,7 @@ import com.casic.endoscope.adapter.CameraPointAdapter import com.casic.endoscope.bean.CameraPointBean import com.casic.endoscope.databinding.ActivityMainBinding +import com.casic.endoscope.extensions.createImageFileDir import com.casic.endoscope.extensions.createVideoFileDir import com.casic.endoscope.extensions.getChannel import com.casic.endoscope.extensions.toTime @@ -28,7 +29,6 @@ import com.hikvision.netsdk.NET_DVR_PREVIEWINFO import com.hikvision.netsdk.PTZCommand import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir import com.pengxh.kt.lite.extensions.getStatusBarHeight import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show diff --git a/app/src/main/res/anim/activity_in.xml b/app/src/main/res/anim/activity_in.xml new file mode 100644 index 0000000..f2696ba --- /dev/null +++ b/app/src/main/res/anim/activity_in.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/activity_out.xml b/app/src/main/res/anim/activity_out.xml new file mode 100644 index 0000000..1e424a5 --- /dev/null +++ b/app/src/main/res/anim/activity_out.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_album.xml b/app/src/main/res/layout/activity_album.xml index 38360ea..cf06f5a 100644 --- a/app/src/main/res/layout/activity_album.xml +++ b/app/src/main/res/layout/activity_album.xml @@ -51,7 +51,7 @@ android:orientation="horizontal"> + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_big_picture.xml b/app/src/main/res/layout/item_big_picture.xml new file mode 100644 index 0000000..d90eb44 --- /dev/null +++ b/app/src/main/res/layout/item_big_picture.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_dir_list_rv.xml b/app/src/main/res/layout/item_dir_list_rv.xml new file mode 100644 index 0000000..f7b7597 --- /dev/null +++ b/app/src/main/res/layout/item_dir_list_rv.xml @@ -0,0 +1,31 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_image_list_gv.xml b/app/src/main/res/layout/item_image_list_gv.xml new file mode 100644 index 0000000..32fb2bd --- /dev/null +++ b/app/src/main/res/layout/item_image_list_gv.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_video_list_gv.xml b/app/src/main/res/layout/item_video_list_gv.xml new file mode 100644 index 0000000..e879ef5 --- /dev/null +++ b/app/src/main/res/layout/item_video_list_gv.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index e0708ab..184d22d 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -32,6 +32,9 @@ 75dp 80dp 100dp + 110dp + 115dp + 120dp 125dp 150dp 180dp diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..b6317cd --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3336534..b4fb060 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,5 +33,10 @@ + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt new file mode 100644 index 0000000..28e22c9 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaDirAdapter.kt @@ -0,0 +1,75 @@ +package com.casic.endoscope.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Environment +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.casic.endoscope.view.BigImageActivity +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.navigatePageTo +import java.io.File + +abstract class MediaDirAdapter( + private val context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val kTag = "MediaDirAdapter" + private var fileBeans = ArrayList() + private lateinit var fileAdapter: MediaFileAdapter + + override fun getItemCount(): Int = dataRows.size + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + LayoutInflater.from(context).inflate(R.layout.item_dir_list_rv, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, @SuppressLint("RecyclerView") position: Int) { + val date = dataRows[position].name + holder.setText(R.id.dateView, date) + + //根据不同的日期显示不同的改日期下的九宫格形式子文件 + val videoDir = File(context.getExternalFilesDir(Environment.DIRECTORY_MOVIES), date) + videoDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), date) + imageDir.listFiles()?.forEach { + fileBeans.add(it) + } + + val realPaths = ArrayList() + fileBeans.forEach { + val absolutePath = it.absolutePath + if (!absolutePath.endsWith(".mp4")) { + realPaths.add(absolutePath) + } + } + + fileAdapter = object : MediaFileAdapter(context, fileBeans) { + override fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) { + bindChildVideoRes(child, childPos, item) + } + + override fun bindImageRes(child: ViewHolder, item: File) { + child.setImageResource(R.id.imageView, item.absolutePath) + } + } + val recyclerView = holder.getView(R.id.recyclerView) + recyclerView.adapter = fileAdapter + fileAdapter.setOnItemClickedListener(object : MediaFileAdapter.OnItemClickedListener { + override fun onItemClicked(item: File) { + if (!item.name.endsWith(".mp4")) { + context.navigatePageTo(position, realPaths) + } + } + }) + } + + abstract fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt new file mode 100644 index 0000000..e447913 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/adapter/MediaFileAdapter.kt @@ -0,0 +1,62 @@ +package com.casic.endoscope.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.casic.endoscope.R +import com.pengxh.kt.lite.adapter.ViewHolder +import java.io.File + +abstract class MediaFileAdapter( + context: Context, private val dataRows: MutableList +) : RecyclerView.Adapter() { + + private val inflater: LayoutInflater = LayoutInflater.from(context) + private val TYPE_VIDEO = 0 + private val TYPE_IMAGE = 1 + + override fun getItemCount(): Int = dataRows.size + + override fun getItemViewType(position: Int): Int { + return if (dataRows[position].name.endsWith(".mp4")) { + TYPE_VIDEO + } else { + TYPE_IMAGE + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return if (viewType == TYPE_VIDEO) { + ViewHolder(inflater.inflate(R.layout.item_video_list_gv, parent, false)) + } else { + ViewHolder(inflater.inflate(R.layout.item_image_list_gv, parent, false)) + } + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val file = dataRows[position] + if (holder.itemViewType == TYPE_VIDEO) { + bindVideoRes(holder, position, dataRows[position]) + } else { + bindImageRes(holder, dataRows[position]) + } + + holder.itemView.setOnClickListener { + itemClickedListener?.onItemClicked(file) + } + } + + abstract fun bindVideoRes(child: ViewHolder, childPos: Int, item: File) + abstract fun bindImageRes(child: ViewHolder, item: File) + + private var itemClickedListener: OnItemClickedListener? = null + + interface OnItemClickedListener { + fun onItemClicked(item: File) + } + + fun setOnItemClickedListener(listener: OnItemClickedListener) { + itemClickedListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/extensions/Context.kt b/app/src/main/java/com/casic/endoscope/extensions/Context.kt index 0afcb27..a301aab 100644 --- a/app/src/main/java/com/casic/endoscope/extensions/Context.kt +++ b/app/src/main/java/com/casic/endoscope/extensions/Context.kt @@ -2,13 +2,22 @@ import android.content.Context import android.os.Environment +import com.pengxh.kt.lite.extensions.timestampToDate import java.io.File //扩展函数 fun Context.createVideoFileDir(): File { - val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), System.currentTimeMillis().timestampToDate()) if (!videoDir.exists()) { videoDir.mkdir() } return videoDir +} + +fun Context.createImageFileDir(): File { + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), System.currentTimeMillis().timestampToDate()) + if (!imageDir.exists()) { + imageDir.mkdir() + } + return imageDir } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt index c0020ec..8c4b495 100644 --- a/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/AlbumActivity.kt @@ -1,32 +1,127 @@ package com.casic.endoscope.view +import android.annotation.SuppressLint +import android.content.pm.ActivityInfo import android.os.Bundle -import android.util.Log +import android.os.Environment +import android.view.View +import android.widget.ImageView +import androidx.activity.OnBackPressedCallback +import androidx.lifecycle.lifecycleScope +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.adapter.MediaDirAdapter import com.casic.endoscope.databinding.ActivityAlbumBinding -import com.casic.endoscope.extensions.createVideoFileDir import com.gyf.immersionbar.ImmersionBar +import com.pengxh.kt.lite.adapter.ViewHolder import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir +import com.pengxh.kt.lite.divider.RecyclerViewItemOffsets +import com.pengxh.kt.lite.extensions.dp2px import com.pengxh.kt.lite.extensions.getStatusBarHeight +import com.shuyu.gsyvideoplayer.GSYVideoManager +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File class AlbumActivity : KotlinBaseActivity() { private val kTag = "AlbumActivity" + private val context = this@AlbumActivity + //子文件夹集合 + private var dirBeans = ArrayList() + private lateinit var directoryAdapter: MediaDirAdapter + + @SuppressLint("NotifyDataSetChanged") override fun initEvent() { + binding.ascButton.setOnClickListener { + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + binding.decButton.setOnClickListener { + //升序 + dirBeans.sortBy { dir -> dir.name } + directoryAdapter.notifyDataSetChanged() + } + + //替换onBackPressed + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + GSYVideoManager.backFromWindowFull(context) + //解决退出全屏后会被强制竖屏的问题 + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + } + }) } override fun initOnCreate(savedInstanceState: Bundle?) { - val videoDir = createVideoFileDir() - videoDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val temp = ArrayList() + val videoDir = File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), "") + videoDir.list()?.forEach { + temp.add(it) } - val imageDir = createImageFileDir() - imageDir.listFiles()?.forEach { - Log.d(kTag, "initOnCreate => ${it.name}") + val imageDir = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + imageDir.list()?.forEach { + temp.add(it) } + + //去重 + val directoryNameSet = HashSet(temp) + + //全部转为File类型,方便是用自带的排序函数 + directoryNameSet.forEach { + dirBeans.add(File(it)) + } + + //按时间排序,降序 + dirBeans.sortByDescending { dir -> dir.name } + + //绑定数据 + directoryAdapter = object : MediaDirAdapter(this, dirBeans) { + override fun bindChildVideoRes(child: ViewHolder, childPos: Int, item: File) { + val videoPlayer = child.getView(R.id.videoPlayer) + videoPlayer.titleTextView.visibility = View.GONE + videoPlayer.backButton.visibility = View.GONE + lifecycleScope.launch(Dispatchers.Main) { + try { + val drawable = withContext(Dispatchers.IO) { + Glide.with(context) + .load(item) + .submit() + .get() + } + val coverImg = ImageView(context) + coverImg.setImageDrawable(drawable) + videoPlayer.thumbImageView = coverImg + } catch (e: Exception) { + e.printStackTrace() + } + } + videoPlayer.setUp(item.absolutePath, true, "") + videoPlayer.fullscreenButton.setOnClickListener { + videoPlayer.startWindowFullscreen(context, false, true) + } + //防止错位设置 + videoPlayer.playTag = System.currentTimeMillis().toString() + videoPlayer.playPosition = childPos + //是否根据视频尺寸,自动选择竖屏全屏或者横屏全屏 + videoPlayer.isAutoFullWithSize = true + //音频焦点冲突时是否释放 + videoPlayer.isReleaseWhenLossAudio = false + //全屏动画 + videoPlayer.isShowFullAnimation = true + } + } + val offset = 10.dp2px(this) + binding.recyclerView.addItemDecoration( + RecyclerViewItemOffsets(offset, offset, offset, offset) + ) + binding.recyclerView.adapter = directoryAdapter } override fun initViewBinding(): ActivityAlbumBinding { @@ -44,4 +139,19 @@ binding.rootView.setPadding(0, statusBarHeight, 0, 0) binding.rootView.requestLayout() } + + override fun onPause() { + super.onPause() + GSYVideoManager.onPause() + } + + override fun onResume() { + super.onResume() + GSYVideoManager.onResume() + } + + override fun onDestroy() { + super.onDestroy() + GSYVideoManager.releaseAllVideos() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt new file mode 100644 index 0000000..c0aa2b3 --- /dev/null +++ b/app/src/main/java/com/casic/endoscope/view/BigImageActivity.kt @@ -0,0 +1,90 @@ +package com.casic.endoscope.view + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.endoscope.R +import com.casic.endoscope.databinding.ActivityBigImageBinding +import com.casic.endoscope.extensions.initImmersionBar +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant + +class BigImageActivity : KotlinBaseActivity() { + + override fun initViewBinding(): ActivityBigImageBinding { + return ActivityBigImageBinding.inflate(layoutInflater) + } + + override fun setupTopBarLayout() { + binding.rootView.initImmersionBar(this, false, R.color.black) + binding.leftBackView.setOnClickListener { finish() } + } + + override fun initOnCreate(savedInstanceState: Bundle?) { + val index = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + binding.pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + binding.imagePagerView.adapter = BigImageAdapter(this, urls) + binding.imagePagerView.currentItem = index + binding.imagePagerView.offscreenPageLimit = imageSize + binding.imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + binding.pageNumberView.text = + String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt index 8c1a5dd..d05c4c5 100644 --- a/app/src/main/java/com/casic/endoscope/view/MainActivity.kt +++ b/app/src/main/java/com/casic/endoscope/view/MainActivity.kt @@ -14,6 +14,7 @@ import com.casic.endoscope.adapter.CameraPointAdapter import com.casic.endoscope.bean.CameraPointBean import com.casic.endoscope.databinding.ActivityMainBinding +import com.casic.endoscope.extensions.createImageFileDir import com.casic.endoscope.extensions.createVideoFileDir import com.casic.endoscope.extensions.getChannel import com.casic.endoscope.extensions.toTime @@ -28,7 +29,6 @@ import com.hikvision.netsdk.NET_DVR_PREVIEWINFO import com.hikvision.netsdk.PTZCommand import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.createImageFileDir import com.pengxh.kt.lite.extensions.getStatusBarHeight import com.pengxh.kt.lite.extensions.navigatePageTo import com.pengxh.kt.lite.extensions.show diff --git a/app/src/main/res/anim/activity_in.xml b/app/src/main/res/anim/activity_in.xml new file mode 100644 index 0000000..f2696ba --- /dev/null +++ b/app/src/main/res/anim/activity_in.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/activity_out.xml b/app/src/main/res/anim/activity_out.xml new file mode 100644 index 0000000..1e424a5 --- /dev/null +++ b/app/src/main/res/anim/activity_out.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_album.xml b/app/src/main/res/layout/activity_album.xml index 38360ea..cf06f5a 100644 --- a/app/src/main/res/layout/activity_album.xml +++ b/app/src/main/res/layout/activity_album.xml @@ -51,7 +51,7 @@ android:orientation="horizontal"> + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_big_picture.xml b/app/src/main/res/layout/item_big_picture.xml new file mode 100644 index 0000000..d90eb44 --- /dev/null +++ b/app/src/main/res/layout/item_big_picture.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_dir_list_rv.xml b/app/src/main/res/layout/item_dir_list_rv.xml new file mode 100644 index 0000000..f7b7597 --- /dev/null +++ b/app/src/main/res/layout/item_dir_list_rv.xml @@ -0,0 +1,31 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_image_list_gv.xml b/app/src/main/res/layout/item_image_list_gv.xml new file mode 100644 index 0000000..32fb2bd --- /dev/null +++ b/app/src/main/res/layout/item_image_list_gv.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_video_list_gv.xml b/app/src/main/res/layout/item_video_list_gv.xml new file mode 100644 index 0000000..e879ef5 --- /dev/null +++ b/app/src/main/res/layout/item_video_list_gv.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index e0708ab..184d22d 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -32,6 +32,9 @@ 75dp 80dp 100dp + 110dp + 115dp + 120dp 125dp 150dp 180dp diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..b6317cd --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 315720c..caf4355 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -6,4 +6,8 @@ @color/purple_500 + + \ No newline at end of file