/*********************************************************************
* * Copyright (C), 2010-2022 Oplus. All rights reserved..
* * VENDOR_EDIT
* * File : AddFilePanelFragment.kt
* * Description : AddFilePanelFragment
* * Version : 1.0
* * Date : 2025/02/08
* * Author : W9085798
* *
* * ---------------------Revision History: ----------------------------
* * <author> <data> <version> <desc>
***********************************************************************/
package com.oplus.filemanager.addfilepanel.ui
import android.annotation.SuppressLint
import android.app.Activity
import android.os.SystemClock
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.annotation.VisibleForTesting
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider
import com.coui.appcompat.button.COUIButton
import com.coui.appcompat.button.SingleButtonWrap
import com.coui.appcompat.contextutil.COUIContextUtil
import com.coui.appcompat.panel.COUIBottomSheetDialog
import com.coui.appcompat.panel.COUIBottomSheetDialogFragment
import com.coui.appcompat.panel.COUIPanelFragment
import com.coui.appcompat.panel.COUIPanelMultiWindowUtils
import com.coui.appcompat.tablayout.COUITab
import com.coui.appcompat.tablayout.COUITabLayout
import com.coui.appcompat.toolbar.COUIToolbar
import com.filemanager.common.MyApplication.appContext
import com.filemanager.common.base.BaseFileBean
import com.filemanager.common.base.BaseFragmentAdapter
import com.filemanager.common.constants.Constants
import com.filemanager.common.controller.LoadingController
import com.filemanager.common.controller.PrivacyPolicyController
import com.filemanager.common.helper.MimeTypeHelper
import com.filemanager.common.helper.uiconfig.UIConfigMonitor
import com.filemanager.common.utils.Injector
import com.filemanager.common.utils.KtViewUtils
import com.filemanager.common.utils.Log
import com.filemanager.common.utils.ModelUtils
import com.filemanager.common.utils.SdkUtils
import com.filemanager.common.utils.StatusBarUtil
import com.filemanager.common.utils.Utils
import com.filemanager.common.utils.dp2px
import com.filemanager.common.view.ViewPagerWrapperForPC
import com.filemanager.common.view.viewpager.RTLViewPager
import com.oplus.filemanager.addfilepanel.R
import com.oplus.filemanager.addfilepanel.bean.AddFileBean
import com.oplus.filemanager.addfilepanel.viewmodel.AddFilePanelViewModel
import com.oplus.filemanager.interfaze.categorydoc.IDocumentExtensionType
import com.oplus.filemanager.interfaze.main.IMain
import kotlin.properties.Delegates
class AddFilePanelFragment : COUIPanelFragment(), COUITabLayout.OnTabSelectedListener,
PrivacyPolicyController.OnPrivacyPolicyListener {
companion object {
private const val TAG = "ShortcutFolderAddFilePanelFragment"
private const val NUM = 1024
private const val DECIMAL_NUM = 1024f
private const val DISMISS_TIME_GAP = 1000L
private const val DELAY_TIME = 50L
private const val PANEL_MAX_HEIGHT = "panel_max_height"
}
var lifeCycle: Lifecycle by Delegates.notNull()
var title: String? = null
var mCurrentPath: String = ""
private var disMissTime: Long = 0L
private var toolBar: COUIToolbar? = null
private var mTabTitle = arrayListOf(
appContext.resources.getString(com.filemanager.common.R.string.total),
appContext.resources.getString(com.filemanager.common.R.string.string_photos),
appContext.resources.getString(com.filemanager.common.R.string.string_videos),
appContext.resources.getString(com.filemanager.common.R.string.string_audio),
appContext.resources.getString(com.filemanager.common.R.string.string_documents),
appContext.resources.getString(com.filemanager.common.R.string.string_other)
)
private val mTabTitles = intArrayOf(
Constants.TAB_ALL, Constants.TAB_IMAGE, Constants.TAB_VIDEO,
Constants.TAB_AUDIO, Constants.TAB_DOCUMENT, Constants.TAB_OTHER
)
private var mAddFileDialogInterface: AddFileDialogInterface? = null
private var mPages: ArrayList<AddFileListFragment> = ArrayList()
private var mViewPager: RTLViewPager? = null
private var mTabView: COUITabLayout? = null
private var mViewPagerWrapper: ViewPagerWrapperForPC? = null
private var addFileBtn: COUIButton? = null
private var verticalButtonWrap: SingleButtonWrap? = null
private var rootView: ViewGroup? = null
private var addFilePanelViewModel: AddFilePanelViewModel? = null
private var statisticsSelectTitleView: TextView? = null
private var statisticsSelectBodyView: TextView? = null
private var contentLayout: RelativeLayout? = null
private var buttonDivider: View? = null
private var statisticsArrowUpView: ImageView? = null
private var statisticsRootView: ViewGroup? = null
private var loadingController: LoadingController? = null
private var mPosition: Int = 0
var limitCount: Int = 0
private val allFiles: MutableList<BaseFileBean> = mutableListOf()
private val imageFiles: MutableList<BaseFileBean> = mutableListOf()
private val videoFiles: MutableList<BaseFileBean> = mutableListOf()
private val audioFiles: MutableList<BaseFileBean> = mutableListOf()
private val docFiles: MutableList<BaseFileBean> = mutableListOf()
private val otherFiles: MutableList<BaseFileBean> = mutableListOf()
private val mSelectArrayByID: MutableSet<Long> = mutableSetOf()
var addFileClickCallback: (selectData: List<AddFileBean>) -> Unit = {}
var isExternalReference: Boolean = false
private fun setPanelMaxHeight() {
if (activity == null) return
rootView?.layoutParams?.apply {
if (UIConfigMonitor.isCurrentZoomWindowShow() && SdkUtils.isAtLeastR() && !isExternalReference) {
val savedHeight: Int = arguments?.getInt(PANEL_MAX_HEIGHT) ?: 0
Log.d(TAG, "setPanelMaxHeight savedHeight = $savedHeight")
if (savedHeight == 0) {
// 处理浮窗
height = handleZoomWindowHeight(requireActivity(), height)
arguments?.putInt(PANEL_MAX_HEIGHT, height)
} else {
height = savedHeight
}
Log.d(TAG, "setPanelMaxHeight height = $height")
} else {
val screenHeight = dp2px(requireActivity(), requireActivity().resources.configuration.screenHeightDp)
val panelMaxHeight = COUIPanelMultiWindowUtils.getPanelMaxHeight(requireActivity(), requireActivity().resources.configuration)
Log.d(TAG, "setPanelMaxHeight screenHeight:$screenHeight panelH:$panelMaxHeight height:$height")
//当是分屏
if (requireActivity().isInMultiWindowMode) {
if (StatusBarUtil.checkIsGestureNavMode(requireActivity())) { //全面屏手势导航
height = handleGestureNavModeHeight(requireActivity(), height)
} else { // 底部导航栏
height = Math.min(screenHeight, panelMaxHeight) - requireActivity().resources.getDimensionPixelOffset(
com.filemanager.common.R.dimen.dimen_40dp
)
height = handleNavModeHeight(requireActivity(), height)
}
}
rootView?.layoutParams = this
}
}
}
/**
* 处理浮窗模式下的高度
*/
private fun handleZoomWindowHeight(activity: Activity, height: Int): Int {
var result = height
val statusBarH = COUIPanelMultiWindowUtils.getStatusBarHeight(activity)
val configuration = activity.resources.configuration
val paddingBottom = COUIPanelMultiWindowUtils.getPanelMarginBottom(context, configuration)
val rect = COUIPanelMultiWindowUtils.getCurrentWindowVisibleRect(activity)
if (rect != null) {
if (rect.top == 0) {
Log.d(TAG, "handleZoomWindowHeight: rect $rect top is invalid, reset")
rect.top = activity.resources.getDimensionPixelOffset(com.filemanager.common.R.dimen.panel_min_top_margin)
}
if (rect.bottom == 0) {
val windowH = KtViewUtils.getWindowSize(activity).y
rect.bottom = windowH
Log.d(TAG, "handleZoomWindowHeight: rect $rect bottom is invalid, reset $windowH")
}
result = (rect.bottom - rect.top) - paddingBottom - statusBarH
Log.d(TAG, "handleZoomWindowHeight: height $result = ${rect.bottom}-${rect.top}-$paddingBottom-$statusBarH")
}
return result
}
/**
* 处理底部导航栏导航时的高度
*/
private fun handleNavModeHeight(it: Activity, height: Int): Int {
val navBarHeight = KtViewUtils.getSoftNavigationBarSize(it)
var result = height
when {
ModelUtils.isTablet() -> { //平板竖屏分屏时
if (UIConfigMonitor.instance.isDevicePortrait(it)) {
result = height - navBarHeight
Log.d(TAG, "handleNavMode pad portrait height:$result")
}
}
UIConfigMonitor.instance.isFoldable(it) -> { // 折叠屏
result = height - navBarHeight
Log.d(TAG, "handleNavMode fold height:$result")
}
else -> { //手机且分屏处于下屏
if (!COUIPanelMultiWindowUtils.isDisplayInUpperWindow(it)) {
result = height - navBarHeight
Log.d(TAG, "handleNavMode phone lower split screen height:$result")
}
}
}
return result
}
/**
* 处理全面屏手势导航时的高度
*/
@VisibleForTesting
fun handleGestureNavModeHeight(activity: Activity, height: Int): Int {
if (COUIPanelMultiWindowUtils.isDisplayInUpperWindow(activity)) { // 上分屏,不用处理
return height
}
// 处于下分屏,并且显示了手势指示条
if (StatusBarUtil.checkShowGestureNavBar(activity)) {
val result = height - activity.resources.getDimensionPixelOffset(com.filemanager.common.R.dimen.dimen_16dp)
Log.d(TAG, "handleGestureNavMode lower split screen with show gesture nvaBar height:$result")
return result
}
return height
}
override fun onDestroy() {
Log.d(TAG, "onDestroy")
super.onDestroy()
verticalButtonWrap?.release()
clearDataList()
addFilePanelViewModel?.onDestroy()
}
override fun initView(panelView: View?) {
activity?.let { activity ->
LayoutInflater.from(activity).inflate(getLayoutResId(), null, false)?.let {
(contentView as? ViewGroup)?.addView(it)
initContentView(it)
initViewModel(activity)
startObserver()
initData()
}
}
}
private fun getLayoutResId(): Int {
return R.layout.add_file_panel_dialog
}
private fun initViewModel(act: FragmentActivity) {
addFilePanelViewModel = ViewModelProvider(act)[AddFilePanelViewModel::class.java]
}
private fun startObserver() {
addFilePanelViewModel?.mAllFiles?.observe(this) {
it ?: return@observe
showLoadingView(false)
setViewPagerData(it)
}
addFilePanelViewModel?.mAllSelectFiles?.observe(this) {
it ?: return@observe
updateStatisticsSelectView(it)
}
}
fun notifyUpdate() {
mSelectArrayByID.clear()
addFilePanelViewModel?.mAllSelectFiles?.value?.forEach { bean ->
if (bean.isSelected) {
bean.mFileID?.let { mSelectArrayByID.add(it) }
}
}
getCurrentFragment()?.apply {
setSelectedData(mSelectArrayByID)
notifyUpdate()
}
}
private fun initContentView(view: View) {
Log.d(TAG, "initContentView")
hideDragView()
rootView = view.findViewById(R.id.dialog_layout)
toolBar = view.findViewById(R.id.toolbar)
mTabView = view.findViewById<COUITabLayout?>(R.id.tab_layout)
mViewPager = view.findViewById(R.id.viewPager)
mViewPagerWrapper = view.findViewById<ViewPagerWrapperForPC?>(R.id.view_pager_wrapper).apply {
notifyMainViewPager = object : ((Boolean) -> Unit) {
override fun invoke(enable: Boolean) {
activity?.let {
val mainAction = Injector.injectFactory<IMain>()
mainAction?.setViewPagerScrollEnabled(it, enable)
}
}
}
}
addFileBtn = view.findViewById<COUIButton?>(R.id.btn_add_file).apply {
verticalButtonWrap = SingleButtonWrap(this, SingleButtonWrap.Type.Small)
setOnClickListener {
Log.d(TAG, "addFileBtn click. select:${addFilePanelViewModel?.mAllSelectFiles?.value?.size}")
val selectList = addFilePanelViewModel?.mAllSelectFiles?.value
selectList?.let { addFileClickCallback.invoke(it) }
}
}
contentLayout = view.findViewById(R.id.content_layout)
buttonDivider = view.findViewById(R.id.button_divider)
statisticsSelectTitleView = view.findViewById<TextView?>(R.id.select_title_content)
statisticsSelectBodyView = view.findViewById<TextView?>(R.id.select_body_content)
statisticsArrowUpView = view.findViewById(R.id.select_arraw_up)
statisticsRootView = view.findViewById<ViewGroup?>(R.id.select_root_view).apply {
setOnClickListener {
if (Utils.isQuickClick()) {
Log.w(TAG, "click too fast, try later")
return@setOnClickListener
}
addFilePanelViewModel?.mAllSelectFiles?.value?.let {
mAddFileDialogInterface?.replaceSelectedPanelFragment(it)
}
}
}
setPanelMaxHeight()
}
private fun initData() {
initToolBar()
resetStatisticsView()
val fragments = childFragmentManager.fragments
for (i in mTabTitles.indices) {
initFragment(i, fragments)
}
initViewPager()
if (PrivacyPolicyController.hasAgreePrivacy()) {
loadData()
} else {
PrivacyPolicyController.bindPrivacyPolicyListener(this)
}
}
private fun loadData() {
Log.d(TAG, "loadData")
showLoadingView(true)
// 加载数据
activity?.let { addFilePanelViewModel?.loadAllFiles(it) }
}
private fun resetStatisticsView() {
addFileBtn?.isEnabled = false
statisticsSelectTitleView?.apply {
visibility = View.VISIBLE
text = appContext.resources.getString(com.filemanager.common.R.string.not_selected_file)
}
statisticsSelectBodyView?.apply {
visibility = View.GONE
text = ""
}
statisticsArrowUpView?.apply {
visibility = View.GONE
}
statisticsRootView?.apply {
isClickable = false
}
}
private fun initToolBar() {
toolBar?.apply {
visibility = View.VISIBLE
title = appContext.resources.getString(com.filemanager.common.R.string.encryption_file_select_title)
isTitleCenterStyle = true
inflateMenu(R.menu.add_file_panel_dialog_menu_bar)
menu.findItem(R.id.cancel).setOnMenuItemClickListener {
mAddFileDialogInterface?.dismissAddFileDialog()
true
}
}
if ((mTabView != null) && (mViewPager != null)) {
mTabView?.let {
it.setupWithViewPager(mViewPager, false)
it.addOnTabSelectedListener(this)
it.isUpdateindicatorposition = true
}
}
}
fun setAddFileDialogInterface(addFileDialog: AddFileDialogInterface) {
mAddFileDialogInterface = addFileDialog
}
private fun initViewPager() {
mViewPager?.let {
it.offscreenPageLimit = mTabTitles.size
it.adapter = ViewPagerFragmentStateAdapter(this)
it.currentItem = 0
it.overScrollMode = View.OVER_SCROLL_NEVER
}
}
private fun initFragment(position: Int, fragments: List<Fragment>): Fragment {
Log.d(TAG, "initFragment")
var fragment = if (fragments.isEmpty()) null else fragments[position]
if (fragment == null) {
fragment = AddFileListFragment()
fragment.isExternalReference = isExternalReference
fragment.lifeCycle = lifeCycle
fragment.mOnItemSelectCallback = { _, fileID ->
mSelectArrayByID.add(fileID)
addFilePanelViewModel?.updateAllSelectFiles(mSelectArrayByID)
}
fragment.mOnItemUnSelectCallback = { _, fileID ->
mSelectArrayByID.remove(fileID)
addFilePanelViewModel?.updateAllSelectFiles(mSelectArrayByID)
}
fragment.mFileEmptyCallback = { isShowEmpty ->
handleFileEmptyView(isShowEmpty)
}
fragment.mCurrentPath = mCurrentPath
fragment.limitCount = limitCount
}
if (fragment is AddFileListFragment) {
mPages.add(fragment)
}
return fragment
}
private fun handleFileEmptyView(isShowEmptyView: Boolean) {
if (isShowEmptyView) {
showLoadingView(false)
buttonDivider?.alpha = 0F
} else {
buttonDivider?.alpha = 1F
}
}
private fun showLoadingView(isShow: Boolean) {
if (isShow) {
Log.d(TAG, "showLoadingView disMissTime $disMissTime")
activity?.let {
loadingController = LoadingController(it, this)
//如果异常loadingView刚刚调用,就不调用显示loadingView,防止loadingView一直显示
Log.d(TAG, "showLoadingView getLoadingShowStartTime ${loadingController?.getLoadingShowStartTime()}")
if (SystemClock.elapsedRealtime() - disMissTime >= DISMISS_TIME_GAP || loadingController?.getLoadingShowStartTime() == 0L) {
loadingController?.showLoading(contentLayout)
}
}
} else {
Log.d(TAG, "showLoadingView dismissLoading")
loadingController?.dismissLoading()
disMissTime = SystemClock.elapsedRealtime()
}
}
override fun onShow(isShowOnFirstPanel: Boolean?) {
super.onShow(isShowOnFirstPanel)
((parentFragment as? COUIBottomSheetDialogFragment)?.dialog as? COUIBottomSheetDialog)
?.setPanelBackgroundTintColor(COUIContextUtil.getAttrColor(context, com.support.appcompat.R.attr.couiColorBackgroundElevatedWithCard))
}
private fun clearDataList() {
allFiles.clear()
imageFiles.clear()
videoFiles.clear()
audioFiles.clear()
docFiles.clear()
otherFiles.clear()
mSelectArrayByID.clear()
}
private fun setViewPagerData(data: MutableList<AddFileBean>) {
Log.d(TAG, "setViewPagerData")
clearDataList()
allFiles.addAll(data)
val documentExtensionType = Injector.injectFactory<IDocumentExtensionType>()
data.forEach { file ->
val localType = file.mLocalType
if (MimeTypeHelper.isImageType(localType)) {
imageFiles.add(file)
} else if (MimeTypeHelper.isVideoType(localType)) {
videoFiles.add(file)
} else if (MimeTypeHelper.isAudioType(localType)) {
audioFiles.add(file)
} else if ((MimeTypeHelper.isDocType(localType) || MimeTypeHelper.isOtherDocType(localType))
&& documentExtensionType?.isCategoryDocSupportType(file) == true
) {
//isCategoryDocSupportType确保面板上文档分类显示的内容和文管文档分类一致(部分未知格式后缀会识解析TXT类型)
docFiles.add(file)
} else {
otherFiles.add(file)
}
}
updateData(mTabTitles[mPosition])
}
private fun updateStatisticsSelectView(data: MutableList<AddFileBean>) {
if (data.size <= 0) {
Log.d(TAG, "unselect file")
resetStatisticsView()
return
}
addFileBtn?.isEnabled = true
statisticsSelectTitleView?.apply {
visibility = View.VISIBLE
text = appContext.resources.getQuantityString(
com.filemanager.common.R.plurals.mark_selected_items_new,
data.size,
data.size
)
}
statisticsSelectBodyView?.apply {
visibility = View.VISIBLE
val size: Long = data.sumOf { it.mSize }
val totalSize: String = updateSizeFormat(size)
text = appContext.resources.getString(com.filemanager.common.R.string.selected_size, totalSize)
}
statisticsArrowUpView?.apply {
visibility = View.VISIBLE
}
statisticsRootView?.apply {
isClickable = true
}
}
@SuppressLint("DefaultLocale")
fun updateSizeFormat(size: Long): String {
return if (size < NUM) {
size.toString() + "B"
} else if (size < NUM * NUM) {
String.format("%.1f", (size / DECIMAL_NUM)) + " KB"
} else if (size < NUM * NUM * NUM) {
String.format("%.1f", (size / NUM / DECIMAL_NUM)) + " MB"
} else {
String.format("%.1f", (size / NUM / NUM / DECIMAL_NUM)) + " GB"
}
}
private fun updateData(fragmentType: Int) {
val fragment = getCurrentFragment()
fragment?.mFragmentType = fragmentType
when (fragmentType) {
Constants.TAB_ALL -> fragment?.setData(allFiles)
Constants.TAB_IMAGE -> fragment?.setData(imageFiles)
Constants.TAB_VIDEO -> fragment?.setData(videoFiles)
Constants.TAB_AUDIO -> fragment?.setData(audioFiles)
Constants.TAB_DOCUMENT -> fragment?.setData(docFiles)
Constants.TAB_OTHER -> fragment?.setData(otherFiles)
}
fragment?.setSelectedData(mSelectArrayByID)
Log.d(
TAG,
"allFiles=${allFiles.size}, imageFiles=${imageFiles.size}, videoFiles=${videoFiles.size}, " +
"audioFiles=${audioFiles.size}, docFiles=${docFiles.size}, otherFiles=${otherFiles.size}"
)
}
override fun onTabSelected(tab: COUITab?) {
Log.d(TAG, "onTabSelected tab.postion=${tab?.position}")
tab?.let {
mPosition = it.position
if (loadingController?.isShowing() != true) {
updateData(mTabTitles[mPosition])
}
}
}
override fun onTabUnselected(p0: COUITab?) {}
override fun onTabReselected(p0: COUITab?) {}
private fun getCurrentFragment(): AddFileListFragment? {
return if (mPosition < mPages.size) {
mPages[mPosition]
} else {
null
}
}
inner class ViewPagerFragmentStateAdapter(fragment: Fragment) : BaseFragmentAdapter(fragment) {
override fun getItemCount(): Int {
return mTabTitle.size
}
override fun createFragment(position: Int): Fragment {
return mPages[position]
}
override fun getPageTitle(position: Int): CharSequence {
return mTabTitle[position]
}
}
override fun onAgreeResult(agree: Boolean, noLongerRemind: Boolean) {
loadData()
}
}
interface AddFileDialogInterface {
fun dismissAddFileDialog()
fun replaceSelectedPanelFragment(selectData: MutableList<AddFileBean>)
}这是对应的kotlin代码,怎么处理
最新发布