diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt index 23ed09d..df03b14 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt @@ -3,6 +3,10 @@ import com.casic.birmm.inspect.model.* import com.casic.birmm.inspect.utils.AuthenticationHelper import com.casic.birmm.inspect.utils.Constant +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File object RetrofitServiceManager { @@ -88,4 +92,13 @@ suspend fun searchByInspection(inspectionId: String): TaskRecordModel { return api.searchByInspection(AuthenticationHelper.token!!, inspectionId) } + + /** + * 上传图片 + */ + suspend fun uploadImage(image: File): ActionResultModel { + val requestBody = RequestBody.create("image/png".toMediaTypeOrNull(), image) + val imagePart = MultipartBody.Part.createFormData("file", image.name, requestBody) + return api.uploadImage(AuthenticationHelper.token!!, imagePart) + } } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt index 23ed09d..df03b14 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt @@ -3,6 +3,10 @@ import com.casic.birmm.inspect.model.* import com.casic.birmm.inspect.utils.AuthenticationHelper import com.casic.birmm.inspect.utils.Constant +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File object RetrofitServiceManager { @@ -88,4 +92,13 @@ suspend fun searchByInspection(inspectionId: String): TaskRecordModel { return api.searchByInspection(AuthenticationHelper.token!!, inspectionId) } + + /** + * 上传图片 + */ + suspend fun uploadImage(image: File): ActionResultModel { + val requestBody = RequestBody.create("image/png".toMediaTypeOrNull(), image) + val imagePart = MultipartBody.Part.createFormData("file", image.name, requestBody) + return api.uploadImage(AuthenticationHelper.token!!, imagePart) + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt index 9b29ca3..fe37dc3 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt @@ -3,9 +3,8 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.GridLayoutManager import com.casic.birmm.inspect.R -import com.casic.birmm.inspect.adapter.ImageRecycleViewAdapter +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter import com.casic.birmm.inspect.base.BaseActivity import com.casic.birmm.inspect.extensions.combineImagePath import com.casic.birmm.inspect.extensions.show @@ -54,19 +53,17 @@ } } //绑定图片 - val imageAdapter = ImageRecycleViewAdapter(this, urls) - imageRecyclerView.layoutManager = GridLayoutManager(this, 2) - imageRecyclerView.adapter = imageAdapter - imageAdapter.setOnItemClickListener(object : - ImageRecycleViewAdapter.OnItemClickListener { - override fun onClick(position: Int) { - if (urls[position].isEmpty()) { - "图片加载失败,无法查看大图".show(this@EventDetailActivity) - } else { - OtherUtils.showBigImage(this@EventDetailActivity, position, urls) - } + val imageAdapter = ImageGridViewAdapter(this) + imageAdapter.setImageList(imageUrls = urls) + imageAdapter.isDeleteVisible(false) + imageGridView.adapter = imageAdapter + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (urls[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@EventDetailActivity) + } else { + OtherUtils.showBigImage(this@EventDetailActivity, position, urls) } - }) + } } else { hasImageLayout.visibility = View.GONE dataView.text = "$data.0" diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt index 23ed09d..df03b14 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt @@ -3,6 +3,10 @@ import com.casic.birmm.inspect.model.* import com.casic.birmm.inspect.utils.AuthenticationHelper import com.casic.birmm.inspect.utils.Constant +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File object RetrofitServiceManager { @@ -88,4 +92,13 @@ suspend fun searchByInspection(inspectionId: String): TaskRecordModel { return api.searchByInspection(AuthenticationHelper.token!!, inspectionId) } + + /** + * 上传图片 + */ + suspend fun uploadImage(image: File): ActionResultModel { + val requestBody = RequestBody.create("image/png".toMediaTypeOrNull(), image) + val imagePart = MultipartBody.Part.createFormData("file", image.name, requestBody) + return api.uploadImage(AuthenticationHelper.token!!, imagePart) + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt index 9b29ca3..fe37dc3 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt @@ -3,9 +3,8 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.GridLayoutManager import com.casic.birmm.inspect.R -import com.casic.birmm.inspect.adapter.ImageRecycleViewAdapter +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter import com.casic.birmm.inspect.base.BaseActivity import com.casic.birmm.inspect.extensions.combineImagePath import com.casic.birmm.inspect.extensions.show @@ -54,19 +53,17 @@ } } //绑定图片 - val imageAdapter = ImageRecycleViewAdapter(this, urls) - imageRecyclerView.layoutManager = GridLayoutManager(this, 2) - imageRecyclerView.adapter = imageAdapter - imageAdapter.setOnItemClickListener(object : - ImageRecycleViewAdapter.OnItemClickListener { - override fun onClick(position: Int) { - if (urls[position].isEmpty()) { - "图片加载失败,无法查看大图".show(this@EventDetailActivity) - } else { - OtherUtils.showBigImage(this@EventDetailActivity, position, urls) - } + val imageAdapter = ImageGridViewAdapter(this) + imageAdapter.setImageList(imageUrls = urls) + imageAdapter.isDeleteVisible(false) + imageGridView.adapter = imageAdapter + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (urls[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@EventDetailActivity) + } else { + OtherUtils.showBigImage(this@EventDetailActivity, position, urls) } - }) + } } else { hasImageLayout.visibility = View.GONE dataView.text = "$data.0" diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt index 207f6c3..91fb674 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.view import android.bluetooth.BluetoothAdapter +import android.content.Intent import android.graphics.Color import android.os.Bundle import android.os.Handler @@ -18,6 +19,7 @@ import com.casic.birmm.inspect.utils.PageNavigationManager import com.casic.birmm.inspect.utils.StatusBarColorUtil import com.casic.birmm.inspect.widgets.InputDialog +import com.casic.birmm.inspect.widgets.SingleChoiceDialog import com.gyf.immersionbar.ImmersionBar import com.qmuiteam.qmui.util.QMUIStatusBarHelper import kotlinx.android.synthetic.main.activity_inspect_route.mapView @@ -42,6 +44,7 @@ private lateinit var aMap: AMap private lateinit var locationStyle: MyLocationStyle + private val itemList: List = arrayListOf("报警事件", "自定义事件") init { weakReferenceHandler = WeakReferenceHandler(this) @@ -131,7 +134,25 @@ newEventButton.setChangeAlphaWhenPress(true) newEventButton.setOnClickListener { - + SingleChoiceDialog.Builder() + .setContext(this) + .setTitle("选择事件类型") + .setChoiceItemButton(itemList) + .setOnDialogClickListener(object : SingleChoiceDialog.OnDialogItemClickListener { + override fun onItemClick(position: Int) { + val intent = Intent(this@MapActivity, NewEventActivity::class.java) + when (position) { + 0 -> { + intent.putExtra("isWarning", true) + } + 1 -> { + intent.putExtra("isWarning", false) + } + } + startActivity(intent) + } + }) + .build().show() } } diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt index 23ed09d..df03b14 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt @@ -3,6 +3,10 @@ import com.casic.birmm.inspect.model.* import com.casic.birmm.inspect.utils.AuthenticationHelper import com.casic.birmm.inspect.utils.Constant +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File object RetrofitServiceManager { @@ -88,4 +92,13 @@ suspend fun searchByInspection(inspectionId: String): TaskRecordModel { return api.searchByInspection(AuthenticationHelper.token!!, inspectionId) } + + /** + * 上传图片 + */ + suspend fun uploadImage(image: File): ActionResultModel { + val requestBody = RequestBody.create("image/png".toMediaTypeOrNull(), image) + val imagePart = MultipartBody.Part.createFormData("file", image.name, requestBody) + return api.uploadImage(AuthenticationHelper.token!!, imagePart) + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt index 9b29ca3..fe37dc3 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt @@ -3,9 +3,8 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.GridLayoutManager import com.casic.birmm.inspect.R -import com.casic.birmm.inspect.adapter.ImageRecycleViewAdapter +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter import com.casic.birmm.inspect.base.BaseActivity import com.casic.birmm.inspect.extensions.combineImagePath import com.casic.birmm.inspect.extensions.show @@ -54,19 +53,17 @@ } } //绑定图片 - val imageAdapter = ImageRecycleViewAdapter(this, urls) - imageRecyclerView.layoutManager = GridLayoutManager(this, 2) - imageRecyclerView.adapter = imageAdapter - imageAdapter.setOnItemClickListener(object : - ImageRecycleViewAdapter.OnItemClickListener { - override fun onClick(position: Int) { - if (urls[position].isEmpty()) { - "图片加载失败,无法查看大图".show(this@EventDetailActivity) - } else { - OtherUtils.showBigImage(this@EventDetailActivity, position, urls) - } + val imageAdapter = ImageGridViewAdapter(this) + imageAdapter.setImageList(imageUrls = urls) + imageAdapter.isDeleteVisible(false) + imageGridView.adapter = imageAdapter + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (urls[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@EventDetailActivity) + } else { + OtherUtils.showBigImage(this@EventDetailActivity, position, urls) } - }) + } } else { hasImageLayout.visibility = View.GONE dataView.text = "$data.0" diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt index 207f6c3..91fb674 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.view import android.bluetooth.BluetoothAdapter +import android.content.Intent import android.graphics.Color import android.os.Bundle import android.os.Handler @@ -18,6 +19,7 @@ import com.casic.birmm.inspect.utils.PageNavigationManager import com.casic.birmm.inspect.utils.StatusBarColorUtil import com.casic.birmm.inspect.widgets.InputDialog +import com.casic.birmm.inspect.widgets.SingleChoiceDialog import com.gyf.immersionbar.ImmersionBar import com.qmuiteam.qmui.util.QMUIStatusBarHelper import kotlinx.android.synthetic.main.activity_inspect_route.mapView @@ -42,6 +44,7 @@ private lateinit var aMap: AMap private lateinit var locationStyle: MyLocationStyle + private val itemList: List = arrayListOf("报警事件", "自定义事件") init { weakReferenceHandler = WeakReferenceHandler(this) @@ -131,7 +134,25 @@ newEventButton.setChangeAlphaWhenPress(true) newEventButton.setOnClickListener { - + SingleChoiceDialog.Builder() + .setContext(this) + .setTitle("选择事件类型") + .setChoiceItemButton(itemList) + .setOnDialogClickListener(object : SingleChoiceDialog.OnDialogItemClickListener { + override fun onItemClick(position: Int) { + val intent = Intent(this@MapActivity, NewEventActivity::class.java) + when (position) { + 0 -> { + intent.putExtra("isWarning", true) + } + 1 -> { + intent.putExtra("isWarning", false) + } + } + startActivity(intent) + } + }) + .build().show() } } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt new file mode 100644 index 0000000..de3eb19 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt @@ -0,0 +1,191 @@ +package com.casic.birmm.inspect.view + +import android.app.Activity +import android.content.Intent +import android.view.View +import androidx.core.content.ContextCompat +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.aihook.alertview.library.AlertView +import com.aihook.alertview.library.OnItemClickListener +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseViewModelActivity +import com.casic.birmm.inspect.extensions.combineImagePath +import com.casic.birmm.inspect.extensions.filterString +import com.casic.birmm.inspect.extensions.show +import com.casic.birmm.inspect.utils.* +import com.casic.birmm.inspect.vm.NewEventViewModel +import com.casic.birmm.inspect.vm.UploadImageViewModel +import com.gyf.immersionbar.ImmersionBar +import com.luck.picture.lib.PictureSelector +import com.luck.picture.lib.config.PictureConfig +import com.luck.picture.lib.config.PictureMimeType +import kotlinx.android.synthetic.main.activity_new_event.* +import kotlinx.android.synthetic.main.include_base_title.* +import java.io.File + + +class NewEventActivity : BaseViewModelActivity() { + + private lateinit var uploadImageViewModel: UploadImageViewModel + private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var imageAdapter: ImageGridViewAdapter + private var isWarning: Boolean = true + + override fun createViewModelByClass(): Class? = NewEventViewModel::class.java + + override fun initLayoutView(): Int = R.layout.activity_new_event + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + } + + override fun initData() { + uploadImageViewModel = ViewModelProvider(this).get(UploadImageViewModel::class.java) + isWarning = intent.getBooleanExtra("isWarning", true) + if (isWarning) { + titleView.text = "报警事件记录" + inspectCardView.visibility = View.VISIBLE + } else { + titleView.text = "自定义事件记录" + inspectCardView.visibility = View.GONE + } + eventCreateTimeView.text = + TimeOrDateUtil.timestampToCompleteDate(System.currentTimeMillis()) + + //初始化图片九宫格 + imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + } + + override fun initEvent() { + leftBackView.setOnClickListener { this.finish() } + + addImageView.setOnClickListener { + AlertView( + "请选择图片来源", null, "取消", null, arrayOf("拍照", "相册"), + this, AlertView.Style.ActionSheet, + OnItemClickListener { _, position -> + when (position) { + 0 -> { + PictureSelector.create(this) + .openCamera(PictureMimeType.ofImage()) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .forResult(PictureConfig.REQUEST_CAMERA) + } + 1 -> { + PictureSelector.create(this) + .openGallery(PictureMimeType.ofImage()) + .isWeChatStyle(true) + .isCamera(false) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .maxSelectNum(4) + .forResult(PictureConfig.CHOOSE_REQUEST) + } + } + } + ).setCancelable(true).show() + } + uploadImageViewModel.resultModel.observe(this, Observer { model -> + if (model.code == 200) { + /** + * 显示图片 + * path: 2021-07\c670eac17d644b179a4324a34bb84329.jpeg + * */ + imageGridView.visibility = View.VISIBLE + val sumItemCount: Int = imageAdapter.count + 1 //每上传一张图片,图片总数都是在原有的基础上+1 + if (sumItemCount <= 4) { + val url = model.data + //let函数处理需要针对一个可null的对象统一做判空处理。 + url?.let { + imagePaths.add(it) + realPaths.add(it.combineImagePath()) + } + if (realPaths.size == 4) { + addImageView.visibility = View.GONE + } + imageAdapter.setImageList(imageUrls = realPaths) + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@NewEventActivity) + } else { + OtherUtils.showBigImage(this@NewEventActivity, position, realPaths) + } + } + //删除按钮点击事件 + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + @Override + override fun onDeleteItemClick(position: Int) { + imagePaths.removeAt(position) + realPaths.removeAt(position) + imageAdapter.setImageList(imageUrls = realPaths) + if (realPaths.size != 2) { + addImageView.visibility = View.VISIBLE + } + } + }) + } else { + "最多只能上传4张图片".show(this) + } + } + }) + uploadImageViewModel.loadState.observe(this, Observer { + when (it) { + is LoadState.Loading -> { + OtherUtils.showLoadingDialog(this, "图片上传中,请稍后...") + } + else -> OtherUtils.dismissLoadingDialog() + } + }) + + addEventButton.setOnClickListener { + if (eventEditTextView.text.toString().filterString().isEmpty()) { + "事件情况说明还未填写,请检查".show(this) + return@setOnClickListener + } + if (isWarning) { + if (inspectNumberView.text.toString().filterString().isEmpty()) { + "最大泄露值还未填写,请检查".show(this) + return@setOnClickListener + } + } + + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + PictureConfig.CHOOSE_REQUEST -> { + val selectResult = PictureSelector.obtainMultipleResult(data) + for (res in selectResult) { + val file = File(res.compressPath) + if (file.length() <= Constant.IMAGE_MINUS_SIZE) { + "图片尺寸太小,请重新选择".show(this) + continue + } + //上传图片 + uploadImageViewModel.uploadImage(file) + } + } + PictureConfig.REQUEST_CAMERA -> { + val cameraResult = PictureSelector.obtainMultipleResult(data)[0] + //上传图片 + uploadImageViewModel.uploadImage(File(cameraResult.compressPath)) + } + } + } + } +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt index 23ed09d..df03b14 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt @@ -3,6 +3,10 @@ import com.casic.birmm.inspect.model.* import com.casic.birmm.inspect.utils.AuthenticationHelper import com.casic.birmm.inspect.utils.Constant +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File object RetrofitServiceManager { @@ -88,4 +92,13 @@ suspend fun searchByInspection(inspectionId: String): TaskRecordModel { return api.searchByInspection(AuthenticationHelper.token!!, inspectionId) } + + /** + * 上传图片 + */ + suspend fun uploadImage(image: File): ActionResultModel { + val requestBody = RequestBody.create("image/png".toMediaTypeOrNull(), image) + val imagePart = MultipartBody.Part.createFormData("file", image.name, requestBody) + return api.uploadImage(AuthenticationHelper.token!!, imagePart) + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt index 9b29ca3..fe37dc3 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt @@ -3,9 +3,8 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.GridLayoutManager import com.casic.birmm.inspect.R -import com.casic.birmm.inspect.adapter.ImageRecycleViewAdapter +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter import com.casic.birmm.inspect.base.BaseActivity import com.casic.birmm.inspect.extensions.combineImagePath import com.casic.birmm.inspect.extensions.show @@ -54,19 +53,17 @@ } } //绑定图片 - val imageAdapter = ImageRecycleViewAdapter(this, urls) - imageRecyclerView.layoutManager = GridLayoutManager(this, 2) - imageRecyclerView.adapter = imageAdapter - imageAdapter.setOnItemClickListener(object : - ImageRecycleViewAdapter.OnItemClickListener { - override fun onClick(position: Int) { - if (urls[position].isEmpty()) { - "图片加载失败,无法查看大图".show(this@EventDetailActivity) - } else { - OtherUtils.showBigImage(this@EventDetailActivity, position, urls) - } + val imageAdapter = ImageGridViewAdapter(this) + imageAdapter.setImageList(imageUrls = urls) + imageAdapter.isDeleteVisible(false) + imageGridView.adapter = imageAdapter + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (urls[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@EventDetailActivity) + } else { + OtherUtils.showBigImage(this@EventDetailActivity, position, urls) } - }) + } } else { hasImageLayout.visibility = View.GONE dataView.text = "$data.0" diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt index 207f6c3..91fb674 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.view import android.bluetooth.BluetoothAdapter +import android.content.Intent import android.graphics.Color import android.os.Bundle import android.os.Handler @@ -18,6 +19,7 @@ import com.casic.birmm.inspect.utils.PageNavigationManager import com.casic.birmm.inspect.utils.StatusBarColorUtil import com.casic.birmm.inspect.widgets.InputDialog +import com.casic.birmm.inspect.widgets.SingleChoiceDialog import com.gyf.immersionbar.ImmersionBar import com.qmuiteam.qmui.util.QMUIStatusBarHelper import kotlinx.android.synthetic.main.activity_inspect_route.mapView @@ -42,6 +44,7 @@ private lateinit var aMap: AMap private lateinit var locationStyle: MyLocationStyle + private val itemList: List = arrayListOf("报警事件", "自定义事件") init { weakReferenceHandler = WeakReferenceHandler(this) @@ -131,7 +134,25 @@ newEventButton.setChangeAlphaWhenPress(true) newEventButton.setOnClickListener { - + SingleChoiceDialog.Builder() + .setContext(this) + .setTitle("选择事件类型") + .setChoiceItemButton(itemList) + .setOnDialogClickListener(object : SingleChoiceDialog.OnDialogItemClickListener { + override fun onItemClick(position: Int) { + val intent = Intent(this@MapActivity, NewEventActivity::class.java) + when (position) { + 0 -> { + intent.putExtra("isWarning", true) + } + 1 -> { + intent.putExtra("isWarning", false) + } + } + startActivity(intent) + } + }) + .build().show() } } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt new file mode 100644 index 0000000..de3eb19 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt @@ -0,0 +1,191 @@ +package com.casic.birmm.inspect.view + +import android.app.Activity +import android.content.Intent +import android.view.View +import androidx.core.content.ContextCompat +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.aihook.alertview.library.AlertView +import com.aihook.alertview.library.OnItemClickListener +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseViewModelActivity +import com.casic.birmm.inspect.extensions.combineImagePath +import com.casic.birmm.inspect.extensions.filterString +import com.casic.birmm.inspect.extensions.show +import com.casic.birmm.inspect.utils.* +import com.casic.birmm.inspect.vm.NewEventViewModel +import com.casic.birmm.inspect.vm.UploadImageViewModel +import com.gyf.immersionbar.ImmersionBar +import com.luck.picture.lib.PictureSelector +import com.luck.picture.lib.config.PictureConfig +import com.luck.picture.lib.config.PictureMimeType +import kotlinx.android.synthetic.main.activity_new_event.* +import kotlinx.android.synthetic.main.include_base_title.* +import java.io.File + + +class NewEventActivity : BaseViewModelActivity() { + + private lateinit var uploadImageViewModel: UploadImageViewModel + private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var imageAdapter: ImageGridViewAdapter + private var isWarning: Boolean = true + + override fun createViewModelByClass(): Class? = NewEventViewModel::class.java + + override fun initLayoutView(): Int = R.layout.activity_new_event + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + } + + override fun initData() { + uploadImageViewModel = ViewModelProvider(this).get(UploadImageViewModel::class.java) + isWarning = intent.getBooleanExtra("isWarning", true) + if (isWarning) { + titleView.text = "报警事件记录" + inspectCardView.visibility = View.VISIBLE + } else { + titleView.text = "自定义事件记录" + inspectCardView.visibility = View.GONE + } + eventCreateTimeView.text = + TimeOrDateUtil.timestampToCompleteDate(System.currentTimeMillis()) + + //初始化图片九宫格 + imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + } + + override fun initEvent() { + leftBackView.setOnClickListener { this.finish() } + + addImageView.setOnClickListener { + AlertView( + "请选择图片来源", null, "取消", null, arrayOf("拍照", "相册"), + this, AlertView.Style.ActionSheet, + OnItemClickListener { _, position -> + when (position) { + 0 -> { + PictureSelector.create(this) + .openCamera(PictureMimeType.ofImage()) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .forResult(PictureConfig.REQUEST_CAMERA) + } + 1 -> { + PictureSelector.create(this) + .openGallery(PictureMimeType.ofImage()) + .isWeChatStyle(true) + .isCamera(false) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .maxSelectNum(4) + .forResult(PictureConfig.CHOOSE_REQUEST) + } + } + } + ).setCancelable(true).show() + } + uploadImageViewModel.resultModel.observe(this, Observer { model -> + if (model.code == 200) { + /** + * 显示图片 + * path: 2021-07\c670eac17d644b179a4324a34bb84329.jpeg + * */ + imageGridView.visibility = View.VISIBLE + val sumItemCount: Int = imageAdapter.count + 1 //每上传一张图片,图片总数都是在原有的基础上+1 + if (sumItemCount <= 4) { + val url = model.data + //let函数处理需要针对一个可null的对象统一做判空处理。 + url?.let { + imagePaths.add(it) + realPaths.add(it.combineImagePath()) + } + if (realPaths.size == 4) { + addImageView.visibility = View.GONE + } + imageAdapter.setImageList(imageUrls = realPaths) + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@NewEventActivity) + } else { + OtherUtils.showBigImage(this@NewEventActivity, position, realPaths) + } + } + //删除按钮点击事件 + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + @Override + override fun onDeleteItemClick(position: Int) { + imagePaths.removeAt(position) + realPaths.removeAt(position) + imageAdapter.setImageList(imageUrls = realPaths) + if (realPaths.size != 2) { + addImageView.visibility = View.VISIBLE + } + } + }) + } else { + "最多只能上传4张图片".show(this) + } + } + }) + uploadImageViewModel.loadState.observe(this, Observer { + when (it) { + is LoadState.Loading -> { + OtherUtils.showLoadingDialog(this, "图片上传中,请稍后...") + } + else -> OtherUtils.dismissLoadingDialog() + } + }) + + addEventButton.setOnClickListener { + if (eventEditTextView.text.toString().filterString().isEmpty()) { + "事件情况说明还未填写,请检查".show(this) + return@setOnClickListener + } + if (isWarning) { + if (inspectNumberView.text.toString().filterString().isEmpty()) { + "最大泄露值还未填写,请检查".show(this) + return@setOnClickListener + } + } + + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + PictureConfig.CHOOSE_REQUEST -> { + val selectResult = PictureSelector.obtainMultipleResult(data) + for (res in selectResult) { + val file = File(res.compressPath) + if (file.length() <= Constant.IMAGE_MINUS_SIZE) { + "图片尺寸太小,请重新选择".show(this) + continue + } + //上传图片 + uploadImageViewModel.uploadImage(file) + } + } + PictureConfig.REQUEST_CAMERA -> { + val cameraResult = PictureSelector.obtainMultipleResult(data)[0] + //上传图片 + uploadImageViewModel.uploadImage(File(cameraResult.compressPath)) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt index d4821de..9de8a96 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt @@ -32,6 +32,7 @@ } private fun startGuideActivity() { +// startActivity(Intent(this, TestActivity::class.java)) startActivity(Intent(this, GuideActivity::class.java)) finish() } diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt index 23ed09d..df03b14 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt @@ -3,6 +3,10 @@ import com.casic.birmm.inspect.model.* import com.casic.birmm.inspect.utils.AuthenticationHelper import com.casic.birmm.inspect.utils.Constant +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File object RetrofitServiceManager { @@ -88,4 +92,13 @@ suspend fun searchByInspection(inspectionId: String): TaskRecordModel { return api.searchByInspection(AuthenticationHelper.token!!, inspectionId) } + + /** + * 上传图片 + */ + suspend fun uploadImage(image: File): ActionResultModel { + val requestBody = RequestBody.create("image/png".toMediaTypeOrNull(), image) + val imagePart = MultipartBody.Part.createFormData("file", image.name, requestBody) + return api.uploadImage(AuthenticationHelper.token!!, imagePart) + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt index 9b29ca3..fe37dc3 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt @@ -3,9 +3,8 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.GridLayoutManager import com.casic.birmm.inspect.R -import com.casic.birmm.inspect.adapter.ImageRecycleViewAdapter +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter import com.casic.birmm.inspect.base.BaseActivity import com.casic.birmm.inspect.extensions.combineImagePath import com.casic.birmm.inspect.extensions.show @@ -54,19 +53,17 @@ } } //绑定图片 - val imageAdapter = ImageRecycleViewAdapter(this, urls) - imageRecyclerView.layoutManager = GridLayoutManager(this, 2) - imageRecyclerView.adapter = imageAdapter - imageAdapter.setOnItemClickListener(object : - ImageRecycleViewAdapter.OnItemClickListener { - override fun onClick(position: Int) { - if (urls[position].isEmpty()) { - "图片加载失败,无法查看大图".show(this@EventDetailActivity) - } else { - OtherUtils.showBigImage(this@EventDetailActivity, position, urls) - } + val imageAdapter = ImageGridViewAdapter(this) + imageAdapter.setImageList(imageUrls = urls) + imageAdapter.isDeleteVisible(false) + imageGridView.adapter = imageAdapter + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (urls[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@EventDetailActivity) + } else { + OtherUtils.showBigImage(this@EventDetailActivity, position, urls) } - }) + } } else { hasImageLayout.visibility = View.GONE dataView.text = "$data.0" diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt index 207f6c3..91fb674 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.view import android.bluetooth.BluetoothAdapter +import android.content.Intent import android.graphics.Color import android.os.Bundle import android.os.Handler @@ -18,6 +19,7 @@ import com.casic.birmm.inspect.utils.PageNavigationManager import com.casic.birmm.inspect.utils.StatusBarColorUtil import com.casic.birmm.inspect.widgets.InputDialog +import com.casic.birmm.inspect.widgets.SingleChoiceDialog import com.gyf.immersionbar.ImmersionBar import com.qmuiteam.qmui.util.QMUIStatusBarHelper import kotlinx.android.synthetic.main.activity_inspect_route.mapView @@ -42,6 +44,7 @@ private lateinit var aMap: AMap private lateinit var locationStyle: MyLocationStyle + private val itemList: List = arrayListOf("报警事件", "自定义事件") init { weakReferenceHandler = WeakReferenceHandler(this) @@ -131,7 +134,25 @@ newEventButton.setChangeAlphaWhenPress(true) newEventButton.setOnClickListener { - + SingleChoiceDialog.Builder() + .setContext(this) + .setTitle("选择事件类型") + .setChoiceItemButton(itemList) + .setOnDialogClickListener(object : SingleChoiceDialog.OnDialogItemClickListener { + override fun onItemClick(position: Int) { + val intent = Intent(this@MapActivity, NewEventActivity::class.java) + when (position) { + 0 -> { + intent.putExtra("isWarning", true) + } + 1 -> { + intent.putExtra("isWarning", false) + } + } + startActivity(intent) + } + }) + .build().show() } } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt new file mode 100644 index 0000000..de3eb19 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt @@ -0,0 +1,191 @@ +package com.casic.birmm.inspect.view + +import android.app.Activity +import android.content.Intent +import android.view.View +import androidx.core.content.ContextCompat +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.aihook.alertview.library.AlertView +import com.aihook.alertview.library.OnItemClickListener +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseViewModelActivity +import com.casic.birmm.inspect.extensions.combineImagePath +import com.casic.birmm.inspect.extensions.filterString +import com.casic.birmm.inspect.extensions.show +import com.casic.birmm.inspect.utils.* +import com.casic.birmm.inspect.vm.NewEventViewModel +import com.casic.birmm.inspect.vm.UploadImageViewModel +import com.gyf.immersionbar.ImmersionBar +import com.luck.picture.lib.PictureSelector +import com.luck.picture.lib.config.PictureConfig +import com.luck.picture.lib.config.PictureMimeType +import kotlinx.android.synthetic.main.activity_new_event.* +import kotlinx.android.synthetic.main.include_base_title.* +import java.io.File + + +class NewEventActivity : BaseViewModelActivity() { + + private lateinit var uploadImageViewModel: UploadImageViewModel + private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var imageAdapter: ImageGridViewAdapter + private var isWarning: Boolean = true + + override fun createViewModelByClass(): Class? = NewEventViewModel::class.java + + override fun initLayoutView(): Int = R.layout.activity_new_event + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + } + + override fun initData() { + uploadImageViewModel = ViewModelProvider(this).get(UploadImageViewModel::class.java) + isWarning = intent.getBooleanExtra("isWarning", true) + if (isWarning) { + titleView.text = "报警事件记录" + inspectCardView.visibility = View.VISIBLE + } else { + titleView.text = "自定义事件记录" + inspectCardView.visibility = View.GONE + } + eventCreateTimeView.text = + TimeOrDateUtil.timestampToCompleteDate(System.currentTimeMillis()) + + //初始化图片九宫格 + imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + } + + override fun initEvent() { + leftBackView.setOnClickListener { this.finish() } + + addImageView.setOnClickListener { + AlertView( + "请选择图片来源", null, "取消", null, arrayOf("拍照", "相册"), + this, AlertView.Style.ActionSheet, + OnItemClickListener { _, position -> + when (position) { + 0 -> { + PictureSelector.create(this) + .openCamera(PictureMimeType.ofImage()) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .forResult(PictureConfig.REQUEST_CAMERA) + } + 1 -> { + PictureSelector.create(this) + .openGallery(PictureMimeType.ofImage()) + .isWeChatStyle(true) + .isCamera(false) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .maxSelectNum(4) + .forResult(PictureConfig.CHOOSE_REQUEST) + } + } + } + ).setCancelable(true).show() + } + uploadImageViewModel.resultModel.observe(this, Observer { model -> + if (model.code == 200) { + /** + * 显示图片 + * path: 2021-07\c670eac17d644b179a4324a34bb84329.jpeg + * */ + imageGridView.visibility = View.VISIBLE + val sumItemCount: Int = imageAdapter.count + 1 //每上传一张图片,图片总数都是在原有的基础上+1 + if (sumItemCount <= 4) { + val url = model.data + //let函数处理需要针对一个可null的对象统一做判空处理。 + url?.let { + imagePaths.add(it) + realPaths.add(it.combineImagePath()) + } + if (realPaths.size == 4) { + addImageView.visibility = View.GONE + } + imageAdapter.setImageList(imageUrls = realPaths) + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@NewEventActivity) + } else { + OtherUtils.showBigImage(this@NewEventActivity, position, realPaths) + } + } + //删除按钮点击事件 + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + @Override + override fun onDeleteItemClick(position: Int) { + imagePaths.removeAt(position) + realPaths.removeAt(position) + imageAdapter.setImageList(imageUrls = realPaths) + if (realPaths.size != 2) { + addImageView.visibility = View.VISIBLE + } + } + }) + } else { + "最多只能上传4张图片".show(this) + } + } + }) + uploadImageViewModel.loadState.observe(this, Observer { + when (it) { + is LoadState.Loading -> { + OtherUtils.showLoadingDialog(this, "图片上传中,请稍后...") + } + else -> OtherUtils.dismissLoadingDialog() + } + }) + + addEventButton.setOnClickListener { + if (eventEditTextView.text.toString().filterString().isEmpty()) { + "事件情况说明还未填写,请检查".show(this) + return@setOnClickListener + } + if (isWarning) { + if (inspectNumberView.text.toString().filterString().isEmpty()) { + "最大泄露值还未填写,请检查".show(this) + return@setOnClickListener + } + } + + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + PictureConfig.CHOOSE_REQUEST -> { + val selectResult = PictureSelector.obtainMultipleResult(data) + for (res in selectResult) { + val file = File(res.compressPath) + if (file.length() <= Constant.IMAGE_MINUS_SIZE) { + "图片尺寸太小,请重新选择".show(this) + continue + } + //上传图片 + uploadImageViewModel.uploadImage(file) + } + } + PictureConfig.REQUEST_CAMERA -> { + val cameraResult = PictureSelector.obtainMultipleResult(data)[0] + //上传图片 + uploadImageViewModel.uploadImage(File(cameraResult.compressPath)) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt index d4821de..9de8a96 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt @@ -32,6 +32,7 @@ } private fun startGuideActivity() { +// startActivity(Intent(this, TestActivity::class.java)) startActivity(Intent(this, GuideActivity::class.java)) finish() } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt new file mode 100644 index 0000000..abb6e23 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt @@ -0,0 +1,54 @@ +package com.casic.birmm.inspect.view + +import android.util.Log +import androidx.core.content.ContextCompat +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseActivity +import com.casic.birmm.inspect.utils.PageNavigationManager +import com.casic.birmm.inspect.utils.StatusBarColorUtil +import com.gyf.immersionbar.ImmersionBar +import kotlinx.android.synthetic.main.activity_test.* +import kotlinx.android.synthetic.main.include_base_title.* + +class TestActivity : BaseActivity() { + + companion object { + private const val Tag = "TestActivity" + } + + private val urls = arrayListOf( + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg" + ) + + override fun initLayoutView(): Int = R.layout.activity_test + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + titleView.text = "测试功能页面" + } + + override fun initData() { + val imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + imageAdapter.setImageList(imageUrls = urls) + imageGridView.setOnItemClickListener { _, _, position, _ -> + Log.d(Tag, "点击path: ${urls[position]}") + } + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + override fun onDeleteItemClick(position: Int) { + Log.d(Tag, "删除path: ${urls[position]}") + } + }) + } + + override fun initEvent() { + + } +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt index 23ed09d..df03b14 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt @@ -3,6 +3,10 @@ import com.casic.birmm.inspect.model.* import com.casic.birmm.inspect.utils.AuthenticationHelper import com.casic.birmm.inspect.utils.Constant +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File object RetrofitServiceManager { @@ -88,4 +92,13 @@ suspend fun searchByInspection(inspectionId: String): TaskRecordModel { return api.searchByInspection(AuthenticationHelper.token!!, inspectionId) } + + /** + * 上传图片 + */ + suspend fun uploadImage(image: File): ActionResultModel { + val requestBody = RequestBody.create("image/png".toMediaTypeOrNull(), image) + val imagePart = MultipartBody.Part.createFormData("file", image.name, requestBody) + return api.uploadImage(AuthenticationHelper.token!!, imagePart) + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt index 9b29ca3..fe37dc3 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt @@ -3,9 +3,8 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.GridLayoutManager import com.casic.birmm.inspect.R -import com.casic.birmm.inspect.adapter.ImageRecycleViewAdapter +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter import com.casic.birmm.inspect.base.BaseActivity import com.casic.birmm.inspect.extensions.combineImagePath import com.casic.birmm.inspect.extensions.show @@ -54,19 +53,17 @@ } } //绑定图片 - val imageAdapter = ImageRecycleViewAdapter(this, urls) - imageRecyclerView.layoutManager = GridLayoutManager(this, 2) - imageRecyclerView.adapter = imageAdapter - imageAdapter.setOnItemClickListener(object : - ImageRecycleViewAdapter.OnItemClickListener { - override fun onClick(position: Int) { - if (urls[position].isEmpty()) { - "图片加载失败,无法查看大图".show(this@EventDetailActivity) - } else { - OtherUtils.showBigImage(this@EventDetailActivity, position, urls) - } + val imageAdapter = ImageGridViewAdapter(this) + imageAdapter.setImageList(imageUrls = urls) + imageAdapter.isDeleteVisible(false) + imageGridView.adapter = imageAdapter + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (urls[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@EventDetailActivity) + } else { + OtherUtils.showBigImage(this@EventDetailActivity, position, urls) } - }) + } } else { hasImageLayout.visibility = View.GONE dataView.text = "$data.0" diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt index 207f6c3..91fb674 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.view import android.bluetooth.BluetoothAdapter +import android.content.Intent import android.graphics.Color import android.os.Bundle import android.os.Handler @@ -18,6 +19,7 @@ import com.casic.birmm.inspect.utils.PageNavigationManager import com.casic.birmm.inspect.utils.StatusBarColorUtil import com.casic.birmm.inspect.widgets.InputDialog +import com.casic.birmm.inspect.widgets.SingleChoiceDialog import com.gyf.immersionbar.ImmersionBar import com.qmuiteam.qmui.util.QMUIStatusBarHelper import kotlinx.android.synthetic.main.activity_inspect_route.mapView @@ -42,6 +44,7 @@ private lateinit var aMap: AMap private lateinit var locationStyle: MyLocationStyle + private val itemList: List = arrayListOf("报警事件", "自定义事件") init { weakReferenceHandler = WeakReferenceHandler(this) @@ -131,7 +134,25 @@ newEventButton.setChangeAlphaWhenPress(true) newEventButton.setOnClickListener { - + SingleChoiceDialog.Builder() + .setContext(this) + .setTitle("选择事件类型") + .setChoiceItemButton(itemList) + .setOnDialogClickListener(object : SingleChoiceDialog.OnDialogItemClickListener { + override fun onItemClick(position: Int) { + val intent = Intent(this@MapActivity, NewEventActivity::class.java) + when (position) { + 0 -> { + intent.putExtra("isWarning", true) + } + 1 -> { + intent.putExtra("isWarning", false) + } + } + startActivity(intent) + } + }) + .build().show() } } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt new file mode 100644 index 0000000..de3eb19 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt @@ -0,0 +1,191 @@ +package com.casic.birmm.inspect.view + +import android.app.Activity +import android.content.Intent +import android.view.View +import androidx.core.content.ContextCompat +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.aihook.alertview.library.AlertView +import com.aihook.alertview.library.OnItemClickListener +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseViewModelActivity +import com.casic.birmm.inspect.extensions.combineImagePath +import com.casic.birmm.inspect.extensions.filterString +import com.casic.birmm.inspect.extensions.show +import com.casic.birmm.inspect.utils.* +import com.casic.birmm.inspect.vm.NewEventViewModel +import com.casic.birmm.inspect.vm.UploadImageViewModel +import com.gyf.immersionbar.ImmersionBar +import com.luck.picture.lib.PictureSelector +import com.luck.picture.lib.config.PictureConfig +import com.luck.picture.lib.config.PictureMimeType +import kotlinx.android.synthetic.main.activity_new_event.* +import kotlinx.android.synthetic.main.include_base_title.* +import java.io.File + + +class NewEventActivity : BaseViewModelActivity() { + + private lateinit var uploadImageViewModel: UploadImageViewModel + private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var imageAdapter: ImageGridViewAdapter + private var isWarning: Boolean = true + + override fun createViewModelByClass(): Class? = NewEventViewModel::class.java + + override fun initLayoutView(): Int = R.layout.activity_new_event + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + } + + override fun initData() { + uploadImageViewModel = ViewModelProvider(this).get(UploadImageViewModel::class.java) + isWarning = intent.getBooleanExtra("isWarning", true) + if (isWarning) { + titleView.text = "报警事件记录" + inspectCardView.visibility = View.VISIBLE + } else { + titleView.text = "自定义事件记录" + inspectCardView.visibility = View.GONE + } + eventCreateTimeView.text = + TimeOrDateUtil.timestampToCompleteDate(System.currentTimeMillis()) + + //初始化图片九宫格 + imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + } + + override fun initEvent() { + leftBackView.setOnClickListener { this.finish() } + + addImageView.setOnClickListener { + AlertView( + "请选择图片来源", null, "取消", null, arrayOf("拍照", "相册"), + this, AlertView.Style.ActionSheet, + OnItemClickListener { _, position -> + when (position) { + 0 -> { + PictureSelector.create(this) + .openCamera(PictureMimeType.ofImage()) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .forResult(PictureConfig.REQUEST_CAMERA) + } + 1 -> { + PictureSelector.create(this) + .openGallery(PictureMimeType.ofImage()) + .isWeChatStyle(true) + .isCamera(false) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .maxSelectNum(4) + .forResult(PictureConfig.CHOOSE_REQUEST) + } + } + } + ).setCancelable(true).show() + } + uploadImageViewModel.resultModel.observe(this, Observer { model -> + if (model.code == 200) { + /** + * 显示图片 + * path: 2021-07\c670eac17d644b179a4324a34bb84329.jpeg + * */ + imageGridView.visibility = View.VISIBLE + val sumItemCount: Int = imageAdapter.count + 1 //每上传一张图片,图片总数都是在原有的基础上+1 + if (sumItemCount <= 4) { + val url = model.data + //let函数处理需要针对一个可null的对象统一做判空处理。 + url?.let { + imagePaths.add(it) + realPaths.add(it.combineImagePath()) + } + if (realPaths.size == 4) { + addImageView.visibility = View.GONE + } + imageAdapter.setImageList(imageUrls = realPaths) + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@NewEventActivity) + } else { + OtherUtils.showBigImage(this@NewEventActivity, position, realPaths) + } + } + //删除按钮点击事件 + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + @Override + override fun onDeleteItemClick(position: Int) { + imagePaths.removeAt(position) + realPaths.removeAt(position) + imageAdapter.setImageList(imageUrls = realPaths) + if (realPaths.size != 2) { + addImageView.visibility = View.VISIBLE + } + } + }) + } else { + "最多只能上传4张图片".show(this) + } + } + }) + uploadImageViewModel.loadState.observe(this, Observer { + when (it) { + is LoadState.Loading -> { + OtherUtils.showLoadingDialog(this, "图片上传中,请稍后...") + } + else -> OtherUtils.dismissLoadingDialog() + } + }) + + addEventButton.setOnClickListener { + if (eventEditTextView.text.toString().filterString().isEmpty()) { + "事件情况说明还未填写,请检查".show(this) + return@setOnClickListener + } + if (isWarning) { + if (inspectNumberView.text.toString().filterString().isEmpty()) { + "最大泄露值还未填写,请检查".show(this) + return@setOnClickListener + } + } + + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + PictureConfig.CHOOSE_REQUEST -> { + val selectResult = PictureSelector.obtainMultipleResult(data) + for (res in selectResult) { + val file = File(res.compressPath) + if (file.length() <= Constant.IMAGE_MINUS_SIZE) { + "图片尺寸太小,请重新选择".show(this) + continue + } + //上传图片 + uploadImageViewModel.uploadImage(file) + } + } + PictureConfig.REQUEST_CAMERA -> { + val cameraResult = PictureSelector.obtainMultipleResult(data)[0] + //上传图片 + uploadImageViewModel.uploadImage(File(cameraResult.compressPath)) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt index d4821de..9de8a96 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt @@ -32,6 +32,7 @@ } private fun startGuideActivity() { +// startActivity(Intent(this, TestActivity::class.java)) startActivity(Intent(this, GuideActivity::class.java)) finish() } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt new file mode 100644 index 0000000..abb6e23 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt @@ -0,0 +1,54 @@ +package com.casic.birmm.inspect.view + +import android.util.Log +import androidx.core.content.ContextCompat +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseActivity +import com.casic.birmm.inspect.utils.PageNavigationManager +import com.casic.birmm.inspect.utils.StatusBarColorUtil +import com.gyf.immersionbar.ImmersionBar +import kotlinx.android.synthetic.main.activity_test.* +import kotlinx.android.synthetic.main.include_base_title.* + +class TestActivity : BaseActivity() { + + companion object { + private const val Tag = "TestActivity" + } + + private val urls = arrayListOf( + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg" + ) + + override fun initLayoutView(): Int = R.layout.activity_test + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + titleView.text = "测试功能页面" + } + + override fun initData() { + val imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + imageAdapter.setImageList(imageUrls = urls) + imageGridView.setOnItemClickListener { _, _, position, _ -> + Log.d(Tag, "点击path: ${urls[position]}") + } + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + override fun onDeleteItemClick(position: Int) { + Log.d(Tag, "删除path: ${urls[position]}") + } + }) + } + + override fun initEvent() { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt new file mode 100644 index 0000000..dd145f4 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt @@ -0,0 +1,6 @@ +package com.casic.birmm.inspect.vm + +import com.casic.birmm.inspect.base.BaseViewModel + +class NewEventViewModel : BaseViewModel() { +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt index 23ed09d..df03b14 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt @@ -3,6 +3,10 @@ import com.casic.birmm.inspect.model.* import com.casic.birmm.inspect.utils.AuthenticationHelper import com.casic.birmm.inspect.utils.Constant +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File object RetrofitServiceManager { @@ -88,4 +92,13 @@ suspend fun searchByInspection(inspectionId: String): TaskRecordModel { return api.searchByInspection(AuthenticationHelper.token!!, inspectionId) } + + /** + * 上传图片 + */ + suspend fun uploadImage(image: File): ActionResultModel { + val requestBody = RequestBody.create("image/png".toMediaTypeOrNull(), image) + val imagePart = MultipartBody.Part.createFormData("file", image.name, requestBody) + return api.uploadImage(AuthenticationHelper.token!!, imagePart) + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt index 9b29ca3..fe37dc3 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt @@ -3,9 +3,8 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.GridLayoutManager import com.casic.birmm.inspect.R -import com.casic.birmm.inspect.adapter.ImageRecycleViewAdapter +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter import com.casic.birmm.inspect.base.BaseActivity import com.casic.birmm.inspect.extensions.combineImagePath import com.casic.birmm.inspect.extensions.show @@ -54,19 +53,17 @@ } } //绑定图片 - val imageAdapter = ImageRecycleViewAdapter(this, urls) - imageRecyclerView.layoutManager = GridLayoutManager(this, 2) - imageRecyclerView.adapter = imageAdapter - imageAdapter.setOnItemClickListener(object : - ImageRecycleViewAdapter.OnItemClickListener { - override fun onClick(position: Int) { - if (urls[position].isEmpty()) { - "图片加载失败,无法查看大图".show(this@EventDetailActivity) - } else { - OtherUtils.showBigImage(this@EventDetailActivity, position, urls) - } + val imageAdapter = ImageGridViewAdapter(this) + imageAdapter.setImageList(imageUrls = urls) + imageAdapter.isDeleteVisible(false) + imageGridView.adapter = imageAdapter + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (urls[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@EventDetailActivity) + } else { + OtherUtils.showBigImage(this@EventDetailActivity, position, urls) } - }) + } } else { hasImageLayout.visibility = View.GONE dataView.text = "$data.0" diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt index 207f6c3..91fb674 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.view import android.bluetooth.BluetoothAdapter +import android.content.Intent import android.graphics.Color import android.os.Bundle import android.os.Handler @@ -18,6 +19,7 @@ import com.casic.birmm.inspect.utils.PageNavigationManager import com.casic.birmm.inspect.utils.StatusBarColorUtil import com.casic.birmm.inspect.widgets.InputDialog +import com.casic.birmm.inspect.widgets.SingleChoiceDialog import com.gyf.immersionbar.ImmersionBar import com.qmuiteam.qmui.util.QMUIStatusBarHelper import kotlinx.android.synthetic.main.activity_inspect_route.mapView @@ -42,6 +44,7 @@ private lateinit var aMap: AMap private lateinit var locationStyle: MyLocationStyle + private val itemList: List = arrayListOf("报警事件", "自定义事件") init { weakReferenceHandler = WeakReferenceHandler(this) @@ -131,7 +134,25 @@ newEventButton.setChangeAlphaWhenPress(true) newEventButton.setOnClickListener { - + SingleChoiceDialog.Builder() + .setContext(this) + .setTitle("选择事件类型") + .setChoiceItemButton(itemList) + .setOnDialogClickListener(object : SingleChoiceDialog.OnDialogItemClickListener { + override fun onItemClick(position: Int) { + val intent = Intent(this@MapActivity, NewEventActivity::class.java) + when (position) { + 0 -> { + intent.putExtra("isWarning", true) + } + 1 -> { + intent.putExtra("isWarning", false) + } + } + startActivity(intent) + } + }) + .build().show() } } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt new file mode 100644 index 0000000..de3eb19 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt @@ -0,0 +1,191 @@ +package com.casic.birmm.inspect.view + +import android.app.Activity +import android.content.Intent +import android.view.View +import androidx.core.content.ContextCompat +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.aihook.alertview.library.AlertView +import com.aihook.alertview.library.OnItemClickListener +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseViewModelActivity +import com.casic.birmm.inspect.extensions.combineImagePath +import com.casic.birmm.inspect.extensions.filterString +import com.casic.birmm.inspect.extensions.show +import com.casic.birmm.inspect.utils.* +import com.casic.birmm.inspect.vm.NewEventViewModel +import com.casic.birmm.inspect.vm.UploadImageViewModel +import com.gyf.immersionbar.ImmersionBar +import com.luck.picture.lib.PictureSelector +import com.luck.picture.lib.config.PictureConfig +import com.luck.picture.lib.config.PictureMimeType +import kotlinx.android.synthetic.main.activity_new_event.* +import kotlinx.android.synthetic.main.include_base_title.* +import java.io.File + + +class NewEventActivity : BaseViewModelActivity() { + + private lateinit var uploadImageViewModel: UploadImageViewModel + private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var imageAdapter: ImageGridViewAdapter + private var isWarning: Boolean = true + + override fun createViewModelByClass(): Class? = NewEventViewModel::class.java + + override fun initLayoutView(): Int = R.layout.activity_new_event + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + } + + override fun initData() { + uploadImageViewModel = ViewModelProvider(this).get(UploadImageViewModel::class.java) + isWarning = intent.getBooleanExtra("isWarning", true) + if (isWarning) { + titleView.text = "报警事件记录" + inspectCardView.visibility = View.VISIBLE + } else { + titleView.text = "自定义事件记录" + inspectCardView.visibility = View.GONE + } + eventCreateTimeView.text = + TimeOrDateUtil.timestampToCompleteDate(System.currentTimeMillis()) + + //初始化图片九宫格 + imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + } + + override fun initEvent() { + leftBackView.setOnClickListener { this.finish() } + + addImageView.setOnClickListener { + AlertView( + "请选择图片来源", null, "取消", null, arrayOf("拍照", "相册"), + this, AlertView.Style.ActionSheet, + OnItemClickListener { _, position -> + when (position) { + 0 -> { + PictureSelector.create(this) + .openCamera(PictureMimeType.ofImage()) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .forResult(PictureConfig.REQUEST_CAMERA) + } + 1 -> { + PictureSelector.create(this) + .openGallery(PictureMimeType.ofImage()) + .isWeChatStyle(true) + .isCamera(false) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .maxSelectNum(4) + .forResult(PictureConfig.CHOOSE_REQUEST) + } + } + } + ).setCancelable(true).show() + } + uploadImageViewModel.resultModel.observe(this, Observer { model -> + if (model.code == 200) { + /** + * 显示图片 + * path: 2021-07\c670eac17d644b179a4324a34bb84329.jpeg + * */ + imageGridView.visibility = View.VISIBLE + val sumItemCount: Int = imageAdapter.count + 1 //每上传一张图片,图片总数都是在原有的基础上+1 + if (sumItemCount <= 4) { + val url = model.data + //let函数处理需要针对一个可null的对象统一做判空处理。 + url?.let { + imagePaths.add(it) + realPaths.add(it.combineImagePath()) + } + if (realPaths.size == 4) { + addImageView.visibility = View.GONE + } + imageAdapter.setImageList(imageUrls = realPaths) + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@NewEventActivity) + } else { + OtherUtils.showBigImage(this@NewEventActivity, position, realPaths) + } + } + //删除按钮点击事件 + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + @Override + override fun onDeleteItemClick(position: Int) { + imagePaths.removeAt(position) + realPaths.removeAt(position) + imageAdapter.setImageList(imageUrls = realPaths) + if (realPaths.size != 2) { + addImageView.visibility = View.VISIBLE + } + } + }) + } else { + "最多只能上传4张图片".show(this) + } + } + }) + uploadImageViewModel.loadState.observe(this, Observer { + when (it) { + is LoadState.Loading -> { + OtherUtils.showLoadingDialog(this, "图片上传中,请稍后...") + } + else -> OtherUtils.dismissLoadingDialog() + } + }) + + addEventButton.setOnClickListener { + if (eventEditTextView.text.toString().filterString().isEmpty()) { + "事件情况说明还未填写,请检查".show(this) + return@setOnClickListener + } + if (isWarning) { + if (inspectNumberView.text.toString().filterString().isEmpty()) { + "最大泄露值还未填写,请检查".show(this) + return@setOnClickListener + } + } + + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + PictureConfig.CHOOSE_REQUEST -> { + val selectResult = PictureSelector.obtainMultipleResult(data) + for (res in selectResult) { + val file = File(res.compressPath) + if (file.length() <= Constant.IMAGE_MINUS_SIZE) { + "图片尺寸太小,请重新选择".show(this) + continue + } + //上传图片 + uploadImageViewModel.uploadImage(file) + } + } + PictureConfig.REQUEST_CAMERA -> { + val cameraResult = PictureSelector.obtainMultipleResult(data)[0] + //上传图片 + uploadImageViewModel.uploadImage(File(cameraResult.compressPath)) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt index d4821de..9de8a96 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt @@ -32,6 +32,7 @@ } private fun startGuideActivity() { +// startActivity(Intent(this, TestActivity::class.java)) startActivity(Intent(this, GuideActivity::class.java)) finish() } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt new file mode 100644 index 0000000..abb6e23 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt @@ -0,0 +1,54 @@ +package com.casic.birmm.inspect.view + +import android.util.Log +import androidx.core.content.ContextCompat +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseActivity +import com.casic.birmm.inspect.utils.PageNavigationManager +import com.casic.birmm.inspect.utils.StatusBarColorUtil +import com.gyf.immersionbar.ImmersionBar +import kotlinx.android.synthetic.main.activity_test.* +import kotlinx.android.synthetic.main.include_base_title.* + +class TestActivity : BaseActivity() { + + companion object { + private const val Tag = "TestActivity" + } + + private val urls = arrayListOf( + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg" + ) + + override fun initLayoutView(): Int = R.layout.activity_test + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + titleView.text = "测试功能页面" + } + + override fun initData() { + val imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + imageAdapter.setImageList(imageUrls = urls) + imageGridView.setOnItemClickListener { _, _, position, _ -> + Log.d(Tag, "点击path: ${urls[position]}") + } + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + override fun onDeleteItemClick(position: Int) { + Log.d(Tag, "删除path: ${urls[position]}") + } + }) + } + + override fun initEvent() { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt new file mode 100644 index 0000000..dd145f4 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt @@ -0,0 +1,6 @@ +package com.casic.birmm.inspect.vm + +import com.casic.birmm.inspect.base.BaseViewModel + +class NewEventViewModel : BaseViewModel() { +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt new file mode 100644 index 0000000..a7fa31b --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt @@ -0,0 +1,21 @@ +package com.casic.birmm.inspect.vm + +import androidx.lifecycle.MutableLiveData +import com.casic.birmm.inspect.base.BaseViewModel +import com.casic.birmm.inspect.extensions.launch +import com.casic.birmm.inspect.model.ActionResultModel +import com.casic.birmm.inspect.utils.LoadState +import com.casic.birmm.inspect.utils.retrofit.RetrofitServiceManager +import java.io.File + +class UploadImageViewModel : BaseViewModel() { + val resultModel = MutableLiveData() + + fun uploadImage(image: File) = launch({ + loadState.value = LoadState.Loading + resultModel.value = RetrofitServiceManager.uploadImage(image) + loadState.value = LoadState.Success + }, { + loadState.value = LoadState.Fail + }) +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt index 23ed09d..df03b14 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt @@ -3,6 +3,10 @@ import com.casic.birmm.inspect.model.* import com.casic.birmm.inspect.utils.AuthenticationHelper import com.casic.birmm.inspect.utils.Constant +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File object RetrofitServiceManager { @@ -88,4 +92,13 @@ suspend fun searchByInspection(inspectionId: String): TaskRecordModel { return api.searchByInspection(AuthenticationHelper.token!!, inspectionId) } + + /** + * 上传图片 + */ + suspend fun uploadImage(image: File): ActionResultModel { + val requestBody = RequestBody.create("image/png".toMediaTypeOrNull(), image) + val imagePart = MultipartBody.Part.createFormData("file", image.name, requestBody) + return api.uploadImage(AuthenticationHelper.token!!, imagePart) + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt index 9b29ca3..fe37dc3 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt @@ -3,9 +3,8 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.GridLayoutManager import com.casic.birmm.inspect.R -import com.casic.birmm.inspect.adapter.ImageRecycleViewAdapter +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter import com.casic.birmm.inspect.base.BaseActivity import com.casic.birmm.inspect.extensions.combineImagePath import com.casic.birmm.inspect.extensions.show @@ -54,19 +53,17 @@ } } //绑定图片 - val imageAdapter = ImageRecycleViewAdapter(this, urls) - imageRecyclerView.layoutManager = GridLayoutManager(this, 2) - imageRecyclerView.adapter = imageAdapter - imageAdapter.setOnItemClickListener(object : - ImageRecycleViewAdapter.OnItemClickListener { - override fun onClick(position: Int) { - if (urls[position].isEmpty()) { - "图片加载失败,无法查看大图".show(this@EventDetailActivity) - } else { - OtherUtils.showBigImage(this@EventDetailActivity, position, urls) - } + val imageAdapter = ImageGridViewAdapter(this) + imageAdapter.setImageList(imageUrls = urls) + imageAdapter.isDeleteVisible(false) + imageGridView.adapter = imageAdapter + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (urls[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@EventDetailActivity) + } else { + OtherUtils.showBigImage(this@EventDetailActivity, position, urls) } - }) + } } else { hasImageLayout.visibility = View.GONE dataView.text = "$data.0" diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt index 207f6c3..91fb674 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.view import android.bluetooth.BluetoothAdapter +import android.content.Intent import android.graphics.Color import android.os.Bundle import android.os.Handler @@ -18,6 +19,7 @@ import com.casic.birmm.inspect.utils.PageNavigationManager import com.casic.birmm.inspect.utils.StatusBarColorUtil import com.casic.birmm.inspect.widgets.InputDialog +import com.casic.birmm.inspect.widgets.SingleChoiceDialog import com.gyf.immersionbar.ImmersionBar import com.qmuiteam.qmui.util.QMUIStatusBarHelper import kotlinx.android.synthetic.main.activity_inspect_route.mapView @@ -42,6 +44,7 @@ private lateinit var aMap: AMap private lateinit var locationStyle: MyLocationStyle + private val itemList: List = arrayListOf("报警事件", "自定义事件") init { weakReferenceHandler = WeakReferenceHandler(this) @@ -131,7 +134,25 @@ newEventButton.setChangeAlphaWhenPress(true) newEventButton.setOnClickListener { - + SingleChoiceDialog.Builder() + .setContext(this) + .setTitle("选择事件类型") + .setChoiceItemButton(itemList) + .setOnDialogClickListener(object : SingleChoiceDialog.OnDialogItemClickListener { + override fun onItemClick(position: Int) { + val intent = Intent(this@MapActivity, NewEventActivity::class.java) + when (position) { + 0 -> { + intent.putExtra("isWarning", true) + } + 1 -> { + intent.putExtra("isWarning", false) + } + } + startActivity(intent) + } + }) + .build().show() } } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt new file mode 100644 index 0000000..de3eb19 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt @@ -0,0 +1,191 @@ +package com.casic.birmm.inspect.view + +import android.app.Activity +import android.content.Intent +import android.view.View +import androidx.core.content.ContextCompat +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.aihook.alertview.library.AlertView +import com.aihook.alertview.library.OnItemClickListener +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseViewModelActivity +import com.casic.birmm.inspect.extensions.combineImagePath +import com.casic.birmm.inspect.extensions.filterString +import com.casic.birmm.inspect.extensions.show +import com.casic.birmm.inspect.utils.* +import com.casic.birmm.inspect.vm.NewEventViewModel +import com.casic.birmm.inspect.vm.UploadImageViewModel +import com.gyf.immersionbar.ImmersionBar +import com.luck.picture.lib.PictureSelector +import com.luck.picture.lib.config.PictureConfig +import com.luck.picture.lib.config.PictureMimeType +import kotlinx.android.synthetic.main.activity_new_event.* +import kotlinx.android.synthetic.main.include_base_title.* +import java.io.File + + +class NewEventActivity : BaseViewModelActivity() { + + private lateinit var uploadImageViewModel: UploadImageViewModel + private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var imageAdapter: ImageGridViewAdapter + private var isWarning: Boolean = true + + override fun createViewModelByClass(): Class? = NewEventViewModel::class.java + + override fun initLayoutView(): Int = R.layout.activity_new_event + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + } + + override fun initData() { + uploadImageViewModel = ViewModelProvider(this).get(UploadImageViewModel::class.java) + isWarning = intent.getBooleanExtra("isWarning", true) + if (isWarning) { + titleView.text = "报警事件记录" + inspectCardView.visibility = View.VISIBLE + } else { + titleView.text = "自定义事件记录" + inspectCardView.visibility = View.GONE + } + eventCreateTimeView.text = + TimeOrDateUtil.timestampToCompleteDate(System.currentTimeMillis()) + + //初始化图片九宫格 + imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + } + + override fun initEvent() { + leftBackView.setOnClickListener { this.finish() } + + addImageView.setOnClickListener { + AlertView( + "请选择图片来源", null, "取消", null, arrayOf("拍照", "相册"), + this, AlertView.Style.ActionSheet, + OnItemClickListener { _, position -> + when (position) { + 0 -> { + PictureSelector.create(this) + .openCamera(PictureMimeType.ofImage()) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .forResult(PictureConfig.REQUEST_CAMERA) + } + 1 -> { + PictureSelector.create(this) + .openGallery(PictureMimeType.ofImage()) + .isWeChatStyle(true) + .isCamera(false) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .maxSelectNum(4) + .forResult(PictureConfig.CHOOSE_REQUEST) + } + } + } + ).setCancelable(true).show() + } + uploadImageViewModel.resultModel.observe(this, Observer { model -> + if (model.code == 200) { + /** + * 显示图片 + * path: 2021-07\c670eac17d644b179a4324a34bb84329.jpeg + * */ + imageGridView.visibility = View.VISIBLE + val sumItemCount: Int = imageAdapter.count + 1 //每上传一张图片,图片总数都是在原有的基础上+1 + if (sumItemCount <= 4) { + val url = model.data + //let函数处理需要针对一个可null的对象统一做判空处理。 + url?.let { + imagePaths.add(it) + realPaths.add(it.combineImagePath()) + } + if (realPaths.size == 4) { + addImageView.visibility = View.GONE + } + imageAdapter.setImageList(imageUrls = realPaths) + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@NewEventActivity) + } else { + OtherUtils.showBigImage(this@NewEventActivity, position, realPaths) + } + } + //删除按钮点击事件 + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + @Override + override fun onDeleteItemClick(position: Int) { + imagePaths.removeAt(position) + realPaths.removeAt(position) + imageAdapter.setImageList(imageUrls = realPaths) + if (realPaths.size != 2) { + addImageView.visibility = View.VISIBLE + } + } + }) + } else { + "最多只能上传4张图片".show(this) + } + } + }) + uploadImageViewModel.loadState.observe(this, Observer { + when (it) { + is LoadState.Loading -> { + OtherUtils.showLoadingDialog(this, "图片上传中,请稍后...") + } + else -> OtherUtils.dismissLoadingDialog() + } + }) + + addEventButton.setOnClickListener { + if (eventEditTextView.text.toString().filterString().isEmpty()) { + "事件情况说明还未填写,请检查".show(this) + return@setOnClickListener + } + if (isWarning) { + if (inspectNumberView.text.toString().filterString().isEmpty()) { + "最大泄露值还未填写,请检查".show(this) + return@setOnClickListener + } + } + + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + PictureConfig.CHOOSE_REQUEST -> { + val selectResult = PictureSelector.obtainMultipleResult(data) + for (res in selectResult) { + val file = File(res.compressPath) + if (file.length() <= Constant.IMAGE_MINUS_SIZE) { + "图片尺寸太小,请重新选择".show(this) + continue + } + //上传图片 + uploadImageViewModel.uploadImage(file) + } + } + PictureConfig.REQUEST_CAMERA -> { + val cameraResult = PictureSelector.obtainMultipleResult(data)[0] + //上传图片 + uploadImageViewModel.uploadImage(File(cameraResult.compressPath)) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt index d4821de..9de8a96 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt @@ -32,6 +32,7 @@ } private fun startGuideActivity() { +// startActivity(Intent(this, TestActivity::class.java)) startActivity(Intent(this, GuideActivity::class.java)) finish() } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt new file mode 100644 index 0000000..abb6e23 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt @@ -0,0 +1,54 @@ +package com.casic.birmm.inspect.view + +import android.util.Log +import androidx.core.content.ContextCompat +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseActivity +import com.casic.birmm.inspect.utils.PageNavigationManager +import com.casic.birmm.inspect.utils.StatusBarColorUtil +import com.gyf.immersionbar.ImmersionBar +import kotlinx.android.synthetic.main.activity_test.* +import kotlinx.android.synthetic.main.include_base_title.* + +class TestActivity : BaseActivity() { + + companion object { + private const val Tag = "TestActivity" + } + + private val urls = arrayListOf( + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg" + ) + + override fun initLayoutView(): Int = R.layout.activity_test + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + titleView.text = "测试功能页面" + } + + override fun initData() { + val imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + imageAdapter.setImageList(imageUrls = urls) + imageGridView.setOnItemClickListener { _, _, position, _ -> + Log.d(Tag, "点击path: ${urls[position]}") + } + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + override fun onDeleteItemClick(position: Int) { + Log.d(Tag, "删除path: ${urls[position]}") + } + }) + } + + override fun initEvent() { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt new file mode 100644 index 0000000..dd145f4 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt @@ -0,0 +1,6 @@ +package com.casic.birmm.inspect.vm + +import com.casic.birmm.inspect.base.BaseViewModel + +class NewEventViewModel : BaseViewModel() { +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt new file mode 100644 index 0000000..a7fa31b --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt @@ -0,0 +1,21 @@ +package com.casic.birmm.inspect.vm + +import androidx.lifecycle.MutableLiveData +import com.casic.birmm.inspect.base.BaseViewModel +import com.casic.birmm.inspect.extensions.launch +import com.casic.birmm.inspect.model.ActionResultModel +import com.casic.birmm.inspect.utils.LoadState +import com.casic.birmm.inspect.utils.retrofit.RetrofitServiceManager +import java.io.File + +class UploadImageViewModel : BaseViewModel() { + val resultModel = MutableLiveData() + + fun uploadImage(image: File) = launch({ + loadState.value = LoadState.Loading + resultModel.value = RetrofitServiceManager.uploadImage(image) + loadState.value = LoadState.Success + }, { + loadState.value = LoadState.Fail + }) +} \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_layout_white.xml b/app/src/main/res/drawable/bg_layout_white.xml index 19b473b..1002512 100644 --- a/app/src/main/res/drawable/bg_layout_white.xml +++ b/app/src/main/res/drawable/bg_layout_white.xml @@ -7,5 +7,5 @@ + android:color="@color/hintColor" /> \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt index 23ed09d..df03b14 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt @@ -3,6 +3,10 @@ import com.casic.birmm.inspect.model.* import com.casic.birmm.inspect.utils.AuthenticationHelper import com.casic.birmm.inspect.utils.Constant +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File object RetrofitServiceManager { @@ -88,4 +92,13 @@ suspend fun searchByInspection(inspectionId: String): TaskRecordModel { return api.searchByInspection(AuthenticationHelper.token!!, inspectionId) } + + /** + * 上传图片 + */ + suspend fun uploadImage(image: File): ActionResultModel { + val requestBody = RequestBody.create("image/png".toMediaTypeOrNull(), image) + val imagePart = MultipartBody.Part.createFormData("file", image.name, requestBody) + return api.uploadImage(AuthenticationHelper.token!!, imagePart) + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt index 9b29ca3..fe37dc3 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt @@ -3,9 +3,8 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.GridLayoutManager import com.casic.birmm.inspect.R -import com.casic.birmm.inspect.adapter.ImageRecycleViewAdapter +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter import com.casic.birmm.inspect.base.BaseActivity import com.casic.birmm.inspect.extensions.combineImagePath import com.casic.birmm.inspect.extensions.show @@ -54,19 +53,17 @@ } } //绑定图片 - val imageAdapter = ImageRecycleViewAdapter(this, urls) - imageRecyclerView.layoutManager = GridLayoutManager(this, 2) - imageRecyclerView.adapter = imageAdapter - imageAdapter.setOnItemClickListener(object : - ImageRecycleViewAdapter.OnItemClickListener { - override fun onClick(position: Int) { - if (urls[position].isEmpty()) { - "图片加载失败,无法查看大图".show(this@EventDetailActivity) - } else { - OtherUtils.showBigImage(this@EventDetailActivity, position, urls) - } + val imageAdapter = ImageGridViewAdapter(this) + imageAdapter.setImageList(imageUrls = urls) + imageAdapter.isDeleteVisible(false) + imageGridView.adapter = imageAdapter + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (urls[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@EventDetailActivity) + } else { + OtherUtils.showBigImage(this@EventDetailActivity, position, urls) } - }) + } } else { hasImageLayout.visibility = View.GONE dataView.text = "$data.0" diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt index 207f6c3..91fb674 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.view import android.bluetooth.BluetoothAdapter +import android.content.Intent import android.graphics.Color import android.os.Bundle import android.os.Handler @@ -18,6 +19,7 @@ import com.casic.birmm.inspect.utils.PageNavigationManager import com.casic.birmm.inspect.utils.StatusBarColorUtil import com.casic.birmm.inspect.widgets.InputDialog +import com.casic.birmm.inspect.widgets.SingleChoiceDialog import com.gyf.immersionbar.ImmersionBar import com.qmuiteam.qmui.util.QMUIStatusBarHelper import kotlinx.android.synthetic.main.activity_inspect_route.mapView @@ -42,6 +44,7 @@ private lateinit var aMap: AMap private lateinit var locationStyle: MyLocationStyle + private val itemList: List = arrayListOf("报警事件", "自定义事件") init { weakReferenceHandler = WeakReferenceHandler(this) @@ -131,7 +134,25 @@ newEventButton.setChangeAlphaWhenPress(true) newEventButton.setOnClickListener { - + SingleChoiceDialog.Builder() + .setContext(this) + .setTitle("选择事件类型") + .setChoiceItemButton(itemList) + .setOnDialogClickListener(object : SingleChoiceDialog.OnDialogItemClickListener { + override fun onItemClick(position: Int) { + val intent = Intent(this@MapActivity, NewEventActivity::class.java) + when (position) { + 0 -> { + intent.putExtra("isWarning", true) + } + 1 -> { + intent.putExtra("isWarning", false) + } + } + startActivity(intent) + } + }) + .build().show() } } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt new file mode 100644 index 0000000..de3eb19 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt @@ -0,0 +1,191 @@ +package com.casic.birmm.inspect.view + +import android.app.Activity +import android.content.Intent +import android.view.View +import androidx.core.content.ContextCompat +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.aihook.alertview.library.AlertView +import com.aihook.alertview.library.OnItemClickListener +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseViewModelActivity +import com.casic.birmm.inspect.extensions.combineImagePath +import com.casic.birmm.inspect.extensions.filterString +import com.casic.birmm.inspect.extensions.show +import com.casic.birmm.inspect.utils.* +import com.casic.birmm.inspect.vm.NewEventViewModel +import com.casic.birmm.inspect.vm.UploadImageViewModel +import com.gyf.immersionbar.ImmersionBar +import com.luck.picture.lib.PictureSelector +import com.luck.picture.lib.config.PictureConfig +import com.luck.picture.lib.config.PictureMimeType +import kotlinx.android.synthetic.main.activity_new_event.* +import kotlinx.android.synthetic.main.include_base_title.* +import java.io.File + + +class NewEventActivity : BaseViewModelActivity() { + + private lateinit var uploadImageViewModel: UploadImageViewModel + private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var imageAdapter: ImageGridViewAdapter + private var isWarning: Boolean = true + + override fun createViewModelByClass(): Class? = NewEventViewModel::class.java + + override fun initLayoutView(): Int = R.layout.activity_new_event + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + } + + override fun initData() { + uploadImageViewModel = ViewModelProvider(this).get(UploadImageViewModel::class.java) + isWarning = intent.getBooleanExtra("isWarning", true) + if (isWarning) { + titleView.text = "报警事件记录" + inspectCardView.visibility = View.VISIBLE + } else { + titleView.text = "自定义事件记录" + inspectCardView.visibility = View.GONE + } + eventCreateTimeView.text = + TimeOrDateUtil.timestampToCompleteDate(System.currentTimeMillis()) + + //初始化图片九宫格 + imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + } + + override fun initEvent() { + leftBackView.setOnClickListener { this.finish() } + + addImageView.setOnClickListener { + AlertView( + "请选择图片来源", null, "取消", null, arrayOf("拍照", "相册"), + this, AlertView.Style.ActionSheet, + OnItemClickListener { _, position -> + when (position) { + 0 -> { + PictureSelector.create(this) + .openCamera(PictureMimeType.ofImage()) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .forResult(PictureConfig.REQUEST_CAMERA) + } + 1 -> { + PictureSelector.create(this) + .openGallery(PictureMimeType.ofImage()) + .isWeChatStyle(true) + .isCamera(false) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .maxSelectNum(4) + .forResult(PictureConfig.CHOOSE_REQUEST) + } + } + } + ).setCancelable(true).show() + } + uploadImageViewModel.resultModel.observe(this, Observer { model -> + if (model.code == 200) { + /** + * 显示图片 + * path: 2021-07\c670eac17d644b179a4324a34bb84329.jpeg + * */ + imageGridView.visibility = View.VISIBLE + val sumItemCount: Int = imageAdapter.count + 1 //每上传一张图片,图片总数都是在原有的基础上+1 + if (sumItemCount <= 4) { + val url = model.data + //let函数处理需要针对一个可null的对象统一做判空处理。 + url?.let { + imagePaths.add(it) + realPaths.add(it.combineImagePath()) + } + if (realPaths.size == 4) { + addImageView.visibility = View.GONE + } + imageAdapter.setImageList(imageUrls = realPaths) + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@NewEventActivity) + } else { + OtherUtils.showBigImage(this@NewEventActivity, position, realPaths) + } + } + //删除按钮点击事件 + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + @Override + override fun onDeleteItemClick(position: Int) { + imagePaths.removeAt(position) + realPaths.removeAt(position) + imageAdapter.setImageList(imageUrls = realPaths) + if (realPaths.size != 2) { + addImageView.visibility = View.VISIBLE + } + } + }) + } else { + "最多只能上传4张图片".show(this) + } + } + }) + uploadImageViewModel.loadState.observe(this, Observer { + when (it) { + is LoadState.Loading -> { + OtherUtils.showLoadingDialog(this, "图片上传中,请稍后...") + } + else -> OtherUtils.dismissLoadingDialog() + } + }) + + addEventButton.setOnClickListener { + if (eventEditTextView.text.toString().filterString().isEmpty()) { + "事件情况说明还未填写,请检查".show(this) + return@setOnClickListener + } + if (isWarning) { + if (inspectNumberView.text.toString().filterString().isEmpty()) { + "最大泄露值还未填写,请检查".show(this) + return@setOnClickListener + } + } + + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + PictureConfig.CHOOSE_REQUEST -> { + val selectResult = PictureSelector.obtainMultipleResult(data) + for (res in selectResult) { + val file = File(res.compressPath) + if (file.length() <= Constant.IMAGE_MINUS_SIZE) { + "图片尺寸太小,请重新选择".show(this) + continue + } + //上传图片 + uploadImageViewModel.uploadImage(file) + } + } + PictureConfig.REQUEST_CAMERA -> { + val cameraResult = PictureSelector.obtainMultipleResult(data)[0] + //上传图片 + uploadImageViewModel.uploadImage(File(cameraResult.compressPath)) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt index d4821de..9de8a96 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt @@ -32,6 +32,7 @@ } private fun startGuideActivity() { +// startActivity(Intent(this, TestActivity::class.java)) startActivity(Intent(this, GuideActivity::class.java)) finish() } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt new file mode 100644 index 0000000..abb6e23 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt @@ -0,0 +1,54 @@ +package com.casic.birmm.inspect.view + +import android.util.Log +import androidx.core.content.ContextCompat +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseActivity +import com.casic.birmm.inspect.utils.PageNavigationManager +import com.casic.birmm.inspect.utils.StatusBarColorUtil +import com.gyf.immersionbar.ImmersionBar +import kotlinx.android.synthetic.main.activity_test.* +import kotlinx.android.synthetic.main.include_base_title.* + +class TestActivity : BaseActivity() { + + companion object { + private const val Tag = "TestActivity" + } + + private val urls = arrayListOf( + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg" + ) + + override fun initLayoutView(): Int = R.layout.activity_test + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + titleView.text = "测试功能页面" + } + + override fun initData() { + val imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + imageAdapter.setImageList(imageUrls = urls) + imageGridView.setOnItemClickListener { _, _, position, _ -> + Log.d(Tag, "点击path: ${urls[position]}") + } + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + override fun onDeleteItemClick(position: Int) { + Log.d(Tag, "删除path: ${urls[position]}") + } + }) + } + + override fun initEvent() { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt new file mode 100644 index 0000000..dd145f4 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt @@ -0,0 +1,6 @@ +package com.casic.birmm.inspect.vm + +import com.casic.birmm.inspect.base.BaseViewModel + +class NewEventViewModel : BaseViewModel() { +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt new file mode 100644 index 0000000..a7fa31b --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt @@ -0,0 +1,21 @@ +package com.casic.birmm.inspect.vm + +import androidx.lifecycle.MutableLiveData +import com.casic.birmm.inspect.base.BaseViewModel +import com.casic.birmm.inspect.extensions.launch +import com.casic.birmm.inspect.model.ActionResultModel +import com.casic.birmm.inspect.utils.LoadState +import com.casic.birmm.inspect.utils.retrofit.RetrofitServiceManager +import java.io.File + +class UploadImageViewModel : BaseViewModel() { + val resultModel = MutableLiveData() + + fun uploadImage(image: File) = launch({ + loadState.value = LoadState.Loading + resultModel.value = RetrofitServiceManager.uploadImage(image) + loadState.value = LoadState.Success + }, { + loadState.value = LoadState.Fail + }) +} \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_layout_white.xml b/app/src/main/res/drawable/bg_layout_white.xml index 19b473b..1002512 100644 --- a/app/src/main/res/drawable/bg_layout_white.xml +++ b/app/src/main/res/drawable/bg_layout_white.xml @@ -7,5 +7,5 @@ + android:color="@color/hintColor" /> \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_black.xml b/app/src/main/res/drawable/ic_add_black.xml new file mode 100644 index 0000000..4a7fb89 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt index 23ed09d..df03b14 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt @@ -3,6 +3,10 @@ import com.casic.birmm.inspect.model.* import com.casic.birmm.inspect.utils.AuthenticationHelper import com.casic.birmm.inspect.utils.Constant +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File object RetrofitServiceManager { @@ -88,4 +92,13 @@ suspend fun searchByInspection(inspectionId: String): TaskRecordModel { return api.searchByInspection(AuthenticationHelper.token!!, inspectionId) } + + /** + * 上传图片 + */ + suspend fun uploadImage(image: File): ActionResultModel { + val requestBody = RequestBody.create("image/png".toMediaTypeOrNull(), image) + val imagePart = MultipartBody.Part.createFormData("file", image.name, requestBody) + return api.uploadImage(AuthenticationHelper.token!!, imagePart) + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt index 9b29ca3..fe37dc3 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt @@ -3,9 +3,8 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.GridLayoutManager import com.casic.birmm.inspect.R -import com.casic.birmm.inspect.adapter.ImageRecycleViewAdapter +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter import com.casic.birmm.inspect.base.BaseActivity import com.casic.birmm.inspect.extensions.combineImagePath import com.casic.birmm.inspect.extensions.show @@ -54,19 +53,17 @@ } } //绑定图片 - val imageAdapter = ImageRecycleViewAdapter(this, urls) - imageRecyclerView.layoutManager = GridLayoutManager(this, 2) - imageRecyclerView.adapter = imageAdapter - imageAdapter.setOnItemClickListener(object : - ImageRecycleViewAdapter.OnItemClickListener { - override fun onClick(position: Int) { - if (urls[position].isEmpty()) { - "图片加载失败,无法查看大图".show(this@EventDetailActivity) - } else { - OtherUtils.showBigImage(this@EventDetailActivity, position, urls) - } + val imageAdapter = ImageGridViewAdapter(this) + imageAdapter.setImageList(imageUrls = urls) + imageAdapter.isDeleteVisible(false) + imageGridView.adapter = imageAdapter + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (urls[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@EventDetailActivity) + } else { + OtherUtils.showBigImage(this@EventDetailActivity, position, urls) } - }) + } } else { hasImageLayout.visibility = View.GONE dataView.text = "$data.0" diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt index 207f6c3..91fb674 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.view import android.bluetooth.BluetoothAdapter +import android.content.Intent import android.graphics.Color import android.os.Bundle import android.os.Handler @@ -18,6 +19,7 @@ import com.casic.birmm.inspect.utils.PageNavigationManager import com.casic.birmm.inspect.utils.StatusBarColorUtil import com.casic.birmm.inspect.widgets.InputDialog +import com.casic.birmm.inspect.widgets.SingleChoiceDialog import com.gyf.immersionbar.ImmersionBar import com.qmuiteam.qmui.util.QMUIStatusBarHelper import kotlinx.android.synthetic.main.activity_inspect_route.mapView @@ -42,6 +44,7 @@ private lateinit var aMap: AMap private lateinit var locationStyle: MyLocationStyle + private val itemList: List = arrayListOf("报警事件", "自定义事件") init { weakReferenceHandler = WeakReferenceHandler(this) @@ -131,7 +134,25 @@ newEventButton.setChangeAlphaWhenPress(true) newEventButton.setOnClickListener { - + SingleChoiceDialog.Builder() + .setContext(this) + .setTitle("选择事件类型") + .setChoiceItemButton(itemList) + .setOnDialogClickListener(object : SingleChoiceDialog.OnDialogItemClickListener { + override fun onItemClick(position: Int) { + val intent = Intent(this@MapActivity, NewEventActivity::class.java) + when (position) { + 0 -> { + intent.putExtra("isWarning", true) + } + 1 -> { + intent.putExtra("isWarning", false) + } + } + startActivity(intent) + } + }) + .build().show() } } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt new file mode 100644 index 0000000..de3eb19 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt @@ -0,0 +1,191 @@ +package com.casic.birmm.inspect.view + +import android.app.Activity +import android.content.Intent +import android.view.View +import androidx.core.content.ContextCompat +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.aihook.alertview.library.AlertView +import com.aihook.alertview.library.OnItemClickListener +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseViewModelActivity +import com.casic.birmm.inspect.extensions.combineImagePath +import com.casic.birmm.inspect.extensions.filterString +import com.casic.birmm.inspect.extensions.show +import com.casic.birmm.inspect.utils.* +import com.casic.birmm.inspect.vm.NewEventViewModel +import com.casic.birmm.inspect.vm.UploadImageViewModel +import com.gyf.immersionbar.ImmersionBar +import com.luck.picture.lib.PictureSelector +import com.luck.picture.lib.config.PictureConfig +import com.luck.picture.lib.config.PictureMimeType +import kotlinx.android.synthetic.main.activity_new_event.* +import kotlinx.android.synthetic.main.include_base_title.* +import java.io.File + + +class NewEventActivity : BaseViewModelActivity() { + + private lateinit var uploadImageViewModel: UploadImageViewModel + private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var imageAdapter: ImageGridViewAdapter + private var isWarning: Boolean = true + + override fun createViewModelByClass(): Class? = NewEventViewModel::class.java + + override fun initLayoutView(): Int = R.layout.activity_new_event + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + } + + override fun initData() { + uploadImageViewModel = ViewModelProvider(this).get(UploadImageViewModel::class.java) + isWarning = intent.getBooleanExtra("isWarning", true) + if (isWarning) { + titleView.text = "报警事件记录" + inspectCardView.visibility = View.VISIBLE + } else { + titleView.text = "自定义事件记录" + inspectCardView.visibility = View.GONE + } + eventCreateTimeView.text = + TimeOrDateUtil.timestampToCompleteDate(System.currentTimeMillis()) + + //初始化图片九宫格 + imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + } + + override fun initEvent() { + leftBackView.setOnClickListener { this.finish() } + + addImageView.setOnClickListener { + AlertView( + "请选择图片来源", null, "取消", null, arrayOf("拍照", "相册"), + this, AlertView.Style.ActionSheet, + OnItemClickListener { _, position -> + when (position) { + 0 -> { + PictureSelector.create(this) + .openCamera(PictureMimeType.ofImage()) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .forResult(PictureConfig.REQUEST_CAMERA) + } + 1 -> { + PictureSelector.create(this) + .openGallery(PictureMimeType.ofImage()) + .isWeChatStyle(true) + .isCamera(false) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .maxSelectNum(4) + .forResult(PictureConfig.CHOOSE_REQUEST) + } + } + } + ).setCancelable(true).show() + } + uploadImageViewModel.resultModel.observe(this, Observer { model -> + if (model.code == 200) { + /** + * 显示图片 + * path: 2021-07\c670eac17d644b179a4324a34bb84329.jpeg + * */ + imageGridView.visibility = View.VISIBLE + val sumItemCount: Int = imageAdapter.count + 1 //每上传一张图片,图片总数都是在原有的基础上+1 + if (sumItemCount <= 4) { + val url = model.data + //let函数处理需要针对一个可null的对象统一做判空处理。 + url?.let { + imagePaths.add(it) + realPaths.add(it.combineImagePath()) + } + if (realPaths.size == 4) { + addImageView.visibility = View.GONE + } + imageAdapter.setImageList(imageUrls = realPaths) + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@NewEventActivity) + } else { + OtherUtils.showBigImage(this@NewEventActivity, position, realPaths) + } + } + //删除按钮点击事件 + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + @Override + override fun onDeleteItemClick(position: Int) { + imagePaths.removeAt(position) + realPaths.removeAt(position) + imageAdapter.setImageList(imageUrls = realPaths) + if (realPaths.size != 2) { + addImageView.visibility = View.VISIBLE + } + } + }) + } else { + "最多只能上传4张图片".show(this) + } + } + }) + uploadImageViewModel.loadState.observe(this, Observer { + when (it) { + is LoadState.Loading -> { + OtherUtils.showLoadingDialog(this, "图片上传中,请稍后...") + } + else -> OtherUtils.dismissLoadingDialog() + } + }) + + addEventButton.setOnClickListener { + if (eventEditTextView.text.toString().filterString().isEmpty()) { + "事件情况说明还未填写,请检查".show(this) + return@setOnClickListener + } + if (isWarning) { + if (inspectNumberView.text.toString().filterString().isEmpty()) { + "最大泄露值还未填写,请检查".show(this) + return@setOnClickListener + } + } + + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + PictureConfig.CHOOSE_REQUEST -> { + val selectResult = PictureSelector.obtainMultipleResult(data) + for (res in selectResult) { + val file = File(res.compressPath) + if (file.length() <= Constant.IMAGE_MINUS_SIZE) { + "图片尺寸太小,请重新选择".show(this) + continue + } + //上传图片 + uploadImageViewModel.uploadImage(file) + } + } + PictureConfig.REQUEST_CAMERA -> { + val cameraResult = PictureSelector.obtainMultipleResult(data)[0] + //上传图片 + uploadImageViewModel.uploadImage(File(cameraResult.compressPath)) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt index d4821de..9de8a96 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt @@ -32,6 +32,7 @@ } private fun startGuideActivity() { +// startActivity(Intent(this, TestActivity::class.java)) startActivity(Intent(this, GuideActivity::class.java)) finish() } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt new file mode 100644 index 0000000..abb6e23 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt @@ -0,0 +1,54 @@ +package com.casic.birmm.inspect.view + +import android.util.Log +import androidx.core.content.ContextCompat +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseActivity +import com.casic.birmm.inspect.utils.PageNavigationManager +import com.casic.birmm.inspect.utils.StatusBarColorUtil +import com.gyf.immersionbar.ImmersionBar +import kotlinx.android.synthetic.main.activity_test.* +import kotlinx.android.synthetic.main.include_base_title.* + +class TestActivity : BaseActivity() { + + companion object { + private const val Tag = "TestActivity" + } + + private val urls = arrayListOf( + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg" + ) + + override fun initLayoutView(): Int = R.layout.activity_test + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + titleView.text = "测试功能页面" + } + + override fun initData() { + val imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + imageAdapter.setImageList(imageUrls = urls) + imageGridView.setOnItemClickListener { _, _, position, _ -> + Log.d(Tag, "点击path: ${urls[position]}") + } + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + override fun onDeleteItemClick(position: Int) { + Log.d(Tag, "删除path: ${urls[position]}") + } + }) + } + + override fun initEvent() { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt new file mode 100644 index 0000000..dd145f4 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt @@ -0,0 +1,6 @@ +package com.casic.birmm.inspect.vm + +import com.casic.birmm.inspect.base.BaseViewModel + +class NewEventViewModel : BaseViewModel() { +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt new file mode 100644 index 0000000..a7fa31b --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt @@ -0,0 +1,21 @@ +package com.casic.birmm.inspect.vm + +import androidx.lifecycle.MutableLiveData +import com.casic.birmm.inspect.base.BaseViewModel +import com.casic.birmm.inspect.extensions.launch +import com.casic.birmm.inspect.model.ActionResultModel +import com.casic.birmm.inspect.utils.LoadState +import com.casic.birmm.inspect.utils.retrofit.RetrofitServiceManager +import java.io.File + +class UploadImageViewModel : BaseViewModel() { + val resultModel = MutableLiveData() + + fun uploadImage(image: File) = launch({ + loadState.value = LoadState.Loading + resultModel.value = RetrofitServiceManager.uploadImage(image) + loadState.value = LoadState.Success + }, { + loadState.value = LoadState.Fail + }) +} \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_layout_white.xml b/app/src/main/res/drawable/bg_layout_white.xml index 19b473b..1002512 100644 --- a/app/src/main/res/drawable/bg_layout_white.xml +++ b/app/src/main/res/drawable/bg_layout_white.xml @@ -7,5 +7,5 @@ + android:color="@color/hintColor" /> \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_black.xml b/app/src/main/res/drawable/ic_add_black.xml new file mode 100644 index 0000000..4a7fb89 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_delete_black.xml b/app/src/main/res/drawable/ic_delete_black.xml new file mode 100644 index 0000000..482b166 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt index 23ed09d..df03b14 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt @@ -3,6 +3,10 @@ import com.casic.birmm.inspect.model.* import com.casic.birmm.inspect.utils.AuthenticationHelper import com.casic.birmm.inspect.utils.Constant +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File object RetrofitServiceManager { @@ -88,4 +92,13 @@ suspend fun searchByInspection(inspectionId: String): TaskRecordModel { return api.searchByInspection(AuthenticationHelper.token!!, inspectionId) } + + /** + * 上传图片 + */ + suspend fun uploadImage(image: File): ActionResultModel { + val requestBody = RequestBody.create("image/png".toMediaTypeOrNull(), image) + val imagePart = MultipartBody.Part.createFormData("file", image.name, requestBody) + return api.uploadImage(AuthenticationHelper.token!!, imagePart) + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt index 9b29ca3..fe37dc3 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt @@ -3,9 +3,8 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.GridLayoutManager import com.casic.birmm.inspect.R -import com.casic.birmm.inspect.adapter.ImageRecycleViewAdapter +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter import com.casic.birmm.inspect.base.BaseActivity import com.casic.birmm.inspect.extensions.combineImagePath import com.casic.birmm.inspect.extensions.show @@ -54,19 +53,17 @@ } } //绑定图片 - val imageAdapter = ImageRecycleViewAdapter(this, urls) - imageRecyclerView.layoutManager = GridLayoutManager(this, 2) - imageRecyclerView.adapter = imageAdapter - imageAdapter.setOnItemClickListener(object : - ImageRecycleViewAdapter.OnItemClickListener { - override fun onClick(position: Int) { - if (urls[position].isEmpty()) { - "图片加载失败,无法查看大图".show(this@EventDetailActivity) - } else { - OtherUtils.showBigImage(this@EventDetailActivity, position, urls) - } + val imageAdapter = ImageGridViewAdapter(this) + imageAdapter.setImageList(imageUrls = urls) + imageAdapter.isDeleteVisible(false) + imageGridView.adapter = imageAdapter + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (urls[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@EventDetailActivity) + } else { + OtherUtils.showBigImage(this@EventDetailActivity, position, urls) } - }) + } } else { hasImageLayout.visibility = View.GONE dataView.text = "$data.0" diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt index 207f6c3..91fb674 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.view import android.bluetooth.BluetoothAdapter +import android.content.Intent import android.graphics.Color import android.os.Bundle import android.os.Handler @@ -18,6 +19,7 @@ import com.casic.birmm.inspect.utils.PageNavigationManager import com.casic.birmm.inspect.utils.StatusBarColorUtil import com.casic.birmm.inspect.widgets.InputDialog +import com.casic.birmm.inspect.widgets.SingleChoiceDialog import com.gyf.immersionbar.ImmersionBar import com.qmuiteam.qmui.util.QMUIStatusBarHelper import kotlinx.android.synthetic.main.activity_inspect_route.mapView @@ -42,6 +44,7 @@ private lateinit var aMap: AMap private lateinit var locationStyle: MyLocationStyle + private val itemList: List = arrayListOf("报警事件", "自定义事件") init { weakReferenceHandler = WeakReferenceHandler(this) @@ -131,7 +134,25 @@ newEventButton.setChangeAlphaWhenPress(true) newEventButton.setOnClickListener { - + SingleChoiceDialog.Builder() + .setContext(this) + .setTitle("选择事件类型") + .setChoiceItemButton(itemList) + .setOnDialogClickListener(object : SingleChoiceDialog.OnDialogItemClickListener { + override fun onItemClick(position: Int) { + val intent = Intent(this@MapActivity, NewEventActivity::class.java) + when (position) { + 0 -> { + intent.putExtra("isWarning", true) + } + 1 -> { + intent.putExtra("isWarning", false) + } + } + startActivity(intent) + } + }) + .build().show() } } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt new file mode 100644 index 0000000..de3eb19 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt @@ -0,0 +1,191 @@ +package com.casic.birmm.inspect.view + +import android.app.Activity +import android.content.Intent +import android.view.View +import androidx.core.content.ContextCompat +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.aihook.alertview.library.AlertView +import com.aihook.alertview.library.OnItemClickListener +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseViewModelActivity +import com.casic.birmm.inspect.extensions.combineImagePath +import com.casic.birmm.inspect.extensions.filterString +import com.casic.birmm.inspect.extensions.show +import com.casic.birmm.inspect.utils.* +import com.casic.birmm.inspect.vm.NewEventViewModel +import com.casic.birmm.inspect.vm.UploadImageViewModel +import com.gyf.immersionbar.ImmersionBar +import com.luck.picture.lib.PictureSelector +import com.luck.picture.lib.config.PictureConfig +import com.luck.picture.lib.config.PictureMimeType +import kotlinx.android.synthetic.main.activity_new_event.* +import kotlinx.android.synthetic.main.include_base_title.* +import java.io.File + + +class NewEventActivity : BaseViewModelActivity() { + + private lateinit var uploadImageViewModel: UploadImageViewModel + private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var imageAdapter: ImageGridViewAdapter + private var isWarning: Boolean = true + + override fun createViewModelByClass(): Class? = NewEventViewModel::class.java + + override fun initLayoutView(): Int = R.layout.activity_new_event + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + } + + override fun initData() { + uploadImageViewModel = ViewModelProvider(this).get(UploadImageViewModel::class.java) + isWarning = intent.getBooleanExtra("isWarning", true) + if (isWarning) { + titleView.text = "报警事件记录" + inspectCardView.visibility = View.VISIBLE + } else { + titleView.text = "自定义事件记录" + inspectCardView.visibility = View.GONE + } + eventCreateTimeView.text = + TimeOrDateUtil.timestampToCompleteDate(System.currentTimeMillis()) + + //初始化图片九宫格 + imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + } + + override fun initEvent() { + leftBackView.setOnClickListener { this.finish() } + + addImageView.setOnClickListener { + AlertView( + "请选择图片来源", null, "取消", null, arrayOf("拍照", "相册"), + this, AlertView.Style.ActionSheet, + OnItemClickListener { _, position -> + when (position) { + 0 -> { + PictureSelector.create(this) + .openCamera(PictureMimeType.ofImage()) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .forResult(PictureConfig.REQUEST_CAMERA) + } + 1 -> { + PictureSelector.create(this) + .openGallery(PictureMimeType.ofImage()) + .isWeChatStyle(true) + .isCamera(false) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .maxSelectNum(4) + .forResult(PictureConfig.CHOOSE_REQUEST) + } + } + } + ).setCancelable(true).show() + } + uploadImageViewModel.resultModel.observe(this, Observer { model -> + if (model.code == 200) { + /** + * 显示图片 + * path: 2021-07\c670eac17d644b179a4324a34bb84329.jpeg + * */ + imageGridView.visibility = View.VISIBLE + val sumItemCount: Int = imageAdapter.count + 1 //每上传一张图片,图片总数都是在原有的基础上+1 + if (sumItemCount <= 4) { + val url = model.data + //let函数处理需要针对一个可null的对象统一做判空处理。 + url?.let { + imagePaths.add(it) + realPaths.add(it.combineImagePath()) + } + if (realPaths.size == 4) { + addImageView.visibility = View.GONE + } + imageAdapter.setImageList(imageUrls = realPaths) + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@NewEventActivity) + } else { + OtherUtils.showBigImage(this@NewEventActivity, position, realPaths) + } + } + //删除按钮点击事件 + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + @Override + override fun onDeleteItemClick(position: Int) { + imagePaths.removeAt(position) + realPaths.removeAt(position) + imageAdapter.setImageList(imageUrls = realPaths) + if (realPaths.size != 2) { + addImageView.visibility = View.VISIBLE + } + } + }) + } else { + "最多只能上传4张图片".show(this) + } + } + }) + uploadImageViewModel.loadState.observe(this, Observer { + when (it) { + is LoadState.Loading -> { + OtherUtils.showLoadingDialog(this, "图片上传中,请稍后...") + } + else -> OtherUtils.dismissLoadingDialog() + } + }) + + addEventButton.setOnClickListener { + if (eventEditTextView.text.toString().filterString().isEmpty()) { + "事件情况说明还未填写,请检查".show(this) + return@setOnClickListener + } + if (isWarning) { + if (inspectNumberView.text.toString().filterString().isEmpty()) { + "最大泄露值还未填写,请检查".show(this) + return@setOnClickListener + } + } + + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + PictureConfig.CHOOSE_REQUEST -> { + val selectResult = PictureSelector.obtainMultipleResult(data) + for (res in selectResult) { + val file = File(res.compressPath) + if (file.length() <= Constant.IMAGE_MINUS_SIZE) { + "图片尺寸太小,请重新选择".show(this) + continue + } + //上传图片 + uploadImageViewModel.uploadImage(file) + } + } + PictureConfig.REQUEST_CAMERA -> { + val cameraResult = PictureSelector.obtainMultipleResult(data)[0] + //上传图片 + uploadImageViewModel.uploadImage(File(cameraResult.compressPath)) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt index d4821de..9de8a96 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt @@ -32,6 +32,7 @@ } private fun startGuideActivity() { +// startActivity(Intent(this, TestActivity::class.java)) startActivity(Intent(this, GuideActivity::class.java)) finish() } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt new file mode 100644 index 0000000..abb6e23 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt @@ -0,0 +1,54 @@ +package com.casic.birmm.inspect.view + +import android.util.Log +import androidx.core.content.ContextCompat +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseActivity +import com.casic.birmm.inspect.utils.PageNavigationManager +import com.casic.birmm.inspect.utils.StatusBarColorUtil +import com.gyf.immersionbar.ImmersionBar +import kotlinx.android.synthetic.main.activity_test.* +import kotlinx.android.synthetic.main.include_base_title.* + +class TestActivity : BaseActivity() { + + companion object { + private const val Tag = "TestActivity" + } + + private val urls = arrayListOf( + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg" + ) + + override fun initLayoutView(): Int = R.layout.activity_test + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + titleView.text = "测试功能页面" + } + + override fun initData() { + val imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + imageAdapter.setImageList(imageUrls = urls) + imageGridView.setOnItemClickListener { _, _, position, _ -> + Log.d(Tag, "点击path: ${urls[position]}") + } + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + override fun onDeleteItemClick(position: Int) { + Log.d(Tag, "删除path: ${urls[position]}") + } + }) + } + + override fun initEvent() { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt new file mode 100644 index 0000000..dd145f4 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt @@ -0,0 +1,6 @@ +package com.casic.birmm.inspect.vm + +import com.casic.birmm.inspect.base.BaseViewModel + +class NewEventViewModel : BaseViewModel() { +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt new file mode 100644 index 0000000..a7fa31b --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt @@ -0,0 +1,21 @@ +package com.casic.birmm.inspect.vm + +import androidx.lifecycle.MutableLiveData +import com.casic.birmm.inspect.base.BaseViewModel +import com.casic.birmm.inspect.extensions.launch +import com.casic.birmm.inspect.model.ActionResultModel +import com.casic.birmm.inspect.utils.LoadState +import com.casic.birmm.inspect.utils.retrofit.RetrofitServiceManager +import java.io.File + +class UploadImageViewModel : BaseViewModel() { + val resultModel = MutableLiveData() + + fun uploadImage(image: File) = launch({ + loadState.value = LoadState.Loading + resultModel.value = RetrofitServiceManager.uploadImage(image) + loadState.value = LoadState.Success + }, { + loadState.value = LoadState.Fail + }) +} \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_layout_white.xml b/app/src/main/res/drawable/bg_layout_white.xml index 19b473b..1002512 100644 --- a/app/src/main/res/drawable/bg_layout_white.xml +++ b/app/src/main/res/drawable/bg_layout_white.xml @@ -7,5 +7,5 @@ + android:color="@color/hintColor" /> \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_black.xml b/app/src/main/res/drawable/ic_add_black.xml new file mode 100644 index 0000000..4a7fb89 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_delete_black.xml b/app/src/main/res/drawable/ic_delete_black.xml new file mode 100644 index 0000000..482b166 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_event_detail.xml b/app/src/main/res/layout/activity_event_detail.xml index 89dbc1e..1eefc6e 100644 --- a/app/src/main/res/layout/activity_event_detail.xml +++ b/app/src/main/res/layout/activity_event_detail.xml @@ -92,17 +92,21 @@ android:orientation="vertical"> - + android:layout_marginTop="@dimen/margin_10dp" + android:horizontalSpacing="@dimen/margin_10dp" + android:numColumns="3" + android:scrollbars="none" + android:verticalSpacing="@dimen/margin_10dp" /> + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt index 23ed09d..df03b14 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt @@ -3,6 +3,10 @@ import com.casic.birmm.inspect.model.* import com.casic.birmm.inspect.utils.AuthenticationHelper import com.casic.birmm.inspect.utils.Constant +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File object RetrofitServiceManager { @@ -88,4 +92,13 @@ suspend fun searchByInspection(inspectionId: String): TaskRecordModel { return api.searchByInspection(AuthenticationHelper.token!!, inspectionId) } + + /** + * 上传图片 + */ + suspend fun uploadImage(image: File): ActionResultModel { + val requestBody = RequestBody.create("image/png".toMediaTypeOrNull(), image) + val imagePart = MultipartBody.Part.createFormData("file", image.name, requestBody) + return api.uploadImage(AuthenticationHelper.token!!, imagePart) + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt index 9b29ca3..fe37dc3 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt @@ -3,9 +3,8 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.GridLayoutManager import com.casic.birmm.inspect.R -import com.casic.birmm.inspect.adapter.ImageRecycleViewAdapter +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter import com.casic.birmm.inspect.base.BaseActivity import com.casic.birmm.inspect.extensions.combineImagePath import com.casic.birmm.inspect.extensions.show @@ -54,19 +53,17 @@ } } //绑定图片 - val imageAdapter = ImageRecycleViewAdapter(this, urls) - imageRecyclerView.layoutManager = GridLayoutManager(this, 2) - imageRecyclerView.adapter = imageAdapter - imageAdapter.setOnItemClickListener(object : - ImageRecycleViewAdapter.OnItemClickListener { - override fun onClick(position: Int) { - if (urls[position].isEmpty()) { - "图片加载失败,无法查看大图".show(this@EventDetailActivity) - } else { - OtherUtils.showBigImage(this@EventDetailActivity, position, urls) - } + val imageAdapter = ImageGridViewAdapter(this) + imageAdapter.setImageList(imageUrls = urls) + imageAdapter.isDeleteVisible(false) + imageGridView.adapter = imageAdapter + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (urls[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@EventDetailActivity) + } else { + OtherUtils.showBigImage(this@EventDetailActivity, position, urls) } - }) + } } else { hasImageLayout.visibility = View.GONE dataView.text = "$data.0" diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt index 207f6c3..91fb674 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.view import android.bluetooth.BluetoothAdapter +import android.content.Intent import android.graphics.Color import android.os.Bundle import android.os.Handler @@ -18,6 +19,7 @@ import com.casic.birmm.inspect.utils.PageNavigationManager import com.casic.birmm.inspect.utils.StatusBarColorUtil import com.casic.birmm.inspect.widgets.InputDialog +import com.casic.birmm.inspect.widgets.SingleChoiceDialog import com.gyf.immersionbar.ImmersionBar import com.qmuiteam.qmui.util.QMUIStatusBarHelper import kotlinx.android.synthetic.main.activity_inspect_route.mapView @@ -42,6 +44,7 @@ private lateinit var aMap: AMap private lateinit var locationStyle: MyLocationStyle + private val itemList: List = arrayListOf("报警事件", "自定义事件") init { weakReferenceHandler = WeakReferenceHandler(this) @@ -131,7 +134,25 @@ newEventButton.setChangeAlphaWhenPress(true) newEventButton.setOnClickListener { - + SingleChoiceDialog.Builder() + .setContext(this) + .setTitle("选择事件类型") + .setChoiceItemButton(itemList) + .setOnDialogClickListener(object : SingleChoiceDialog.OnDialogItemClickListener { + override fun onItemClick(position: Int) { + val intent = Intent(this@MapActivity, NewEventActivity::class.java) + when (position) { + 0 -> { + intent.putExtra("isWarning", true) + } + 1 -> { + intent.putExtra("isWarning", false) + } + } + startActivity(intent) + } + }) + .build().show() } } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt new file mode 100644 index 0000000..de3eb19 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt @@ -0,0 +1,191 @@ +package com.casic.birmm.inspect.view + +import android.app.Activity +import android.content.Intent +import android.view.View +import androidx.core.content.ContextCompat +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.aihook.alertview.library.AlertView +import com.aihook.alertview.library.OnItemClickListener +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseViewModelActivity +import com.casic.birmm.inspect.extensions.combineImagePath +import com.casic.birmm.inspect.extensions.filterString +import com.casic.birmm.inspect.extensions.show +import com.casic.birmm.inspect.utils.* +import com.casic.birmm.inspect.vm.NewEventViewModel +import com.casic.birmm.inspect.vm.UploadImageViewModel +import com.gyf.immersionbar.ImmersionBar +import com.luck.picture.lib.PictureSelector +import com.luck.picture.lib.config.PictureConfig +import com.luck.picture.lib.config.PictureMimeType +import kotlinx.android.synthetic.main.activity_new_event.* +import kotlinx.android.synthetic.main.include_base_title.* +import java.io.File + + +class NewEventActivity : BaseViewModelActivity() { + + private lateinit var uploadImageViewModel: UploadImageViewModel + private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var imageAdapter: ImageGridViewAdapter + private var isWarning: Boolean = true + + override fun createViewModelByClass(): Class? = NewEventViewModel::class.java + + override fun initLayoutView(): Int = R.layout.activity_new_event + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + } + + override fun initData() { + uploadImageViewModel = ViewModelProvider(this).get(UploadImageViewModel::class.java) + isWarning = intent.getBooleanExtra("isWarning", true) + if (isWarning) { + titleView.text = "报警事件记录" + inspectCardView.visibility = View.VISIBLE + } else { + titleView.text = "自定义事件记录" + inspectCardView.visibility = View.GONE + } + eventCreateTimeView.text = + TimeOrDateUtil.timestampToCompleteDate(System.currentTimeMillis()) + + //初始化图片九宫格 + imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + } + + override fun initEvent() { + leftBackView.setOnClickListener { this.finish() } + + addImageView.setOnClickListener { + AlertView( + "请选择图片来源", null, "取消", null, arrayOf("拍照", "相册"), + this, AlertView.Style.ActionSheet, + OnItemClickListener { _, position -> + when (position) { + 0 -> { + PictureSelector.create(this) + .openCamera(PictureMimeType.ofImage()) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .forResult(PictureConfig.REQUEST_CAMERA) + } + 1 -> { + PictureSelector.create(this) + .openGallery(PictureMimeType.ofImage()) + .isWeChatStyle(true) + .isCamera(false) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .maxSelectNum(4) + .forResult(PictureConfig.CHOOSE_REQUEST) + } + } + } + ).setCancelable(true).show() + } + uploadImageViewModel.resultModel.observe(this, Observer { model -> + if (model.code == 200) { + /** + * 显示图片 + * path: 2021-07\c670eac17d644b179a4324a34bb84329.jpeg + * */ + imageGridView.visibility = View.VISIBLE + val sumItemCount: Int = imageAdapter.count + 1 //每上传一张图片,图片总数都是在原有的基础上+1 + if (sumItemCount <= 4) { + val url = model.data + //let函数处理需要针对一个可null的对象统一做判空处理。 + url?.let { + imagePaths.add(it) + realPaths.add(it.combineImagePath()) + } + if (realPaths.size == 4) { + addImageView.visibility = View.GONE + } + imageAdapter.setImageList(imageUrls = realPaths) + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@NewEventActivity) + } else { + OtherUtils.showBigImage(this@NewEventActivity, position, realPaths) + } + } + //删除按钮点击事件 + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + @Override + override fun onDeleteItemClick(position: Int) { + imagePaths.removeAt(position) + realPaths.removeAt(position) + imageAdapter.setImageList(imageUrls = realPaths) + if (realPaths.size != 2) { + addImageView.visibility = View.VISIBLE + } + } + }) + } else { + "最多只能上传4张图片".show(this) + } + } + }) + uploadImageViewModel.loadState.observe(this, Observer { + when (it) { + is LoadState.Loading -> { + OtherUtils.showLoadingDialog(this, "图片上传中,请稍后...") + } + else -> OtherUtils.dismissLoadingDialog() + } + }) + + addEventButton.setOnClickListener { + if (eventEditTextView.text.toString().filterString().isEmpty()) { + "事件情况说明还未填写,请检查".show(this) + return@setOnClickListener + } + if (isWarning) { + if (inspectNumberView.text.toString().filterString().isEmpty()) { + "最大泄露值还未填写,请检查".show(this) + return@setOnClickListener + } + } + + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + PictureConfig.CHOOSE_REQUEST -> { + val selectResult = PictureSelector.obtainMultipleResult(data) + for (res in selectResult) { + val file = File(res.compressPath) + if (file.length() <= Constant.IMAGE_MINUS_SIZE) { + "图片尺寸太小,请重新选择".show(this) + continue + } + //上传图片 + uploadImageViewModel.uploadImage(file) + } + } + PictureConfig.REQUEST_CAMERA -> { + val cameraResult = PictureSelector.obtainMultipleResult(data)[0] + //上传图片 + uploadImageViewModel.uploadImage(File(cameraResult.compressPath)) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt index d4821de..9de8a96 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt @@ -32,6 +32,7 @@ } private fun startGuideActivity() { +// startActivity(Intent(this, TestActivity::class.java)) startActivity(Intent(this, GuideActivity::class.java)) finish() } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt new file mode 100644 index 0000000..abb6e23 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt @@ -0,0 +1,54 @@ +package com.casic.birmm.inspect.view + +import android.util.Log +import androidx.core.content.ContextCompat +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseActivity +import com.casic.birmm.inspect.utils.PageNavigationManager +import com.casic.birmm.inspect.utils.StatusBarColorUtil +import com.gyf.immersionbar.ImmersionBar +import kotlinx.android.synthetic.main.activity_test.* +import kotlinx.android.synthetic.main.include_base_title.* + +class TestActivity : BaseActivity() { + + companion object { + private const val Tag = "TestActivity" + } + + private val urls = arrayListOf( + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg" + ) + + override fun initLayoutView(): Int = R.layout.activity_test + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + titleView.text = "测试功能页面" + } + + override fun initData() { + val imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + imageAdapter.setImageList(imageUrls = urls) + imageGridView.setOnItemClickListener { _, _, position, _ -> + Log.d(Tag, "点击path: ${urls[position]}") + } + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + override fun onDeleteItemClick(position: Int) { + Log.d(Tag, "删除path: ${urls[position]}") + } + }) + } + + override fun initEvent() { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt new file mode 100644 index 0000000..dd145f4 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt @@ -0,0 +1,6 @@ +package com.casic.birmm.inspect.vm + +import com.casic.birmm.inspect.base.BaseViewModel + +class NewEventViewModel : BaseViewModel() { +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt new file mode 100644 index 0000000..a7fa31b --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt @@ -0,0 +1,21 @@ +package com.casic.birmm.inspect.vm + +import androidx.lifecycle.MutableLiveData +import com.casic.birmm.inspect.base.BaseViewModel +import com.casic.birmm.inspect.extensions.launch +import com.casic.birmm.inspect.model.ActionResultModel +import com.casic.birmm.inspect.utils.LoadState +import com.casic.birmm.inspect.utils.retrofit.RetrofitServiceManager +import java.io.File + +class UploadImageViewModel : BaseViewModel() { + val resultModel = MutableLiveData() + + fun uploadImage(image: File) = launch({ + loadState.value = LoadState.Loading + resultModel.value = RetrofitServiceManager.uploadImage(image) + loadState.value = LoadState.Success + }, { + loadState.value = LoadState.Fail + }) +} \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_layout_white.xml b/app/src/main/res/drawable/bg_layout_white.xml index 19b473b..1002512 100644 --- a/app/src/main/res/drawable/bg_layout_white.xml +++ b/app/src/main/res/drawable/bg_layout_white.xml @@ -7,5 +7,5 @@ + android:color="@color/hintColor" /> \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_black.xml b/app/src/main/res/drawable/ic_add_black.xml new file mode 100644 index 0000000..4a7fb89 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_delete_black.xml b/app/src/main/res/drawable/ic_delete_black.xml new file mode 100644 index 0000000..482b166 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_event_detail.xml b/app/src/main/res/layout/activity_event_detail.xml index 89dbc1e..1eefc6e 100644 --- a/app/src/main/res/layout/activity_event_detail.xml +++ b/app/src/main/res/layout/activity_event_detail.xml @@ -92,17 +92,21 @@ android:orientation="vertical"> - + android:layout_marginTop="@dimen/margin_10dp" + android:horizontalSpacing="@dimen/margin_10dp" + android:numColumns="3" + android:scrollbars="none" + android:verticalSpacing="@dimen/margin_10dp" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt index 23ed09d..df03b14 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt @@ -3,6 +3,10 @@ import com.casic.birmm.inspect.model.* import com.casic.birmm.inspect.utils.AuthenticationHelper import com.casic.birmm.inspect.utils.Constant +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File object RetrofitServiceManager { @@ -88,4 +92,13 @@ suspend fun searchByInspection(inspectionId: String): TaskRecordModel { return api.searchByInspection(AuthenticationHelper.token!!, inspectionId) } + + /** + * 上传图片 + */ + suspend fun uploadImage(image: File): ActionResultModel { + val requestBody = RequestBody.create("image/png".toMediaTypeOrNull(), image) + val imagePart = MultipartBody.Part.createFormData("file", image.name, requestBody) + return api.uploadImage(AuthenticationHelper.token!!, imagePart) + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt index 9b29ca3..fe37dc3 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt @@ -3,9 +3,8 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.GridLayoutManager import com.casic.birmm.inspect.R -import com.casic.birmm.inspect.adapter.ImageRecycleViewAdapter +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter import com.casic.birmm.inspect.base.BaseActivity import com.casic.birmm.inspect.extensions.combineImagePath import com.casic.birmm.inspect.extensions.show @@ -54,19 +53,17 @@ } } //绑定图片 - val imageAdapter = ImageRecycleViewAdapter(this, urls) - imageRecyclerView.layoutManager = GridLayoutManager(this, 2) - imageRecyclerView.adapter = imageAdapter - imageAdapter.setOnItemClickListener(object : - ImageRecycleViewAdapter.OnItemClickListener { - override fun onClick(position: Int) { - if (urls[position].isEmpty()) { - "图片加载失败,无法查看大图".show(this@EventDetailActivity) - } else { - OtherUtils.showBigImage(this@EventDetailActivity, position, urls) - } + val imageAdapter = ImageGridViewAdapter(this) + imageAdapter.setImageList(imageUrls = urls) + imageAdapter.isDeleteVisible(false) + imageGridView.adapter = imageAdapter + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (urls[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@EventDetailActivity) + } else { + OtherUtils.showBigImage(this@EventDetailActivity, position, urls) } - }) + } } else { hasImageLayout.visibility = View.GONE dataView.text = "$data.0" diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt index 207f6c3..91fb674 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.view import android.bluetooth.BluetoothAdapter +import android.content.Intent import android.graphics.Color import android.os.Bundle import android.os.Handler @@ -18,6 +19,7 @@ import com.casic.birmm.inspect.utils.PageNavigationManager import com.casic.birmm.inspect.utils.StatusBarColorUtil import com.casic.birmm.inspect.widgets.InputDialog +import com.casic.birmm.inspect.widgets.SingleChoiceDialog import com.gyf.immersionbar.ImmersionBar import com.qmuiteam.qmui.util.QMUIStatusBarHelper import kotlinx.android.synthetic.main.activity_inspect_route.mapView @@ -42,6 +44,7 @@ private lateinit var aMap: AMap private lateinit var locationStyle: MyLocationStyle + private val itemList: List = arrayListOf("报警事件", "自定义事件") init { weakReferenceHandler = WeakReferenceHandler(this) @@ -131,7 +134,25 @@ newEventButton.setChangeAlphaWhenPress(true) newEventButton.setOnClickListener { - + SingleChoiceDialog.Builder() + .setContext(this) + .setTitle("选择事件类型") + .setChoiceItemButton(itemList) + .setOnDialogClickListener(object : SingleChoiceDialog.OnDialogItemClickListener { + override fun onItemClick(position: Int) { + val intent = Intent(this@MapActivity, NewEventActivity::class.java) + when (position) { + 0 -> { + intent.putExtra("isWarning", true) + } + 1 -> { + intent.putExtra("isWarning", false) + } + } + startActivity(intent) + } + }) + .build().show() } } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt new file mode 100644 index 0000000..de3eb19 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt @@ -0,0 +1,191 @@ +package com.casic.birmm.inspect.view + +import android.app.Activity +import android.content.Intent +import android.view.View +import androidx.core.content.ContextCompat +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.aihook.alertview.library.AlertView +import com.aihook.alertview.library.OnItemClickListener +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseViewModelActivity +import com.casic.birmm.inspect.extensions.combineImagePath +import com.casic.birmm.inspect.extensions.filterString +import com.casic.birmm.inspect.extensions.show +import com.casic.birmm.inspect.utils.* +import com.casic.birmm.inspect.vm.NewEventViewModel +import com.casic.birmm.inspect.vm.UploadImageViewModel +import com.gyf.immersionbar.ImmersionBar +import com.luck.picture.lib.PictureSelector +import com.luck.picture.lib.config.PictureConfig +import com.luck.picture.lib.config.PictureMimeType +import kotlinx.android.synthetic.main.activity_new_event.* +import kotlinx.android.synthetic.main.include_base_title.* +import java.io.File + + +class NewEventActivity : BaseViewModelActivity() { + + private lateinit var uploadImageViewModel: UploadImageViewModel + private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var imageAdapter: ImageGridViewAdapter + private var isWarning: Boolean = true + + override fun createViewModelByClass(): Class? = NewEventViewModel::class.java + + override fun initLayoutView(): Int = R.layout.activity_new_event + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + } + + override fun initData() { + uploadImageViewModel = ViewModelProvider(this).get(UploadImageViewModel::class.java) + isWarning = intent.getBooleanExtra("isWarning", true) + if (isWarning) { + titleView.text = "报警事件记录" + inspectCardView.visibility = View.VISIBLE + } else { + titleView.text = "自定义事件记录" + inspectCardView.visibility = View.GONE + } + eventCreateTimeView.text = + TimeOrDateUtil.timestampToCompleteDate(System.currentTimeMillis()) + + //初始化图片九宫格 + imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + } + + override fun initEvent() { + leftBackView.setOnClickListener { this.finish() } + + addImageView.setOnClickListener { + AlertView( + "请选择图片来源", null, "取消", null, arrayOf("拍照", "相册"), + this, AlertView.Style.ActionSheet, + OnItemClickListener { _, position -> + when (position) { + 0 -> { + PictureSelector.create(this) + .openCamera(PictureMimeType.ofImage()) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .forResult(PictureConfig.REQUEST_CAMERA) + } + 1 -> { + PictureSelector.create(this) + .openGallery(PictureMimeType.ofImage()) + .isWeChatStyle(true) + .isCamera(false) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .maxSelectNum(4) + .forResult(PictureConfig.CHOOSE_REQUEST) + } + } + } + ).setCancelable(true).show() + } + uploadImageViewModel.resultModel.observe(this, Observer { model -> + if (model.code == 200) { + /** + * 显示图片 + * path: 2021-07\c670eac17d644b179a4324a34bb84329.jpeg + * */ + imageGridView.visibility = View.VISIBLE + val sumItemCount: Int = imageAdapter.count + 1 //每上传一张图片,图片总数都是在原有的基础上+1 + if (sumItemCount <= 4) { + val url = model.data + //let函数处理需要针对一个可null的对象统一做判空处理。 + url?.let { + imagePaths.add(it) + realPaths.add(it.combineImagePath()) + } + if (realPaths.size == 4) { + addImageView.visibility = View.GONE + } + imageAdapter.setImageList(imageUrls = realPaths) + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@NewEventActivity) + } else { + OtherUtils.showBigImage(this@NewEventActivity, position, realPaths) + } + } + //删除按钮点击事件 + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + @Override + override fun onDeleteItemClick(position: Int) { + imagePaths.removeAt(position) + realPaths.removeAt(position) + imageAdapter.setImageList(imageUrls = realPaths) + if (realPaths.size != 2) { + addImageView.visibility = View.VISIBLE + } + } + }) + } else { + "最多只能上传4张图片".show(this) + } + } + }) + uploadImageViewModel.loadState.observe(this, Observer { + when (it) { + is LoadState.Loading -> { + OtherUtils.showLoadingDialog(this, "图片上传中,请稍后...") + } + else -> OtherUtils.dismissLoadingDialog() + } + }) + + addEventButton.setOnClickListener { + if (eventEditTextView.text.toString().filterString().isEmpty()) { + "事件情况说明还未填写,请检查".show(this) + return@setOnClickListener + } + if (isWarning) { + if (inspectNumberView.text.toString().filterString().isEmpty()) { + "最大泄露值还未填写,请检查".show(this) + return@setOnClickListener + } + } + + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + PictureConfig.CHOOSE_REQUEST -> { + val selectResult = PictureSelector.obtainMultipleResult(data) + for (res in selectResult) { + val file = File(res.compressPath) + if (file.length() <= Constant.IMAGE_MINUS_SIZE) { + "图片尺寸太小,请重新选择".show(this) + continue + } + //上传图片 + uploadImageViewModel.uploadImage(file) + } + } + PictureConfig.REQUEST_CAMERA -> { + val cameraResult = PictureSelector.obtainMultipleResult(data)[0] + //上传图片 + uploadImageViewModel.uploadImage(File(cameraResult.compressPath)) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt index d4821de..9de8a96 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt @@ -32,6 +32,7 @@ } private fun startGuideActivity() { +// startActivity(Intent(this, TestActivity::class.java)) startActivity(Intent(this, GuideActivity::class.java)) finish() } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt new file mode 100644 index 0000000..abb6e23 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt @@ -0,0 +1,54 @@ +package com.casic.birmm.inspect.view + +import android.util.Log +import androidx.core.content.ContextCompat +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseActivity +import com.casic.birmm.inspect.utils.PageNavigationManager +import com.casic.birmm.inspect.utils.StatusBarColorUtil +import com.gyf.immersionbar.ImmersionBar +import kotlinx.android.synthetic.main.activity_test.* +import kotlinx.android.synthetic.main.include_base_title.* + +class TestActivity : BaseActivity() { + + companion object { + private const val Tag = "TestActivity" + } + + private val urls = arrayListOf( + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg" + ) + + override fun initLayoutView(): Int = R.layout.activity_test + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + titleView.text = "测试功能页面" + } + + override fun initData() { + val imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + imageAdapter.setImageList(imageUrls = urls) + imageGridView.setOnItemClickListener { _, _, position, _ -> + Log.d(Tag, "点击path: ${urls[position]}") + } + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + override fun onDeleteItemClick(position: Int) { + Log.d(Tag, "删除path: ${urls[position]}") + } + }) + } + + override fun initEvent() { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt new file mode 100644 index 0000000..dd145f4 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt @@ -0,0 +1,6 @@ +package com.casic.birmm.inspect.vm + +import com.casic.birmm.inspect.base.BaseViewModel + +class NewEventViewModel : BaseViewModel() { +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt new file mode 100644 index 0000000..a7fa31b --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt @@ -0,0 +1,21 @@ +package com.casic.birmm.inspect.vm + +import androidx.lifecycle.MutableLiveData +import com.casic.birmm.inspect.base.BaseViewModel +import com.casic.birmm.inspect.extensions.launch +import com.casic.birmm.inspect.model.ActionResultModel +import com.casic.birmm.inspect.utils.LoadState +import com.casic.birmm.inspect.utils.retrofit.RetrofitServiceManager +import java.io.File + +class UploadImageViewModel : BaseViewModel() { + val resultModel = MutableLiveData() + + fun uploadImage(image: File) = launch({ + loadState.value = LoadState.Loading + resultModel.value = RetrofitServiceManager.uploadImage(image) + loadState.value = LoadState.Success + }, { + loadState.value = LoadState.Fail + }) +} \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_layout_white.xml b/app/src/main/res/drawable/bg_layout_white.xml index 19b473b..1002512 100644 --- a/app/src/main/res/drawable/bg_layout_white.xml +++ b/app/src/main/res/drawable/bg_layout_white.xml @@ -7,5 +7,5 @@ + android:color="@color/hintColor" /> \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_black.xml b/app/src/main/res/drawable/ic_add_black.xml new file mode 100644 index 0000000..4a7fb89 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_delete_black.xml b/app/src/main/res/drawable/ic_delete_black.xml new file mode 100644 index 0000000..482b166 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_event_detail.xml b/app/src/main/res/layout/activity_event_detail.xml index 89dbc1e..1eefc6e 100644 --- a/app/src/main/res/layout/activity_event_detail.xml +++ b/app/src/main/res/layout/activity_event_detail.xml @@ -92,17 +92,21 @@ android:orientation="vertical"> - + android:layout_marginTop="@dimen/margin_10dp" + android:horizontalSpacing="@dimen/margin_10dp" + android:numColumns="3" + android:scrollbars="none" + android:verticalSpacing="@dimen/margin_10dp" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_test.xml b/app/src/main/res/layout/activity_test.xml new file mode 100644 index 0000000..066d6dd --- /dev/null +++ b/app/src/main/res/layout/activity_test.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt index 23ed09d..df03b14 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt @@ -3,6 +3,10 @@ import com.casic.birmm.inspect.model.* import com.casic.birmm.inspect.utils.AuthenticationHelper import com.casic.birmm.inspect.utils.Constant +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File object RetrofitServiceManager { @@ -88,4 +92,13 @@ suspend fun searchByInspection(inspectionId: String): TaskRecordModel { return api.searchByInspection(AuthenticationHelper.token!!, inspectionId) } + + /** + * 上传图片 + */ + suspend fun uploadImage(image: File): ActionResultModel { + val requestBody = RequestBody.create("image/png".toMediaTypeOrNull(), image) + val imagePart = MultipartBody.Part.createFormData("file", image.name, requestBody) + return api.uploadImage(AuthenticationHelper.token!!, imagePart) + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt index 9b29ca3..fe37dc3 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt @@ -3,9 +3,8 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.GridLayoutManager import com.casic.birmm.inspect.R -import com.casic.birmm.inspect.adapter.ImageRecycleViewAdapter +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter import com.casic.birmm.inspect.base.BaseActivity import com.casic.birmm.inspect.extensions.combineImagePath import com.casic.birmm.inspect.extensions.show @@ -54,19 +53,17 @@ } } //绑定图片 - val imageAdapter = ImageRecycleViewAdapter(this, urls) - imageRecyclerView.layoutManager = GridLayoutManager(this, 2) - imageRecyclerView.adapter = imageAdapter - imageAdapter.setOnItemClickListener(object : - ImageRecycleViewAdapter.OnItemClickListener { - override fun onClick(position: Int) { - if (urls[position].isEmpty()) { - "图片加载失败,无法查看大图".show(this@EventDetailActivity) - } else { - OtherUtils.showBigImage(this@EventDetailActivity, position, urls) - } + val imageAdapter = ImageGridViewAdapter(this) + imageAdapter.setImageList(imageUrls = urls) + imageAdapter.isDeleteVisible(false) + imageGridView.adapter = imageAdapter + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (urls[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@EventDetailActivity) + } else { + OtherUtils.showBigImage(this@EventDetailActivity, position, urls) } - }) + } } else { hasImageLayout.visibility = View.GONE dataView.text = "$data.0" diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt index 207f6c3..91fb674 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.view import android.bluetooth.BluetoothAdapter +import android.content.Intent import android.graphics.Color import android.os.Bundle import android.os.Handler @@ -18,6 +19,7 @@ import com.casic.birmm.inspect.utils.PageNavigationManager import com.casic.birmm.inspect.utils.StatusBarColorUtil import com.casic.birmm.inspect.widgets.InputDialog +import com.casic.birmm.inspect.widgets.SingleChoiceDialog import com.gyf.immersionbar.ImmersionBar import com.qmuiteam.qmui.util.QMUIStatusBarHelper import kotlinx.android.synthetic.main.activity_inspect_route.mapView @@ -42,6 +44,7 @@ private lateinit var aMap: AMap private lateinit var locationStyle: MyLocationStyle + private val itemList: List = arrayListOf("报警事件", "自定义事件") init { weakReferenceHandler = WeakReferenceHandler(this) @@ -131,7 +134,25 @@ newEventButton.setChangeAlphaWhenPress(true) newEventButton.setOnClickListener { - + SingleChoiceDialog.Builder() + .setContext(this) + .setTitle("选择事件类型") + .setChoiceItemButton(itemList) + .setOnDialogClickListener(object : SingleChoiceDialog.OnDialogItemClickListener { + override fun onItemClick(position: Int) { + val intent = Intent(this@MapActivity, NewEventActivity::class.java) + when (position) { + 0 -> { + intent.putExtra("isWarning", true) + } + 1 -> { + intent.putExtra("isWarning", false) + } + } + startActivity(intent) + } + }) + .build().show() } } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt new file mode 100644 index 0000000..de3eb19 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt @@ -0,0 +1,191 @@ +package com.casic.birmm.inspect.view + +import android.app.Activity +import android.content.Intent +import android.view.View +import androidx.core.content.ContextCompat +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.aihook.alertview.library.AlertView +import com.aihook.alertview.library.OnItemClickListener +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseViewModelActivity +import com.casic.birmm.inspect.extensions.combineImagePath +import com.casic.birmm.inspect.extensions.filterString +import com.casic.birmm.inspect.extensions.show +import com.casic.birmm.inspect.utils.* +import com.casic.birmm.inspect.vm.NewEventViewModel +import com.casic.birmm.inspect.vm.UploadImageViewModel +import com.gyf.immersionbar.ImmersionBar +import com.luck.picture.lib.PictureSelector +import com.luck.picture.lib.config.PictureConfig +import com.luck.picture.lib.config.PictureMimeType +import kotlinx.android.synthetic.main.activity_new_event.* +import kotlinx.android.synthetic.main.include_base_title.* +import java.io.File + + +class NewEventActivity : BaseViewModelActivity() { + + private lateinit var uploadImageViewModel: UploadImageViewModel + private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var imageAdapter: ImageGridViewAdapter + private var isWarning: Boolean = true + + override fun createViewModelByClass(): Class? = NewEventViewModel::class.java + + override fun initLayoutView(): Int = R.layout.activity_new_event + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + } + + override fun initData() { + uploadImageViewModel = ViewModelProvider(this).get(UploadImageViewModel::class.java) + isWarning = intent.getBooleanExtra("isWarning", true) + if (isWarning) { + titleView.text = "报警事件记录" + inspectCardView.visibility = View.VISIBLE + } else { + titleView.text = "自定义事件记录" + inspectCardView.visibility = View.GONE + } + eventCreateTimeView.text = + TimeOrDateUtil.timestampToCompleteDate(System.currentTimeMillis()) + + //初始化图片九宫格 + imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + } + + override fun initEvent() { + leftBackView.setOnClickListener { this.finish() } + + addImageView.setOnClickListener { + AlertView( + "请选择图片来源", null, "取消", null, arrayOf("拍照", "相册"), + this, AlertView.Style.ActionSheet, + OnItemClickListener { _, position -> + when (position) { + 0 -> { + PictureSelector.create(this) + .openCamera(PictureMimeType.ofImage()) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .forResult(PictureConfig.REQUEST_CAMERA) + } + 1 -> { + PictureSelector.create(this) + .openGallery(PictureMimeType.ofImage()) + .isWeChatStyle(true) + .isCamera(false) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .maxSelectNum(4) + .forResult(PictureConfig.CHOOSE_REQUEST) + } + } + } + ).setCancelable(true).show() + } + uploadImageViewModel.resultModel.observe(this, Observer { model -> + if (model.code == 200) { + /** + * 显示图片 + * path: 2021-07\c670eac17d644b179a4324a34bb84329.jpeg + * */ + imageGridView.visibility = View.VISIBLE + val sumItemCount: Int = imageAdapter.count + 1 //每上传一张图片,图片总数都是在原有的基础上+1 + if (sumItemCount <= 4) { + val url = model.data + //let函数处理需要针对一个可null的对象统一做判空处理。 + url?.let { + imagePaths.add(it) + realPaths.add(it.combineImagePath()) + } + if (realPaths.size == 4) { + addImageView.visibility = View.GONE + } + imageAdapter.setImageList(imageUrls = realPaths) + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@NewEventActivity) + } else { + OtherUtils.showBigImage(this@NewEventActivity, position, realPaths) + } + } + //删除按钮点击事件 + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + @Override + override fun onDeleteItemClick(position: Int) { + imagePaths.removeAt(position) + realPaths.removeAt(position) + imageAdapter.setImageList(imageUrls = realPaths) + if (realPaths.size != 2) { + addImageView.visibility = View.VISIBLE + } + } + }) + } else { + "最多只能上传4张图片".show(this) + } + } + }) + uploadImageViewModel.loadState.observe(this, Observer { + when (it) { + is LoadState.Loading -> { + OtherUtils.showLoadingDialog(this, "图片上传中,请稍后...") + } + else -> OtherUtils.dismissLoadingDialog() + } + }) + + addEventButton.setOnClickListener { + if (eventEditTextView.text.toString().filterString().isEmpty()) { + "事件情况说明还未填写,请检查".show(this) + return@setOnClickListener + } + if (isWarning) { + if (inspectNumberView.text.toString().filterString().isEmpty()) { + "最大泄露值还未填写,请检查".show(this) + return@setOnClickListener + } + } + + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + PictureConfig.CHOOSE_REQUEST -> { + val selectResult = PictureSelector.obtainMultipleResult(data) + for (res in selectResult) { + val file = File(res.compressPath) + if (file.length() <= Constant.IMAGE_MINUS_SIZE) { + "图片尺寸太小,请重新选择".show(this) + continue + } + //上传图片 + uploadImageViewModel.uploadImage(file) + } + } + PictureConfig.REQUEST_CAMERA -> { + val cameraResult = PictureSelector.obtainMultipleResult(data)[0] + //上传图片 + uploadImageViewModel.uploadImage(File(cameraResult.compressPath)) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt index d4821de..9de8a96 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt @@ -32,6 +32,7 @@ } private fun startGuideActivity() { +// startActivity(Intent(this, TestActivity::class.java)) startActivity(Intent(this, GuideActivity::class.java)) finish() } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt new file mode 100644 index 0000000..abb6e23 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt @@ -0,0 +1,54 @@ +package com.casic.birmm.inspect.view + +import android.util.Log +import androidx.core.content.ContextCompat +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseActivity +import com.casic.birmm.inspect.utils.PageNavigationManager +import com.casic.birmm.inspect.utils.StatusBarColorUtil +import com.gyf.immersionbar.ImmersionBar +import kotlinx.android.synthetic.main.activity_test.* +import kotlinx.android.synthetic.main.include_base_title.* + +class TestActivity : BaseActivity() { + + companion object { + private const val Tag = "TestActivity" + } + + private val urls = arrayListOf( + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg" + ) + + override fun initLayoutView(): Int = R.layout.activity_test + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + titleView.text = "测试功能页面" + } + + override fun initData() { + val imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + imageAdapter.setImageList(imageUrls = urls) + imageGridView.setOnItemClickListener { _, _, position, _ -> + Log.d(Tag, "点击path: ${urls[position]}") + } + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + override fun onDeleteItemClick(position: Int) { + Log.d(Tag, "删除path: ${urls[position]}") + } + }) + } + + override fun initEvent() { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt new file mode 100644 index 0000000..dd145f4 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt @@ -0,0 +1,6 @@ +package com.casic.birmm.inspect.vm + +import com.casic.birmm.inspect.base.BaseViewModel + +class NewEventViewModel : BaseViewModel() { +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt new file mode 100644 index 0000000..a7fa31b --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt @@ -0,0 +1,21 @@ +package com.casic.birmm.inspect.vm + +import androidx.lifecycle.MutableLiveData +import com.casic.birmm.inspect.base.BaseViewModel +import com.casic.birmm.inspect.extensions.launch +import com.casic.birmm.inspect.model.ActionResultModel +import com.casic.birmm.inspect.utils.LoadState +import com.casic.birmm.inspect.utils.retrofit.RetrofitServiceManager +import java.io.File + +class UploadImageViewModel : BaseViewModel() { + val resultModel = MutableLiveData() + + fun uploadImage(image: File) = launch({ + loadState.value = LoadState.Loading + resultModel.value = RetrofitServiceManager.uploadImage(image) + loadState.value = LoadState.Success + }, { + loadState.value = LoadState.Fail + }) +} \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_layout_white.xml b/app/src/main/res/drawable/bg_layout_white.xml index 19b473b..1002512 100644 --- a/app/src/main/res/drawable/bg_layout_white.xml +++ b/app/src/main/res/drawable/bg_layout_white.xml @@ -7,5 +7,5 @@ + android:color="@color/hintColor" /> \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_black.xml b/app/src/main/res/drawable/ic_add_black.xml new file mode 100644 index 0000000..4a7fb89 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_delete_black.xml b/app/src/main/res/drawable/ic_delete_black.xml new file mode 100644 index 0000000..482b166 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_event_detail.xml b/app/src/main/res/layout/activity_event_detail.xml index 89dbc1e..1eefc6e 100644 --- a/app/src/main/res/layout/activity_event_detail.xml +++ b/app/src/main/res/layout/activity_event_detail.xml @@ -92,17 +92,21 @@ android:orientation="vertical"> - + android:layout_marginTop="@dimen/margin_10dp" + android:horizontalSpacing="@dimen/margin_10dp" + android:numColumns="3" + android:scrollbars="none" + android:verticalSpacing="@dimen/margin_10dp" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_test.xml b/app/src/main/res/layout/activity_test.xml new file mode 100644 index 0000000..066d6dd --- /dev/null +++ b/app/src/main/res/layout/activity_test.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_user_settings.xml b/app/src/main/res/layout/activity_user_settings.xml index e6f0e59..d5541c1 100644 --- a/app/src/main/res/layout/activity_user_settings.xml +++ b/app/src/main/res/layout/activity_user_settings.xml @@ -124,7 +124,7 @@ android:layout_marginHorizontal="30dp" android:layout_marginBottom="30dp" android:paddingVertical="7dp" - android:text="退\u3000\u3000出" + android:text="退出登录" android:textColor="@color/white" android:textSize="@dimen/titleFontSize" app:qmui_backgroundColor="@color/mainThemeColor" diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt index 23ed09d..df03b14 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt @@ -3,6 +3,10 @@ import com.casic.birmm.inspect.model.* import com.casic.birmm.inspect.utils.AuthenticationHelper import com.casic.birmm.inspect.utils.Constant +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File object RetrofitServiceManager { @@ -88,4 +92,13 @@ suspend fun searchByInspection(inspectionId: String): TaskRecordModel { return api.searchByInspection(AuthenticationHelper.token!!, inspectionId) } + + /** + * 上传图片 + */ + suspend fun uploadImage(image: File): ActionResultModel { + val requestBody = RequestBody.create("image/png".toMediaTypeOrNull(), image) + val imagePart = MultipartBody.Part.createFormData("file", image.name, requestBody) + return api.uploadImage(AuthenticationHelper.token!!, imagePart) + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt index 9b29ca3..fe37dc3 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt @@ -3,9 +3,8 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.GridLayoutManager import com.casic.birmm.inspect.R -import com.casic.birmm.inspect.adapter.ImageRecycleViewAdapter +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter import com.casic.birmm.inspect.base.BaseActivity import com.casic.birmm.inspect.extensions.combineImagePath import com.casic.birmm.inspect.extensions.show @@ -54,19 +53,17 @@ } } //绑定图片 - val imageAdapter = ImageRecycleViewAdapter(this, urls) - imageRecyclerView.layoutManager = GridLayoutManager(this, 2) - imageRecyclerView.adapter = imageAdapter - imageAdapter.setOnItemClickListener(object : - ImageRecycleViewAdapter.OnItemClickListener { - override fun onClick(position: Int) { - if (urls[position].isEmpty()) { - "图片加载失败,无法查看大图".show(this@EventDetailActivity) - } else { - OtherUtils.showBigImage(this@EventDetailActivity, position, urls) - } + val imageAdapter = ImageGridViewAdapter(this) + imageAdapter.setImageList(imageUrls = urls) + imageAdapter.isDeleteVisible(false) + imageGridView.adapter = imageAdapter + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (urls[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@EventDetailActivity) + } else { + OtherUtils.showBigImage(this@EventDetailActivity, position, urls) } - }) + } } else { hasImageLayout.visibility = View.GONE dataView.text = "$data.0" diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt index 207f6c3..91fb674 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.view import android.bluetooth.BluetoothAdapter +import android.content.Intent import android.graphics.Color import android.os.Bundle import android.os.Handler @@ -18,6 +19,7 @@ import com.casic.birmm.inspect.utils.PageNavigationManager import com.casic.birmm.inspect.utils.StatusBarColorUtil import com.casic.birmm.inspect.widgets.InputDialog +import com.casic.birmm.inspect.widgets.SingleChoiceDialog import com.gyf.immersionbar.ImmersionBar import com.qmuiteam.qmui.util.QMUIStatusBarHelper import kotlinx.android.synthetic.main.activity_inspect_route.mapView @@ -42,6 +44,7 @@ private lateinit var aMap: AMap private lateinit var locationStyle: MyLocationStyle + private val itemList: List = arrayListOf("报警事件", "自定义事件") init { weakReferenceHandler = WeakReferenceHandler(this) @@ -131,7 +134,25 @@ newEventButton.setChangeAlphaWhenPress(true) newEventButton.setOnClickListener { - + SingleChoiceDialog.Builder() + .setContext(this) + .setTitle("选择事件类型") + .setChoiceItemButton(itemList) + .setOnDialogClickListener(object : SingleChoiceDialog.OnDialogItemClickListener { + override fun onItemClick(position: Int) { + val intent = Intent(this@MapActivity, NewEventActivity::class.java) + when (position) { + 0 -> { + intent.putExtra("isWarning", true) + } + 1 -> { + intent.putExtra("isWarning", false) + } + } + startActivity(intent) + } + }) + .build().show() } } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt new file mode 100644 index 0000000..de3eb19 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt @@ -0,0 +1,191 @@ +package com.casic.birmm.inspect.view + +import android.app.Activity +import android.content.Intent +import android.view.View +import androidx.core.content.ContextCompat +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.aihook.alertview.library.AlertView +import com.aihook.alertview.library.OnItemClickListener +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseViewModelActivity +import com.casic.birmm.inspect.extensions.combineImagePath +import com.casic.birmm.inspect.extensions.filterString +import com.casic.birmm.inspect.extensions.show +import com.casic.birmm.inspect.utils.* +import com.casic.birmm.inspect.vm.NewEventViewModel +import com.casic.birmm.inspect.vm.UploadImageViewModel +import com.gyf.immersionbar.ImmersionBar +import com.luck.picture.lib.PictureSelector +import com.luck.picture.lib.config.PictureConfig +import com.luck.picture.lib.config.PictureMimeType +import kotlinx.android.synthetic.main.activity_new_event.* +import kotlinx.android.synthetic.main.include_base_title.* +import java.io.File + + +class NewEventActivity : BaseViewModelActivity() { + + private lateinit var uploadImageViewModel: UploadImageViewModel + private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var imageAdapter: ImageGridViewAdapter + private var isWarning: Boolean = true + + override fun createViewModelByClass(): Class? = NewEventViewModel::class.java + + override fun initLayoutView(): Int = R.layout.activity_new_event + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + } + + override fun initData() { + uploadImageViewModel = ViewModelProvider(this).get(UploadImageViewModel::class.java) + isWarning = intent.getBooleanExtra("isWarning", true) + if (isWarning) { + titleView.text = "报警事件记录" + inspectCardView.visibility = View.VISIBLE + } else { + titleView.text = "自定义事件记录" + inspectCardView.visibility = View.GONE + } + eventCreateTimeView.text = + TimeOrDateUtil.timestampToCompleteDate(System.currentTimeMillis()) + + //初始化图片九宫格 + imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + } + + override fun initEvent() { + leftBackView.setOnClickListener { this.finish() } + + addImageView.setOnClickListener { + AlertView( + "请选择图片来源", null, "取消", null, arrayOf("拍照", "相册"), + this, AlertView.Style.ActionSheet, + OnItemClickListener { _, position -> + when (position) { + 0 -> { + PictureSelector.create(this) + .openCamera(PictureMimeType.ofImage()) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .forResult(PictureConfig.REQUEST_CAMERA) + } + 1 -> { + PictureSelector.create(this) + .openGallery(PictureMimeType.ofImage()) + .isWeChatStyle(true) + .isCamera(false) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .maxSelectNum(4) + .forResult(PictureConfig.CHOOSE_REQUEST) + } + } + } + ).setCancelable(true).show() + } + uploadImageViewModel.resultModel.observe(this, Observer { model -> + if (model.code == 200) { + /** + * 显示图片 + * path: 2021-07\c670eac17d644b179a4324a34bb84329.jpeg + * */ + imageGridView.visibility = View.VISIBLE + val sumItemCount: Int = imageAdapter.count + 1 //每上传一张图片,图片总数都是在原有的基础上+1 + if (sumItemCount <= 4) { + val url = model.data + //let函数处理需要针对一个可null的对象统一做判空处理。 + url?.let { + imagePaths.add(it) + realPaths.add(it.combineImagePath()) + } + if (realPaths.size == 4) { + addImageView.visibility = View.GONE + } + imageAdapter.setImageList(imageUrls = realPaths) + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@NewEventActivity) + } else { + OtherUtils.showBigImage(this@NewEventActivity, position, realPaths) + } + } + //删除按钮点击事件 + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + @Override + override fun onDeleteItemClick(position: Int) { + imagePaths.removeAt(position) + realPaths.removeAt(position) + imageAdapter.setImageList(imageUrls = realPaths) + if (realPaths.size != 2) { + addImageView.visibility = View.VISIBLE + } + } + }) + } else { + "最多只能上传4张图片".show(this) + } + } + }) + uploadImageViewModel.loadState.observe(this, Observer { + when (it) { + is LoadState.Loading -> { + OtherUtils.showLoadingDialog(this, "图片上传中,请稍后...") + } + else -> OtherUtils.dismissLoadingDialog() + } + }) + + addEventButton.setOnClickListener { + if (eventEditTextView.text.toString().filterString().isEmpty()) { + "事件情况说明还未填写,请检查".show(this) + return@setOnClickListener + } + if (isWarning) { + if (inspectNumberView.text.toString().filterString().isEmpty()) { + "最大泄露值还未填写,请检查".show(this) + return@setOnClickListener + } + } + + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + PictureConfig.CHOOSE_REQUEST -> { + val selectResult = PictureSelector.obtainMultipleResult(data) + for (res in selectResult) { + val file = File(res.compressPath) + if (file.length() <= Constant.IMAGE_MINUS_SIZE) { + "图片尺寸太小,请重新选择".show(this) + continue + } + //上传图片 + uploadImageViewModel.uploadImage(file) + } + } + PictureConfig.REQUEST_CAMERA -> { + val cameraResult = PictureSelector.obtainMultipleResult(data)[0] + //上传图片 + uploadImageViewModel.uploadImage(File(cameraResult.compressPath)) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt index d4821de..9de8a96 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt @@ -32,6 +32,7 @@ } private fun startGuideActivity() { +// startActivity(Intent(this, TestActivity::class.java)) startActivity(Intent(this, GuideActivity::class.java)) finish() } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt new file mode 100644 index 0000000..abb6e23 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt @@ -0,0 +1,54 @@ +package com.casic.birmm.inspect.view + +import android.util.Log +import androidx.core.content.ContextCompat +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseActivity +import com.casic.birmm.inspect.utils.PageNavigationManager +import com.casic.birmm.inspect.utils.StatusBarColorUtil +import com.gyf.immersionbar.ImmersionBar +import kotlinx.android.synthetic.main.activity_test.* +import kotlinx.android.synthetic.main.include_base_title.* + +class TestActivity : BaseActivity() { + + companion object { + private const val Tag = "TestActivity" + } + + private val urls = arrayListOf( + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg" + ) + + override fun initLayoutView(): Int = R.layout.activity_test + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + titleView.text = "测试功能页面" + } + + override fun initData() { + val imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + imageAdapter.setImageList(imageUrls = urls) + imageGridView.setOnItemClickListener { _, _, position, _ -> + Log.d(Tag, "点击path: ${urls[position]}") + } + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + override fun onDeleteItemClick(position: Int) { + Log.d(Tag, "删除path: ${urls[position]}") + } + }) + } + + override fun initEvent() { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt new file mode 100644 index 0000000..dd145f4 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt @@ -0,0 +1,6 @@ +package com.casic.birmm.inspect.vm + +import com.casic.birmm.inspect.base.BaseViewModel + +class NewEventViewModel : BaseViewModel() { +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt new file mode 100644 index 0000000..a7fa31b --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt @@ -0,0 +1,21 @@ +package com.casic.birmm.inspect.vm + +import androidx.lifecycle.MutableLiveData +import com.casic.birmm.inspect.base.BaseViewModel +import com.casic.birmm.inspect.extensions.launch +import com.casic.birmm.inspect.model.ActionResultModel +import com.casic.birmm.inspect.utils.LoadState +import com.casic.birmm.inspect.utils.retrofit.RetrofitServiceManager +import java.io.File + +class UploadImageViewModel : BaseViewModel() { + val resultModel = MutableLiveData() + + fun uploadImage(image: File) = launch({ + loadState.value = LoadState.Loading + resultModel.value = RetrofitServiceManager.uploadImage(image) + loadState.value = LoadState.Success + }, { + loadState.value = LoadState.Fail + }) +} \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_layout_white.xml b/app/src/main/res/drawable/bg_layout_white.xml index 19b473b..1002512 100644 --- a/app/src/main/res/drawable/bg_layout_white.xml +++ b/app/src/main/res/drawable/bg_layout_white.xml @@ -7,5 +7,5 @@ + android:color="@color/hintColor" /> \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_black.xml b/app/src/main/res/drawable/ic_add_black.xml new file mode 100644 index 0000000..4a7fb89 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_delete_black.xml b/app/src/main/res/drawable/ic_delete_black.xml new file mode 100644 index 0000000..482b166 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_event_detail.xml b/app/src/main/res/layout/activity_event_detail.xml index 89dbc1e..1eefc6e 100644 --- a/app/src/main/res/layout/activity_event_detail.xml +++ b/app/src/main/res/layout/activity_event_detail.xml @@ -92,17 +92,21 @@ android:orientation="vertical"> - + android:layout_marginTop="@dimen/margin_10dp" + android:horizontalSpacing="@dimen/margin_10dp" + android:numColumns="3" + android:scrollbars="none" + android:verticalSpacing="@dimen/margin_10dp" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_test.xml b/app/src/main/res/layout/activity_test.xml new file mode 100644 index 0000000..066d6dd --- /dev/null +++ b/app/src/main/res/layout/activity_test.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_user_settings.xml b/app/src/main/res/layout/activity_user_settings.xml index e6f0e59..d5541c1 100644 --- a/app/src/main/res/layout/activity_user_settings.xml +++ b/app/src/main/res/layout/activity_user_settings.xml @@ -124,7 +124,7 @@ android:layout_marginHorizontal="30dp" android:layout_marginBottom="30dp" android:paddingVertical="7dp" - android:text="退\u3000\u3000出" + android:text="退出登录" android:textColor="@color/white" android:textSize="@dimen/titleFontSize" app:qmui_backgroundColor="@color/mainThemeColor" diff --git a/app/src/main/res/layout/item_image_gridview.xml b/app/src/main/res/layout/item_image_gridview.xml index 84868e0..f858d5f 100644 --- a/app/src/main/res/layout/item_image_gridview.xml +++ b/app/src/main/res/layout/item_image_gridview.xml @@ -1,12 +1,19 @@ - + android:layout_height="wrap_content"> - \ No newline at end of file + android:layout_width="110dp" + android:layout_height="110dp" + android:layout_gravity="center" + android:scaleType="centerCrop" /> + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt index 23ed09d..df03b14 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt @@ -3,6 +3,10 @@ import com.casic.birmm.inspect.model.* import com.casic.birmm.inspect.utils.AuthenticationHelper import com.casic.birmm.inspect.utils.Constant +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File object RetrofitServiceManager { @@ -88,4 +92,13 @@ suspend fun searchByInspection(inspectionId: String): TaskRecordModel { return api.searchByInspection(AuthenticationHelper.token!!, inspectionId) } + + /** + * 上传图片 + */ + suspend fun uploadImage(image: File): ActionResultModel { + val requestBody = RequestBody.create("image/png".toMediaTypeOrNull(), image) + val imagePart = MultipartBody.Part.createFormData("file", image.name, requestBody) + return api.uploadImage(AuthenticationHelper.token!!, imagePart) + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt index 9b29ca3..fe37dc3 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt @@ -3,9 +3,8 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.GridLayoutManager import com.casic.birmm.inspect.R -import com.casic.birmm.inspect.adapter.ImageRecycleViewAdapter +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter import com.casic.birmm.inspect.base.BaseActivity import com.casic.birmm.inspect.extensions.combineImagePath import com.casic.birmm.inspect.extensions.show @@ -54,19 +53,17 @@ } } //绑定图片 - val imageAdapter = ImageRecycleViewAdapter(this, urls) - imageRecyclerView.layoutManager = GridLayoutManager(this, 2) - imageRecyclerView.adapter = imageAdapter - imageAdapter.setOnItemClickListener(object : - ImageRecycleViewAdapter.OnItemClickListener { - override fun onClick(position: Int) { - if (urls[position].isEmpty()) { - "图片加载失败,无法查看大图".show(this@EventDetailActivity) - } else { - OtherUtils.showBigImage(this@EventDetailActivity, position, urls) - } + val imageAdapter = ImageGridViewAdapter(this) + imageAdapter.setImageList(imageUrls = urls) + imageAdapter.isDeleteVisible(false) + imageGridView.adapter = imageAdapter + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (urls[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@EventDetailActivity) + } else { + OtherUtils.showBigImage(this@EventDetailActivity, position, urls) } - }) + } } else { hasImageLayout.visibility = View.GONE dataView.text = "$data.0" diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt index 207f6c3..91fb674 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.view import android.bluetooth.BluetoothAdapter +import android.content.Intent import android.graphics.Color import android.os.Bundle import android.os.Handler @@ -18,6 +19,7 @@ import com.casic.birmm.inspect.utils.PageNavigationManager import com.casic.birmm.inspect.utils.StatusBarColorUtil import com.casic.birmm.inspect.widgets.InputDialog +import com.casic.birmm.inspect.widgets.SingleChoiceDialog import com.gyf.immersionbar.ImmersionBar import com.qmuiteam.qmui.util.QMUIStatusBarHelper import kotlinx.android.synthetic.main.activity_inspect_route.mapView @@ -42,6 +44,7 @@ private lateinit var aMap: AMap private lateinit var locationStyle: MyLocationStyle + private val itemList: List = arrayListOf("报警事件", "自定义事件") init { weakReferenceHandler = WeakReferenceHandler(this) @@ -131,7 +134,25 @@ newEventButton.setChangeAlphaWhenPress(true) newEventButton.setOnClickListener { - + SingleChoiceDialog.Builder() + .setContext(this) + .setTitle("选择事件类型") + .setChoiceItemButton(itemList) + .setOnDialogClickListener(object : SingleChoiceDialog.OnDialogItemClickListener { + override fun onItemClick(position: Int) { + val intent = Intent(this@MapActivity, NewEventActivity::class.java) + when (position) { + 0 -> { + intent.putExtra("isWarning", true) + } + 1 -> { + intent.putExtra("isWarning", false) + } + } + startActivity(intent) + } + }) + .build().show() } } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt new file mode 100644 index 0000000..de3eb19 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt @@ -0,0 +1,191 @@ +package com.casic.birmm.inspect.view + +import android.app.Activity +import android.content.Intent +import android.view.View +import androidx.core.content.ContextCompat +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.aihook.alertview.library.AlertView +import com.aihook.alertview.library.OnItemClickListener +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseViewModelActivity +import com.casic.birmm.inspect.extensions.combineImagePath +import com.casic.birmm.inspect.extensions.filterString +import com.casic.birmm.inspect.extensions.show +import com.casic.birmm.inspect.utils.* +import com.casic.birmm.inspect.vm.NewEventViewModel +import com.casic.birmm.inspect.vm.UploadImageViewModel +import com.gyf.immersionbar.ImmersionBar +import com.luck.picture.lib.PictureSelector +import com.luck.picture.lib.config.PictureConfig +import com.luck.picture.lib.config.PictureMimeType +import kotlinx.android.synthetic.main.activity_new_event.* +import kotlinx.android.synthetic.main.include_base_title.* +import java.io.File + + +class NewEventActivity : BaseViewModelActivity() { + + private lateinit var uploadImageViewModel: UploadImageViewModel + private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var imageAdapter: ImageGridViewAdapter + private var isWarning: Boolean = true + + override fun createViewModelByClass(): Class? = NewEventViewModel::class.java + + override fun initLayoutView(): Int = R.layout.activity_new_event + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + } + + override fun initData() { + uploadImageViewModel = ViewModelProvider(this).get(UploadImageViewModel::class.java) + isWarning = intent.getBooleanExtra("isWarning", true) + if (isWarning) { + titleView.text = "报警事件记录" + inspectCardView.visibility = View.VISIBLE + } else { + titleView.text = "自定义事件记录" + inspectCardView.visibility = View.GONE + } + eventCreateTimeView.text = + TimeOrDateUtil.timestampToCompleteDate(System.currentTimeMillis()) + + //初始化图片九宫格 + imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + } + + override fun initEvent() { + leftBackView.setOnClickListener { this.finish() } + + addImageView.setOnClickListener { + AlertView( + "请选择图片来源", null, "取消", null, arrayOf("拍照", "相册"), + this, AlertView.Style.ActionSheet, + OnItemClickListener { _, position -> + when (position) { + 0 -> { + PictureSelector.create(this) + .openCamera(PictureMimeType.ofImage()) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .forResult(PictureConfig.REQUEST_CAMERA) + } + 1 -> { + PictureSelector.create(this) + .openGallery(PictureMimeType.ofImage()) + .isWeChatStyle(true) + .isCamera(false) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .maxSelectNum(4) + .forResult(PictureConfig.CHOOSE_REQUEST) + } + } + } + ).setCancelable(true).show() + } + uploadImageViewModel.resultModel.observe(this, Observer { model -> + if (model.code == 200) { + /** + * 显示图片 + * path: 2021-07\c670eac17d644b179a4324a34bb84329.jpeg + * */ + imageGridView.visibility = View.VISIBLE + val sumItemCount: Int = imageAdapter.count + 1 //每上传一张图片,图片总数都是在原有的基础上+1 + if (sumItemCount <= 4) { + val url = model.data + //let函数处理需要针对一个可null的对象统一做判空处理。 + url?.let { + imagePaths.add(it) + realPaths.add(it.combineImagePath()) + } + if (realPaths.size == 4) { + addImageView.visibility = View.GONE + } + imageAdapter.setImageList(imageUrls = realPaths) + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@NewEventActivity) + } else { + OtherUtils.showBigImage(this@NewEventActivity, position, realPaths) + } + } + //删除按钮点击事件 + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + @Override + override fun onDeleteItemClick(position: Int) { + imagePaths.removeAt(position) + realPaths.removeAt(position) + imageAdapter.setImageList(imageUrls = realPaths) + if (realPaths.size != 2) { + addImageView.visibility = View.VISIBLE + } + } + }) + } else { + "最多只能上传4张图片".show(this) + } + } + }) + uploadImageViewModel.loadState.observe(this, Observer { + when (it) { + is LoadState.Loading -> { + OtherUtils.showLoadingDialog(this, "图片上传中,请稍后...") + } + else -> OtherUtils.dismissLoadingDialog() + } + }) + + addEventButton.setOnClickListener { + if (eventEditTextView.text.toString().filterString().isEmpty()) { + "事件情况说明还未填写,请检查".show(this) + return@setOnClickListener + } + if (isWarning) { + if (inspectNumberView.text.toString().filterString().isEmpty()) { + "最大泄露值还未填写,请检查".show(this) + return@setOnClickListener + } + } + + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + PictureConfig.CHOOSE_REQUEST -> { + val selectResult = PictureSelector.obtainMultipleResult(data) + for (res in selectResult) { + val file = File(res.compressPath) + if (file.length() <= Constant.IMAGE_MINUS_SIZE) { + "图片尺寸太小,请重新选择".show(this) + continue + } + //上传图片 + uploadImageViewModel.uploadImage(file) + } + } + PictureConfig.REQUEST_CAMERA -> { + val cameraResult = PictureSelector.obtainMultipleResult(data)[0] + //上传图片 + uploadImageViewModel.uploadImage(File(cameraResult.compressPath)) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt index d4821de..9de8a96 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt @@ -32,6 +32,7 @@ } private fun startGuideActivity() { +// startActivity(Intent(this, TestActivity::class.java)) startActivity(Intent(this, GuideActivity::class.java)) finish() } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt new file mode 100644 index 0000000..abb6e23 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt @@ -0,0 +1,54 @@ +package com.casic.birmm.inspect.view + +import android.util.Log +import androidx.core.content.ContextCompat +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseActivity +import com.casic.birmm.inspect.utils.PageNavigationManager +import com.casic.birmm.inspect.utils.StatusBarColorUtil +import com.gyf.immersionbar.ImmersionBar +import kotlinx.android.synthetic.main.activity_test.* +import kotlinx.android.synthetic.main.include_base_title.* + +class TestActivity : BaseActivity() { + + companion object { + private const val Tag = "TestActivity" + } + + private val urls = arrayListOf( + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg" + ) + + override fun initLayoutView(): Int = R.layout.activity_test + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + titleView.text = "测试功能页面" + } + + override fun initData() { + val imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + imageAdapter.setImageList(imageUrls = urls) + imageGridView.setOnItemClickListener { _, _, position, _ -> + Log.d(Tag, "点击path: ${urls[position]}") + } + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + override fun onDeleteItemClick(position: Int) { + Log.d(Tag, "删除path: ${urls[position]}") + } + }) + } + + override fun initEvent() { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt new file mode 100644 index 0000000..dd145f4 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt @@ -0,0 +1,6 @@ +package com.casic.birmm.inspect.vm + +import com.casic.birmm.inspect.base.BaseViewModel + +class NewEventViewModel : BaseViewModel() { +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt new file mode 100644 index 0000000..a7fa31b --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt @@ -0,0 +1,21 @@ +package com.casic.birmm.inspect.vm + +import androidx.lifecycle.MutableLiveData +import com.casic.birmm.inspect.base.BaseViewModel +import com.casic.birmm.inspect.extensions.launch +import com.casic.birmm.inspect.model.ActionResultModel +import com.casic.birmm.inspect.utils.LoadState +import com.casic.birmm.inspect.utils.retrofit.RetrofitServiceManager +import java.io.File + +class UploadImageViewModel : BaseViewModel() { + val resultModel = MutableLiveData() + + fun uploadImage(image: File) = launch({ + loadState.value = LoadState.Loading + resultModel.value = RetrofitServiceManager.uploadImage(image) + loadState.value = LoadState.Success + }, { + loadState.value = LoadState.Fail + }) +} \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_layout_white.xml b/app/src/main/res/drawable/bg_layout_white.xml index 19b473b..1002512 100644 --- a/app/src/main/res/drawable/bg_layout_white.xml +++ b/app/src/main/res/drawable/bg_layout_white.xml @@ -7,5 +7,5 @@ + android:color="@color/hintColor" /> \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_black.xml b/app/src/main/res/drawable/ic_add_black.xml new file mode 100644 index 0000000..4a7fb89 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_delete_black.xml b/app/src/main/res/drawable/ic_delete_black.xml new file mode 100644 index 0000000..482b166 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_event_detail.xml b/app/src/main/res/layout/activity_event_detail.xml index 89dbc1e..1eefc6e 100644 --- a/app/src/main/res/layout/activity_event_detail.xml +++ b/app/src/main/res/layout/activity_event_detail.xml @@ -92,17 +92,21 @@ android:orientation="vertical"> - + android:layout_marginTop="@dimen/margin_10dp" + android:horizontalSpacing="@dimen/margin_10dp" + android:numColumns="3" + android:scrollbars="none" + android:verticalSpacing="@dimen/margin_10dp" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_test.xml b/app/src/main/res/layout/activity_test.xml new file mode 100644 index 0000000..066d6dd --- /dev/null +++ b/app/src/main/res/layout/activity_test.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_user_settings.xml b/app/src/main/res/layout/activity_user_settings.xml index e6f0e59..d5541c1 100644 --- a/app/src/main/res/layout/activity_user_settings.xml +++ b/app/src/main/res/layout/activity_user_settings.xml @@ -124,7 +124,7 @@ android:layout_marginHorizontal="30dp" android:layout_marginBottom="30dp" android:paddingVertical="7dp" - android:text="退\u3000\u3000出" + android:text="退出登录" android:textColor="@color/white" android:textSize="@dimen/titleFontSize" app:qmui_backgroundColor="@color/mainThemeColor" diff --git a/app/src/main/res/layout/item_image_gridview.xml b/app/src/main/res/layout/item_image_gridview.xml index 84868e0..f858d5f 100644 --- a/app/src/main/res/layout/item_image_gridview.xml +++ b/app/src/main/res/layout/item_image_gridview.xml @@ -1,12 +1,19 @@ - + android:layout_height="wrap_content"> - \ No newline at end of file + android:layout_width="110dp" + android:layout_height="110dp" + android:layout_gravity="center" + android:scaleType="centerCrop" /> + + + \ No newline at end of file diff --git a/app/src/main/res/layout/line.xml b/app/src/main/res/layout/line.xml index fd99e01..38d7554 100644 --- a/app/src/main/res/layout/line.xml +++ b/app/src/main/res/layout/line.xml @@ -2,4 +2,4 @@ \ No newline at end of file + android:background="@color/hintColor" /> \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 7e1d8f5..a101c80 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -81,4 +81,6 @@ //高德地图 implementation 'com.amap.api:3dmap:7.9.1' implementation 'com.amap.api:location:5.3.1' + //仿iOS风格的dialog库 + implementation 'com.aihook:alertview:1.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6a3f570..4e17162 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,7 @@ + + @@ -53,6 +55,7 @@ + = ArrayList() + + fun setImageList(@Nullable imageUrls: List?) { + images.clear() + if (imageUrls != null) { + images.addAll(imageUrls) + } + notifyDataSetChanged() + } + + fun isDeleteVisible(isVisible: Boolean) { + this.isVisible = isVisible + } + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getCount(): Int = images.size + + override fun getItem(position: Int): Any = images[position] + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val view: View + val holder: ItemViewHolder + if (convertView == null) { + holder = ItemViewHolder() + view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, null) + holder.imageView = view.findViewById(R.id.imageView) + holder.deleteView = view.findViewById(R.id.deleteView) + view.tag = holder + } else { + view = convertView + holder = view.tag as ItemViewHolder + } + Glide.with(context) + .load(images[position]) + .apply(RequestOptions().error(R.drawable.ic_load_error)) + .into(holder.imageView) + if (isVisible) { + holder.deleteView.visibility = View.VISIBLE + holder.deleteView.setOnClickListener { + deleteItemClickListener!!.onDeleteItemClick(position) + } + } else { + holder.deleteView.visibility = View.INVISIBLE + } + return view + } + + inner class ItemViewHolder { + lateinit var imageView: ImageView + lateinit var deleteView: ImageView + } + + private var deleteItemClickListener: OnDeleteItemClickListener? = null + + interface OnDeleteItemClickListener { + fun onDeleteItemClick(position: Int) + } + + fun setOnDeleteClickListener(listener: OnDeleteItemClickListener?) { + deleteItemClickListener = listener + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt b/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt deleted file mode 100644 index aff92d4..0000000 --- a/app/src/main/java/com/casic/birmm/inspect/adapter/ImageRecycleViewAdapter.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.casic.birmm.inspect.adapter - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.request.RequestOptions -import com.casic.birmm.inspect.R - -class ImageRecycleViewAdapter(private val context: Context, private val images: List) : - RecyclerView.Adapter() { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - val view = LayoutInflater.from(context).inflate(R.layout.item_image_gridview, parent, false) - return ItemViewHolder(view) - } - - override fun getItemCount(): Int = images.size - - override fun getItemId(position: Int): Long = position.toLong() - - override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { - Glide.with(context) - .load(images[position]) - .apply(RequestOptions().error(R.drawable.ic_load_error)) - .into(holder.imageView) - holder.itemView.setOnClickListener { itemClickListener!!.onClick(position) } - } - - class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val imageView: ImageView = itemView.findViewById(R.id.imageView) - } - - private var itemClickListener: OnItemClickListener? = null - - interface OnItemClickListener { - fun onClick(position: Int) - } - - fun setOnItemClickListener(listener: OnItemClickListener?) { - itemClickListener = listener - } -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt index fc0ca75..dbbbd33 100644 --- a/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt +++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseApplication.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.base import android.app.Application +import com.casic.birmm.inspect.utils.FileUtils import com.casic.birmm.inspect.utils.SaveKeyValues import kotlin.properties.Delegates @@ -14,5 +15,6 @@ super.onCreate() instance = this SaveKeyValues.initSharedPreferences() + FileUtils.initFileConfig() } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt index 1f700ab..164d636 100644 --- a/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt +++ b/app/src/main/java/com/casic/birmm/inspect/extensions/String.kt @@ -2,7 +2,6 @@ import android.content.Context import android.graphics.Color -import android.text.TextUtils import android.view.Gravity import android.widget.TextView import android.widget.Toast @@ -18,9 +17,7 @@ //过滤空格,回车 fun String.filterString(): String { - if (TextUtils.isEmpty(this)) { - return this - } + if (this.isEmpty()) return this val s: String //先过滤回车换行 val p = Pattern.compile("\\s*|\t|\r|\n") @@ -32,11 +29,12 @@ //拼接图片地址 fun String.combineImagePath(): String { + if (this.isEmpty()) return this val defaultValue = SaveKeyValues.getValue( Constant.DEFAULT_SERVER_CONFIG, "http://111.198.10.15:12204" ) as String - return "$defaultValue/static/$this" + return "$defaultValue/static/${this.replace("\\", "/")}" } diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt index aef675a..0c9e963 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/Constant.kt @@ -8,7 +8,7 @@ Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, - Manifest.permission.READ_PHONE_STATE + Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA ) const val PERMISSIONS_CODE = 999 @@ -19,6 +19,7 @@ const val DEVICE_DISCONNECTED = 23 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val IMAGE_MINUS_SIZE = 50 * 1024 const val DEFAULT_SERVER_CONFIG = "defaultServerConfig" const val USER_OBJECT = "userObject" diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt new file mode 100644 index 0000000..8b6d696 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/FileUtils.kt @@ -0,0 +1,124 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.os.Environment +import android.util.Log +import com.casic.birmm.inspect.base.BaseApplication +import com.casic.birmm.inspect.utils.callback.IDownloadListener +import okhttp3.* +import java.io.File +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.text.SimpleDateFormat +import java.util.* + +object FileUtils { + private const val Tag = "FileUtils" + private lateinit var context: Context + private var index = 1 + + fun initFileConfig() { + this.context = BaseApplication.instance + } + + val imageCompressPath: String + get() { + val imageDir = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "") + if (!imageDir.exists()) { + val mkdir = imageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建imageCompressPath文件夹") + } + } + return imageDir.toString() + } + + val waterImageFile: File + get() { + val waterImageDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "WaterImage") + if (!waterImageDir.exists()) { + val mkdir = waterImageDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建waterImageFile文件夹") + } + } + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA).format(Date()) + //index用来区分for循环太快会导致多想图片覆盖压缩问题 + val imageFile = + File(waterImageDir.toString() + File.separator + "IMG_" + timeStamp + "_" + (index++) + ".png") + if (!imageFile.exists()) { + try { + imageFile.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + } + } + return imageFile + } + + //储存下载文件的目录 + private val downloadFilePath: String + get() { + val downloadDir = + File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "") + if (!downloadDir.exists()) { + val mkdir = downloadDir.mkdir() + if (mkdir) { + Log.d(Tag, "创建downloadFilePath文件夹") + } + } + return downloadDir.toString() + } + + fun downloadFile(url: String, listener: IDownloadListener) { + val okHttpClient = OkHttpClient() + val request = Request.Builder().get().url(url).build() + okHttpClient.newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + e.printStackTrace() + } + + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + var inputStream: InputStream? = null + val buf = ByteArray(2048) + var len: Int + var fos: FileOutputStream? = null + val savePath = downloadFilePath + try { + val body = response.body + if (body != null) { + inputStream = body.byteStream() + val total = body.contentLength() + listener.onDownloadStart(total) + val file = File(savePath, url.substring(url.lastIndexOf("/") + 1)) + fos = FileOutputStream(file) + var current: Long = 0 + while (inputStream.read(buf).also { len = it } != -1) { + fos.write(buf, 0, len) + current += len.toLong() + listener.onProgressChanged(current) + } + fos.flush() + listener.onDownloadEnd(file) + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + try { + inputStream?.close() + } catch (e: IOException) { + e.printStackTrace() + } + try { + fos?.close() + } catch (e: IOException) { + e.printStackTrace() + } + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt new file mode 100644 index 0000000..6a68178 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/GlideLoadEngine.kt @@ -0,0 +1,77 @@ +package com.casic.birmm.inspect.utils + +import android.content.Context +import android.graphics.Bitmap +import android.widget.ImageView +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.bumptech.glide.Glide +import com.bumptech.glide.request.RequestOptions +import com.bumptech.glide.request.target.BitmapImageViewTarget +import com.casic.birmm.inspect.R +import com.luck.picture.lib.engine.ImageEngine +import com.luck.picture.lib.listener.OnImageCompleteCallback +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView + +class GlideLoadEngine private constructor() : ImageEngine { + companion object { + private var instance: GlideLoadEngine? = null + fun createGlideEngine(): GlideLoadEngine? { + if (null == instance) { + synchronized(GlideLoadEngine::class.java) { + if (null == instance) { + instance = GlideLoadEngine() + } + } + } + return instance + } + } + + override fun loadImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).load(url).into(imageView) + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView, + callback: OnImageCompleteCallback + ) { + + } + + override fun loadImage( + context: Context, + url: String, + imageView: ImageView, + longImageView: SubsamplingScaleImageView + ) { + } + + override fun loadFolderImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(object : BitmapImageViewTarget(imageView) { + override fun setResource(resource: Bitmap?) { + val circularBitmapDrawable = + RoundedBitmapDrawableFactory.create(context.resources, resource) + circularBitmapDrawable.cornerRadius = 8f + imageView.setImageDrawable(circularBitmapDrawable) + } + }) + } + + override fun loadAsGifImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context).asGif().load(url).into(imageView) + } + + override fun loadGridImage(context: Context, url: String, imageView: ImageView) { + Glide.with(context) + .load(url) + .apply(RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt new file mode 100644 index 0000000..a3d49d6 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IDownloadListener.kt @@ -0,0 +1,9 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IDownloadListener { + fun onDownloadStart(totalBytes: Long) + fun onProgressChanged(currentBytes: Long) + fun onDownloadEnd(file: File?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt new file mode 100644 index 0000000..8e3041e --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/utils/callback/IWaterMarkAddListener.kt @@ -0,0 +1,8 @@ +package com.casic.birmm.inspect.utils.callback + +import java.io.File + +interface IWaterMarkAddListener { + fun onSuccess(file: File?) + fun onError(e: Throwable?) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt index 36b219f..a05027e 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt @@ -1,8 +1,10 @@ package com.casic.birmm.inspect.utils.retrofit import com.casic.birmm.inspect.model.* +import okhttp3.MultipartBody import retrofit2.http.* + /** * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符 * */ @@ -79,4 +81,16 @@ @Header("token") token: String, @Query("inspectionId") inspectionId: String ): TaskRecordModel + + /** + * 上传图片 + * 系统路径static拼接图片返回路径 + * http://xx.com/static/2019-10/8050891248624f2bbefedcb196ce89cb.jpeg + */ + @Multipart + @POST("/fileUpload") + suspend fun uploadImage( + @Header("token") token: String, + @Part file: MultipartBody.Part + ): ActionResultModel } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt index 23ed09d..df03b14 100644 --- a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt @@ -3,6 +3,10 @@ import com.casic.birmm.inspect.model.* import com.casic.birmm.inspect.utils.AuthenticationHelper import com.casic.birmm.inspect.utils.Constant +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody +import java.io.File object RetrofitServiceManager { @@ -88,4 +92,13 @@ suspend fun searchByInspection(inspectionId: String): TaskRecordModel { return api.searchByInspection(AuthenticationHelper.token!!, inspectionId) } + + /** + * 上传图片 + */ + suspend fun uploadImage(image: File): ActionResultModel { + val requestBody = RequestBody.create("image/png".toMediaTypeOrNull(), image) + val imagePart = MultipartBody.Part.createFormData("file", image.name, requestBody) + return api.uploadImage(AuthenticationHelper.token!!, imagePart) + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt index 9b29ca3..fe37dc3 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/EventDetailActivity.kt @@ -3,9 +3,8 @@ import android.annotation.SuppressLint import android.view.View import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.GridLayoutManager import com.casic.birmm.inspect.R -import com.casic.birmm.inspect.adapter.ImageRecycleViewAdapter +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter import com.casic.birmm.inspect.base.BaseActivity import com.casic.birmm.inspect.extensions.combineImagePath import com.casic.birmm.inspect.extensions.show @@ -54,19 +53,17 @@ } } //绑定图片 - val imageAdapter = ImageRecycleViewAdapter(this, urls) - imageRecyclerView.layoutManager = GridLayoutManager(this, 2) - imageRecyclerView.adapter = imageAdapter - imageAdapter.setOnItemClickListener(object : - ImageRecycleViewAdapter.OnItemClickListener { - override fun onClick(position: Int) { - if (urls[position].isEmpty()) { - "图片加载失败,无法查看大图".show(this@EventDetailActivity) - } else { - OtherUtils.showBigImage(this@EventDetailActivity, position, urls) - } + val imageAdapter = ImageGridViewAdapter(this) + imageAdapter.setImageList(imageUrls = urls) + imageAdapter.isDeleteVisible(false) + imageGridView.adapter = imageAdapter + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (urls[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@EventDetailActivity) + } else { + OtherUtils.showBigImage(this@EventDetailActivity, position, urls) } - }) + } } else { hasImageLayout.visibility = View.GONE dataView.text = "$data.0" diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt index 207f6c3..91fb674 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/MapActivity.kt @@ -1,6 +1,7 @@ package com.casic.birmm.inspect.view import android.bluetooth.BluetoothAdapter +import android.content.Intent import android.graphics.Color import android.os.Bundle import android.os.Handler @@ -18,6 +19,7 @@ import com.casic.birmm.inspect.utils.PageNavigationManager import com.casic.birmm.inspect.utils.StatusBarColorUtil import com.casic.birmm.inspect.widgets.InputDialog +import com.casic.birmm.inspect.widgets.SingleChoiceDialog import com.gyf.immersionbar.ImmersionBar import com.qmuiteam.qmui.util.QMUIStatusBarHelper import kotlinx.android.synthetic.main.activity_inspect_route.mapView @@ -42,6 +44,7 @@ private lateinit var aMap: AMap private lateinit var locationStyle: MyLocationStyle + private val itemList: List = arrayListOf("报警事件", "自定义事件") init { weakReferenceHandler = WeakReferenceHandler(this) @@ -131,7 +134,25 @@ newEventButton.setChangeAlphaWhenPress(true) newEventButton.setOnClickListener { - + SingleChoiceDialog.Builder() + .setContext(this) + .setTitle("选择事件类型") + .setChoiceItemButton(itemList) + .setOnDialogClickListener(object : SingleChoiceDialog.OnDialogItemClickListener { + override fun onItemClick(position: Int) { + val intent = Intent(this@MapActivity, NewEventActivity::class.java) + when (position) { + 0 -> { + intent.putExtra("isWarning", true) + } + 1 -> { + intent.putExtra("isWarning", false) + } + } + startActivity(intent) + } + }) + .build().show() } } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt new file mode 100644 index 0000000..de3eb19 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/NewEventActivity.kt @@ -0,0 +1,191 @@ +package com.casic.birmm.inspect.view + +import android.app.Activity +import android.content.Intent +import android.view.View +import androidx.core.content.ContextCompat +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider +import com.aihook.alertview.library.AlertView +import com.aihook.alertview.library.OnItemClickListener +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseViewModelActivity +import com.casic.birmm.inspect.extensions.combineImagePath +import com.casic.birmm.inspect.extensions.filterString +import com.casic.birmm.inspect.extensions.show +import com.casic.birmm.inspect.utils.* +import com.casic.birmm.inspect.vm.NewEventViewModel +import com.casic.birmm.inspect.vm.UploadImageViewModel +import com.gyf.immersionbar.ImmersionBar +import com.luck.picture.lib.PictureSelector +import com.luck.picture.lib.config.PictureConfig +import com.luck.picture.lib.config.PictureMimeType +import kotlinx.android.synthetic.main.activity_new_event.* +import kotlinx.android.synthetic.main.include_base_title.* +import java.io.File + + +class NewEventActivity : BaseViewModelActivity() { + + private lateinit var uploadImageViewModel: UploadImageViewModel + private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 + private val realPaths: ArrayList = ArrayList() //真实图片路径 + private lateinit var imageAdapter: ImageGridViewAdapter + private var isWarning: Boolean = true + + override fun createViewModelByClass(): Class? = NewEventViewModel::class.java + + override fun initLayoutView(): Int = R.layout.activity_new_event + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + } + + override fun initData() { + uploadImageViewModel = ViewModelProvider(this).get(UploadImageViewModel::class.java) + isWarning = intent.getBooleanExtra("isWarning", true) + if (isWarning) { + titleView.text = "报警事件记录" + inspectCardView.visibility = View.VISIBLE + } else { + titleView.text = "自定义事件记录" + inspectCardView.visibility = View.GONE + } + eventCreateTimeView.text = + TimeOrDateUtil.timestampToCompleteDate(System.currentTimeMillis()) + + //初始化图片九宫格 + imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + } + + override fun initEvent() { + leftBackView.setOnClickListener { this.finish() } + + addImageView.setOnClickListener { + AlertView( + "请选择图片来源", null, "取消", null, arrayOf("拍照", "相册"), + this, AlertView.Style.ActionSheet, + OnItemClickListener { _, position -> + when (position) { + 0 -> { + PictureSelector.create(this) + .openCamera(PictureMimeType.ofImage()) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .forResult(PictureConfig.REQUEST_CAMERA) + } + 1 -> { + PictureSelector.create(this) + .openGallery(PictureMimeType.ofImage()) + .isWeChatStyle(true) + .isCamera(false) + .isCompress(true) + .compressQuality(90) + .compressSavePath(FileUtils.imageCompressPath) + .imageEngine(GlideLoadEngine.createGlideEngine()) + .maxSelectNum(4) + .forResult(PictureConfig.CHOOSE_REQUEST) + } + } + } + ).setCancelable(true).show() + } + uploadImageViewModel.resultModel.observe(this, Observer { model -> + if (model.code == 200) { + /** + * 显示图片 + * path: 2021-07\c670eac17d644b179a4324a34bb84329.jpeg + * */ + imageGridView.visibility = View.VISIBLE + val sumItemCount: Int = imageAdapter.count + 1 //每上传一张图片,图片总数都是在原有的基础上+1 + if (sumItemCount <= 4) { + val url = model.data + //let函数处理需要针对一个可null的对象统一做判空处理。 + url?.let { + imagePaths.add(it) + realPaths.add(it.combineImagePath()) + } + if (realPaths.size == 4) { + addImageView.visibility = View.GONE + } + imageAdapter.setImageList(imageUrls = realPaths) + imageGridView.setOnItemClickListener { _, _, position, _ -> + if (realPaths[position].isEmpty()) { + "图片加载失败,无法查看大图".show(this@NewEventActivity) + } else { + OtherUtils.showBigImage(this@NewEventActivity, position, realPaths) + } + } + //删除按钮点击事件 + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + @Override + override fun onDeleteItemClick(position: Int) { + imagePaths.removeAt(position) + realPaths.removeAt(position) + imageAdapter.setImageList(imageUrls = realPaths) + if (realPaths.size != 2) { + addImageView.visibility = View.VISIBLE + } + } + }) + } else { + "最多只能上传4张图片".show(this) + } + } + }) + uploadImageViewModel.loadState.observe(this, Observer { + when (it) { + is LoadState.Loading -> { + OtherUtils.showLoadingDialog(this, "图片上传中,请稍后...") + } + else -> OtherUtils.dismissLoadingDialog() + } + }) + + addEventButton.setOnClickListener { + if (eventEditTextView.text.toString().filterString().isEmpty()) { + "事件情况说明还未填写,请检查".show(this) + return@setOnClickListener + } + if (isWarning) { + if (inspectNumberView.text.toString().filterString().isEmpty()) { + "最大泄露值还未填写,请检查".show(this) + return@setOnClickListener + } + } + + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + PictureConfig.CHOOSE_REQUEST -> { + val selectResult = PictureSelector.obtainMultipleResult(data) + for (res in selectResult) { + val file = File(res.compressPath) + if (file.length() <= Constant.IMAGE_MINUS_SIZE) { + "图片尺寸太小,请重新选择".show(this) + continue + } + //上传图片 + uploadImageViewModel.uploadImage(file) + } + } + PictureConfig.REQUEST_CAMERA -> { + val cameraResult = PictureSelector.obtainMultipleResult(data)[0] + //上传图片 + uploadImageViewModel.uploadImage(File(cameraResult.compressPath)) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt index d4821de..9de8a96 100644 --- a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt +++ b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt @@ -32,6 +32,7 @@ } private fun startGuideActivity() { +// startActivity(Intent(this, TestActivity::class.java)) startActivity(Intent(this, GuideActivity::class.java)) finish() } diff --git a/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt new file mode 100644 index 0000000..abb6e23 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/view/TestActivity.kt @@ -0,0 +1,54 @@ +package com.casic.birmm.inspect.view + +import android.util.Log +import androidx.core.content.ContextCompat +import com.casic.birmm.inspect.R +import com.casic.birmm.inspect.adapter.ImageGridViewAdapter +import com.casic.birmm.inspect.base.BaseActivity +import com.casic.birmm.inspect.utils.PageNavigationManager +import com.casic.birmm.inspect.utils.StatusBarColorUtil +import com.gyf.immersionbar.ImmersionBar +import kotlinx.android.synthetic.main.activity_test.* +import kotlinx.android.synthetic.main.include_base_title.* + +class TestActivity : BaseActivity() { + + companion object { + private const val Tag = "TestActivity" + } + + private val urls = arrayListOf( + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg", + "http://111.198.10.15:12204/static/2021-07/b2c3f2f2e5ba4686bfece696bf5f8510.jpeg" + ) + + override fun initLayoutView(): Int = R.layout.activity_test + + override fun setupTopBarLayout() { + PageNavigationManager.addActivity(this) + StatusBarColorUtil.setColor(this, ContextCompat.getColor(this, R.color.mainThemeColor)) + ImmersionBar.with(this).statusBarDarkFont(false).init() + titleView.text = "测试功能页面" + } + + override fun initData() { + val imageAdapter = ImageGridViewAdapter(this) + imageGridView.adapter = imageAdapter + imageAdapter.setImageList(imageUrls = urls) + imageGridView.setOnItemClickListener { _, _, position, _ -> + Log.d(Tag, "点击path: ${urls[position]}") + } + imageAdapter.setOnDeleteClickListener(object : + ImageGridViewAdapter.OnDeleteItemClickListener { + override fun onDeleteItemClick(position: Int) { + Log.d(Tag, "删除path: ${urls[position]}") + } + }) + } + + override fun initEvent() { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt new file mode 100644 index 0000000..dd145f4 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/NewEventViewModel.kt @@ -0,0 +1,6 @@ +package com.casic.birmm.inspect.vm + +import com.casic.birmm.inspect.base.BaseViewModel + +class NewEventViewModel : BaseViewModel() { +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt new file mode 100644 index 0000000..a7fa31b --- /dev/null +++ b/app/src/main/java/com/casic/birmm/inspect/vm/UploadImageViewModel.kt @@ -0,0 +1,21 @@ +package com.casic.birmm.inspect.vm + +import androidx.lifecycle.MutableLiveData +import com.casic.birmm.inspect.base.BaseViewModel +import com.casic.birmm.inspect.extensions.launch +import com.casic.birmm.inspect.model.ActionResultModel +import com.casic.birmm.inspect.utils.LoadState +import com.casic.birmm.inspect.utils.retrofit.RetrofitServiceManager +import java.io.File + +class UploadImageViewModel : BaseViewModel() { + val resultModel = MutableLiveData() + + fun uploadImage(image: File) = launch({ + loadState.value = LoadState.Loading + resultModel.value = RetrofitServiceManager.uploadImage(image) + loadState.value = LoadState.Success + }, { + loadState.value = LoadState.Fail + }) +} \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_layout_white.xml b/app/src/main/res/drawable/bg_layout_white.xml index 19b473b..1002512 100644 --- a/app/src/main/res/drawable/bg_layout_white.xml +++ b/app/src/main/res/drawable/bg_layout_white.xml @@ -7,5 +7,5 @@ + android:color="@color/hintColor" /> \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_black.xml b/app/src/main/res/drawable/ic_add_black.xml new file mode 100644 index 0000000..4a7fb89 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_delete_black.xml b/app/src/main/res/drawable/ic_delete_black.xml new file mode 100644 index 0000000..482b166 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete_black.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_event_detail.xml b/app/src/main/res/layout/activity_event_detail.xml index 89dbc1e..1eefc6e 100644 --- a/app/src/main/res/layout/activity_event_detail.xml +++ b/app/src/main/res/layout/activity_event_detail.xml @@ -92,17 +92,21 @@ android:orientation="vertical"> - + android:layout_marginTop="@dimen/margin_10dp" + android:horizontalSpacing="@dimen/margin_10dp" + android:numColumns="3" + android:scrollbars="none" + android:verticalSpacing="@dimen/margin_10dp" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_test.xml b/app/src/main/res/layout/activity_test.xml new file mode 100644 index 0000000..066d6dd --- /dev/null +++ b/app/src/main/res/layout/activity_test.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_user_settings.xml b/app/src/main/res/layout/activity_user_settings.xml index e6f0e59..d5541c1 100644 --- a/app/src/main/res/layout/activity_user_settings.xml +++ b/app/src/main/res/layout/activity_user_settings.xml @@ -124,7 +124,7 @@ android:layout_marginHorizontal="30dp" android:layout_marginBottom="30dp" android:paddingVertical="7dp" - android:text="退\u3000\u3000出" + android:text="退出登录" android:textColor="@color/white" android:textSize="@dimen/titleFontSize" app:qmui_backgroundColor="@color/mainThemeColor" diff --git a/app/src/main/res/layout/item_image_gridview.xml b/app/src/main/res/layout/item_image_gridview.xml index 84868e0..f858d5f 100644 --- a/app/src/main/res/layout/item_image_gridview.xml +++ b/app/src/main/res/layout/item_image_gridview.xml @@ -1,12 +1,19 @@ - + android:layout_height="wrap_content"> - \ No newline at end of file + android:layout_width="110dp" + android:layout_height="110dp" + android:layout_gravity="center" + android:scaleType="centerCrop" /> + + + \ No newline at end of file diff --git a/app/src/main/res/layout/line.xml b/app/src/main/res/layout/line.xml index fd99e01..38d7554 100644 --- a/app/src/main/res/layout/line.xml +++ b/app/src/main/res/layout/line.xml @@ -2,4 +2,4 @@ \ No newline at end of file + android:background="@color/hintColor" /> \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 92f3cdc..2b808b3 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,7 +7,6 @@ #FFFFFF #F9F9F9 #EFEFEF - #E5E5E5 #D3D3D3 #C0C0C0 #A9A9A9