diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Int.kt b/app/src/main/java/com/casic/detector/extensions/Int.kt index 10275bb..d67cac8 100644 --- a/app/src/main/java/com/casic/detector/extensions/Int.kt +++ b/app/src/main/java/com/casic/detector/extensions/Int.kt @@ -13,4 +13,12 @@ paint.color = color canvas.drawArc(rectF, 0f, 360f, true, paint) return bitmap +} + +fun Int.appendZero(): String { + return if (this < 10) { + "0$this" + } else { + this.toString() + } } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Int.kt b/app/src/main/java/com/casic/detector/extensions/Int.kt index 10275bb..d67cac8 100644 --- a/app/src/main/java/com/casic/detector/extensions/Int.kt +++ b/app/src/main/java/com/casic/detector/extensions/Int.kt @@ -13,4 +13,12 @@ paint.color = color canvas.drawArc(rectF, 0f, 360f, true, paint) return bitmap +} + +fun Int.appendZero(): String { + return if (this < 10) { + "0$this" + } else { + this.toString() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index 7352dc1..aacd89d 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -45,6 +45,36 @@ } } +fun String.toObjectType(): String { + return if (this == LocaleConstant.POINT_TYPE_ARRAY[0]) { + "1" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[1]) { + "2" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[2]) { + "3" + } else { + "4" + } +} + +fun String.toColor(): String { + return if (this == LocaleConstant.COLOR_ARRAY[0]) { + "0" + } else if (this == LocaleConstant.COLOR_ARRAY[1]) { + "1" + } else if (this == LocaleConstant.COLOR_ARRAY[2]) { + "2" + } else if (this == LocaleConstant.COLOR_ARRAY[3]) { + "3" + } else if (this == LocaleConstant.COLOR_ARRAY[4]) { + "4" + } else if (this == LocaleConstant.COLOR_ARRAY[5]) { + "5" + } else { + "6" + } +} + fun String.compressImage(context: Context, listener: OnImageCompressListener) { Luban.with(context) .load(this) @@ -63,4 +93,14 @@ listener.onError(e) } }).launch() +} + +//根据控件名字存默认值 +fun String.setDefaultValue(value: String) { + SaveKeyValues.putValue(this, value) +} + +//根据控件名字取默认值 +fun String.getDefaultValue(): String { + return SaveKeyValues.getValue(this, "") as String } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Int.kt b/app/src/main/java/com/casic/detector/extensions/Int.kt index 10275bb..d67cac8 100644 --- a/app/src/main/java/com/casic/detector/extensions/Int.kt +++ b/app/src/main/java/com/casic/detector/extensions/Int.kt @@ -13,4 +13,12 @@ paint.color = color canvas.drawArc(rectF, 0f, 360f, true, paint) return bitmap +} + +fun Int.appendZero(): String { + return if (this < 10) { + "0$this" + } else { + this.toString() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index 7352dc1..aacd89d 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -45,6 +45,36 @@ } } +fun String.toObjectType(): String { + return if (this == LocaleConstant.POINT_TYPE_ARRAY[0]) { + "1" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[1]) { + "2" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[2]) { + "3" + } else { + "4" + } +} + +fun String.toColor(): String { + return if (this == LocaleConstant.COLOR_ARRAY[0]) { + "0" + } else if (this == LocaleConstant.COLOR_ARRAY[1]) { + "1" + } else if (this == LocaleConstant.COLOR_ARRAY[2]) { + "2" + } else if (this == LocaleConstant.COLOR_ARRAY[3]) { + "3" + } else if (this == LocaleConstant.COLOR_ARRAY[4]) { + "4" + } else if (this == LocaleConstant.COLOR_ARRAY[5]) { + "5" + } else { + "6" + } +} + fun String.compressImage(context: Context, listener: OnImageCompressListener) { Luban.with(context) .load(this) @@ -63,4 +93,14 @@ listener.onError(e) } }).launch() +} + +//根据控件名字存默认值 +fun String.setDefaultValue(value: String) { + SaveKeyValues.putValue(this, value) +} + +//根据控件名字取默认值 +fun String.getDefaultValue(): String { + return SaveKeyValues.getValue(this, "") as String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 6ee3191..9e862aa 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -1,10 +1,8 @@ package com.casic.detector.retrofit +import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query +import retrofit2.http.* interface RetrofitService { /** @@ -56,6 +54,12 @@ /** * 安装新标识器 */ + @Multipart @POST("/ems/marker/save-marker-photo.do") - suspend fun installLabel(@Body requestBody: RequestBody): String + suspend fun installLabel( + @PartMap jsonMarker: Map, + @Part fileBuffer1: MultipartBody.Part?, + @Part fileBuffer2: MultipartBody.Part?, + @Part fileBuffer3: MultipartBody.Part? + ): String } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Int.kt b/app/src/main/java/com/casic/detector/extensions/Int.kt index 10275bb..d67cac8 100644 --- a/app/src/main/java/com/casic/detector/extensions/Int.kt +++ b/app/src/main/java/com/casic/detector/extensions/Int.kt @@ -13,4 +13,12 @@ paint.color = color canvas.drawArc(rectF, 0f, 360f, true, paint) return bitmap +} + +fun Int.appendZero(): String { + return if (this < 10) { + "0$this" + } else { + this.toString() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index 7352dc1..aacd89d 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -45,6 +45,36 @@ } } +fun String.toObjectType(): String { + return if (this == LocaleConstant.POINT_TYPE_ARRAY[0]) { + "1" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[1]) { + "2" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[2]) { + "3" + } else { + "4" + } +} + +fun String.toColor(): String { + return if (this == LocaleConstant.COLOR_ARRAY[0]) { + "0" + } else if (this == LocaleConstant.COLOR_ARRAY[1]) { + "1" + } else if (this == LocaleConstant.COLOR_ARRAY[2]) { + "2" + } else if (this == LocaleConstant.COLOR_ARRAY[3]) { + "3" + } else if (this == LocaleConstant.COLOR_ARRAY[4]) { + "4" + } else if (this == LocaleConstant.COLOR_ARRAY[5]) { + "5" + } else { + "6" + } +} + fun String.compressImage(context: Context, listener: OnImageCompressListener) { Luban.with(context) .load(this) @@ -63,4 +93,14 @@ listener.onError(e) } }).launch() +} + +//根据控件名字存默认值 +fun String.setDefaultValue(value: String) { + SaveKeyValues.putValue(this, value) +} + +//根据控件名字取默认值 +fun String.getDefaultValue(): String { + return SaveKeyValues.getValue(this, "") as String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 6ee3191..9e862aa 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -1,10 +1,8 @@ package com.casic.detector.retrofit +import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query +import retrofit2.http.* interface RetrofitService { /** @@ -56,6 +54,12 @@ /** * 安装新标识器 */ + @Multipart @POST("/ems/marker/save-marker-photo.do") - suspend fun installLabel(@Body requestBody: RequestBody): String + suspend fun installLabel( + @PartMap jsonMarker: Map, + @Part fileBuffer1: MultipartBody.Part?, + @Part fileBuffer2: MultipartBody.Part?, + @Part fileBuffer3: MultipartBody.Part? + ): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 1549f93..6e6f1ae 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -7,7 +7,11 @@ import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody +import java.io.File object RetrofitServiceManager { private val api by lazy { @@ -68,6 +72,7 @@ /** * 安装新标识器 + * Multipart上传图片,文件,带多参数上传 */ suspend fun installLabel( companyId: String, @@ -95,7 +100,8 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ): String { val param = JsonObject() param.addProperty("companyId", companyId) @@ -127,6 +133,31 @@ val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return api.installLabel(requestBody) + val res = HashMap() + res["jsonMarker"] = requestBody + + val multiParts = ArrayList() + realPaths.forEachIndexed { index, s -> + val file = File(s) + val fileMultipart = MultipartBody.Part.createFormData( + "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) + ) + multiParts.add(fileMultipart) + } + + return when (multiParts.size) { + 3 -> { + api.installLabel(res, multiParts[0], multiParts[1], multiParts[2]) + } + 2 -> { + api.installLabel(res, multiParts[0], multiParts[1], null) + } + 1 -> { + api.installLabel(res, multiParts[0], null, null) + } + else -> { + api.installLabel(res, null, null, null) + } + } } } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Int.kt b/app/src/main/java/com/casic/detector/extensions/Int.kt index 10275bb..d67cac8 100644 --- a/app/src/main/java/com/casic/detector/extensions/Int.kt +++ b/app/src/main/java/com/casic/detector/extensions/Int.kt @@ -13,4 +13,12 @@ paint.color = color canvas.drawArc(rectF, 0f, 360f, true, paint) return bitmap +} + +fun Int.appendZero(): String { + return if (this < 10) { + "0$this" + } else { + this.toString() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index 7352dc1..aacd89d 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -45,6 +45,36 @@ } } +fun String.toObjectType(): String { + return if (this == LocaleConstant.POINT_TYPE_ARRAY[0]) { + "1" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[1]) { + "2" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[2]) { + "3" + } else { + "4" + } +} + +fun String.toColor(): String { + return if (this == LocaleConstant.COLOR_ARRAY[0]) { + "0" + } else if (this == LocaleConstant.COLOR_ARRAY[1]) { + "1" + } else if (this == LocaleConstant.COLOR_ARRAY[2]) { + "2" + } else if (this == LocaleConstant.COLOR_ARRAY[3]) { + "3" + } else if (this == LocaleConstant.COLOR_ARRAY[4]) { + "4" + } else if (this == LocaleConstant.COLOR_ARRAY[5]) { + "5" + } else { + "6" + } +} + fun String.compressImage(context: Context, listener: OnImageCompressListener) { Luban.with(context) .load(this) @@ -63,4 +93,14 @@ listener.onError(e) } }).launch() +} + +//根据控件名字存默认值 +fun String.setDefaultValue(value: String) { + SaveKeyValues.putValue(this, value) +} + +//根据控件名字取默认值 +fun String.getDefaultValue(): String { + return SaveKeyValues.getValue(this, "") as String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 6ee3191..9e862aa 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -1,10 +1,8 @@ package com.casic.detector.retrofit +import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query +import retrofit2.http.* interface RetrofitService { /** @@ -56,6 +54,12 @@ /** * 安装新标识器 */ + @Multipart @POST("/ems/marker/save-marker-photo.do") - suspend fun installLabel(@Body requestBody: RequestBody): String + suspend fun installLabel( + @PartMap jsonMarker: Map, + @Part fileBuffer1: MultipartBody.Part?, + @Part fileBuffer2: MultipartBody.Part?, + @Part fileBuffer3: MultipartBody.Part? + ): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 1549f93..6e6f1ae 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -7,7 +7,11 @@ import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody +import java.io.File object RetrofitServiceManager { private val api by lazy { @@ -68,6 +72,7 @@ /** * 安装新标识器 + * Multipart上传图片,文件,带多参数上传 */ suspend fun installLabel( companyId: String, @@ -95,7 +100,8 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ): String { val param = JsonObject() param.addProperty("companyId", companyId) @@ -127,6 +133,31 @@ val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return api.installLabel(requestBody) + val res = HashMap() + res["jsonMarker"] = requestBody + + val multiParts = ArrayList() + realPaths.forEachIndexed { index, s -> + val file = File(s) + val fileMultipart = MultipartBody.Part.createFormData( + "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) + ) + multiParts.add(fileMultipart) + } + + return when (multiParts.size) { + 3 -> { + api.installLabel(res, multiParts[0], multiParts[1], multiParts[2]) + } + 2 -> { + api.installLabel(res, multiParts[0], multiParts[1], null) + } + 1 -> { + api.installLabel(res, multiParts[0], null, null) + } + else -> { + api.installLabel(res, null, null, null) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt index 5bb7fbe..e34bbb8 100644 --- a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt @@ -22,16 +22,17 @@ const val USER_NAME = "USER_NAME" const val USER_ID = "USER_ID" const val USER_COMPANY_ID = "USER_COMPANY_ID" + const val OBJECT_ID = "OBJECT_ID" const val SERVER_IP = "SERVER_IP" const val SERVER_PORT = "SERVER_PORT" const val APP_AUTHORITY = "com.casic.detector.fileprovider" val POPUP_TITLES = arrayOf("更新数据", "下载工单", "关于软件", "事件上报", "标识器补全") - var POINT_TYPE_ARRAY = arrayOf("", "管线", "管线附属物", "管线特征管点", "交叉穿越点") + var POINT_TYPE_ARRAY = arrayOf("管线", "管线附属物", "管线特征管点", "交叉穿越点") var SPINNER_ARRAY = arrayOf("标识器ID", "所属区域", "所属线路", "所属道路", "权属单位", "安装部门", "安装时间", "备注") - var PIPE_MATERIAL_ARRAY = arrayOf("", "铸铁", "塑料") - var DOWN_PIPE_TYPE_ARRAY = arrayOf("", "热力", "燃气", "供水", "电力", "通信") - var BURY_METHOD_ARRAY = arrayOf("", "直埋", "圆管", "管块", "管沟", "架空") + var PIPE_MATERIAL_ARRAY = arrayOf("铸铁", "塑料") + var DOWN_PIPE_TYPE_ARRAY = arrayOf("热力", "燃气", "供水", "电力", "通信") + var BURY_METHOD_ARRAY = arrayOf("直埋", "圆管", "管块", "管沟", "架空") var IDENTIFIER_TYPE_ARRAY = arrayOf("EM30", "EM50", "EM14") var COLOR_ARRAY = arrayOf("蓝色", "橙色", "红色", "黑色", "紫色", "黄色", "绿色") } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Int.kt b/app/src/main/java/com/casic/detector/extensions/Int.kt index 10275bb..d67cac8 100644 --- a/app/src/main/java/com/casic/detector/extensions/Int.kt +++ b/app/src/main/java/com/casic/detector/extensions/Int.kt @@ -13,4 +13,12 @@ paint.color = color canvas.drawArc(rectF, 0f, 360f, true, paint) return bitmap +} + +fun Int.appendZero(): String { + return if (this < 10) { + "0$this" + } else { + this.toString() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index 7352dc1..aacd89d 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -45,6 +45,36 @@ } } +fun String.toObjectType(): String { + return if (this == LocaleConstant.POINT_TYPE_ARRAY[0]) { + "1" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[1]) { + "2" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[2]) { + "3" + } else { + "4" + } +} + +fun String.toColor(): String { + return if (this == LocaleConstant.COLOR_ARRAY[0]) { + "0" + } else if (this == LocaleConstant.COLOR_ARRAY[1]) { + "1" + } else if (this == LocaleConstant.COLOR_ARRAY[2]) { + "2" + } else if (this == LocaleConstant.COLOR_ARRAY[3]) { + "3" + } else if (this == LocaleConstant.COLOR_ARRAY[4]) { + "4" + } else if (this == LocaleConstant.COLOR_ARRAY[5]) { + "5" + } else { + "6" + } +} + fun String.compressImage(context: Context, listener: OnImageCompressListener) { Luban.with(context) .load(this) @@ -63,4 +93,14 @@ listener.onError(e) } }).launch() +} + +//根据控件名字存默认值 +fun String.setDefaultValue(value: String) { + SaveKeyValues.putValue(this, value) +} + +//根据控件名字取默认值 +fun String.getDefaultValue(): String { + return SaveKeyValues.getValue(this, "") as String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 6ee3191..9e862aa 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -1,10 +1,8 @@ package com.casic.detector.retrofit +import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query +import retrofit2.http.* interface RetrofitService { /** @@ -56,6 +54,12 @@ /** * 安装新标识器 */ + @Multipart @POST("/ems/marker/save-marker-photo.do") - suspend fun installLabel(@Body requestBody: RequestBody): String + suspend fun installLabel( + @PartMap jsonMarker: Map, + @Part fileBuffer1: MultipartBody.Part?, + @Part fileBuffer2: MultipartBody.Part?, + @Part fileBuffer3: MultipartBody.Part? + ): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 1549f93..6e6f1ae 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -7,7 +7,11 @@ import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody +import java.io.File object RetrofitServiceManager { private val api by lazy { @@ -68,6 +72,7 @@ /** * 安装新标识器 + * Multipart上传图片,文件,带多参数上传 */ suspend fun installLabel( companyId: String, @@ -95,7 +100,8 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ): String { val param = JsonObject() param.addProperty("companyId", companyId) @@ -127,6 +133,31 @@ val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return api.installLabel(requestBody) + val res = HashMap() + res["jsonMarker"] = requestBody + + val multiParts = ArrayList() + realPaths.forEachIndexed { index, s -> + val file = File(s) + val fileMultipart = MultipartBody.Part.createFormData( + "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) + ) + multiParts.add(fileMultipart) + } + + return when (multiParts.size) { + 3 -> { + api.installLabel(res, multiParts[0], multiParts[1], multiParts[2]) + } + 2 -> { + api.installLabel(res, multiParts[0], multiParts[1], null) + } + 1 -> { + api.installLabel(res, multiParts[0], null, null) + } + else -> { + api.installLabel(res, null, null, null) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt index 5bb7fbe..e34bbb8 100644 --- a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt @@ -22,16 +22,17 @@ const val USER_NAME = "USER_NAME" const val USER_ID = "USER_ID" const val USER_COMPANY_ID = "USER_COMPANY_ID" + const val OBJECT_ID = "OBJECT_ID" const val SERVER_IP = "SERVER_IP" const val SERVER_PORT = "SERVER_PORT" const val APP_AUTHORITY = "com.casic.detector.fileprovider" val POPUP_TITLES = arrayOf("更新数据", "下载工单", "关于软件", "事件上报", "标识器补全") - var POINT_TYPE_ARRAY = arrayOf("", "管线", "管线附属物", "管线特征管点", "交叉穿越点") + var POINT_TYPE_ARRAY = arrayOf("管线", "管线附属物", "管线特征管点", "交叉穿越点") var SPINNER_ARRAY = arrayOf("标识器ID", "所属区域", "所属线路", "所属道路", "权属单位", "安装部门", "安装时间", "备注") - var PIPE_MATERIAL_ARRAY = arrayOf("", "铸铁", "塑料") - var DOWN_PIPE_TYPE_ARRAY = arrayOf("", "热力", "燃气", "供水", "电力", "通信") - var BURY_METHOD_ARRAY = arrayOf("", "直埋", "圆管", "管块", "管沟", "架空") + var PIPE_MATERIAL_ARRAY = arrayOf("铸铁", "塑料") + var DOWN_PIPE_TYPE_ARRAY = arrayOf("热力", "燃气", "供水", "电力", "通信") + var BURY_METHOD_ARRAY = arrayOf("直埋", "圆管", "管块", "管沟", "架空") var IDENTIFIER_TYPE_ARRAY = arrayOf("EM30", "EM50", "EM14") var COLOR_ARRAY = arrayOf("蓝色", "橙色", "红色", "黑色", "紫色", "黄色", "绿色") } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/BigImageActivity.kt b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt new file mode 100644 index 0000000..ca6c7d7 --- /dev/null +++ b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt @@ -0,0 +1,87 @@ +package com.casic.detector.view + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant +import com.pengxh.kt.lite.utils.ImmerseStatusBarUtil +import kotlinx.android.synthetic.main.activity_big_image.* + +class BigImageActivity : KotlinBaseActivity() { + + override fun initLayoutView(): Int = R.layout.activity_big_image + + override fun setupTopBarLayout() { + ImmerseStatusBarUtil.setColor(this, Color.BLACK) + leftBackView.setOnClickListener { finish() } + } + + override fun initData() { + + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + val index: Int = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + imagePagerView.adapter = BigImageAdapter(this, urls) + imagePagerView.currentItem = index + imagePagerView.offscreenPageLimit = imageSize + imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + pageNumberView.text = String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Int.kt b/app/src/main/java/com/casic/detector/extensions/Int.kt index 10275bb..d67cac8 100644 --- a/app/src/main/java/com/casic/detector/extensions/Int.kt +++ b/app/src/main/java/com/casic/detector/extensions/Int.kt @@ -13,4 +13,12 @@ paint.color = color canvas.drawArc(rectF, 0f, 360f, true, paint) return bitmap +} + +fun Int.appendZero(): String { + return if (this < 10) { + "0$this" + } else { + this.toString() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index 7352dc1..aacd89d 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -45,6 +45,36 @@ } } +fun String.toObjectType(): String { + return if (this == LocaleConstant.POINT_TYPE_ARRAY[0]) { + "1" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[1]) { + "2" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[2]) { + "3" + } else { + "4" + } +} + +fun String.toColor(): String { + return if (this == LocaleConstant.COLOR_ARRAY[0]) { + "0" + } else if (this == LocaleConstant.COLOR_ARRAY[1]) { + "1" + } else if (this == LocaleConstant.COLOR_ARRAY[2]) { + "2" + } else if (this == LocaleConstant.COLOR_ARRAY[3]) { + "3" + } else if (this == LocaleConstant.COLOR_ARRAY[4]) { + "4" + } else if (this == LocaleConstant.COLOR_ARRAY[5]) { + "5" + } else { + "6" + } +} + fun String.compressImage(context: Context, listener: OnImageCompressListener) { Luban.with(context) .load(this) @@ -63,4 +93,14 @@ listener.onError(e) } }).launch() +} + +//根据控件名字存默认值 +fun String.setDefaultValue(value: String) { + SaveKeyValues.putValue(this, value) +} + +//根据控件名字取默认值 +fun String.getDefaultValue(): String { + return SaveKeyValues.getValue(this, "") as String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 6ee3191..9e862aa 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -1,10 +1,8 @@ package com.casic.detector.retrofit +import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query +import retrofit2.http.* interface RetrofitService { /** @@ -56,6 +54,12 @@ /** * 安装新标识器 */ + @Multipart @POST("/ems/marker/save-marker-photo.do") - suspend fun installLabel(@Body requestBody: RequestBody): String + suspend fun installLabel( + @PartMap jsonMarker: Map, + @Part fileBuffer1: MultipartBody.Part?, + @Part fileBuffer2: MultipartBody.Part?, + @Part fileBuffer3: MultipartBody.Part? + ): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 1549f93..6e6f1ae 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -7,7 +7,11 @@ import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody +import java.io.File object RetrofitServiceManager { private val api by lazy { @@ -68,6 +72,7 @@ /** * 安装新标识器 + * Multipart上传图片,文件,带多参数上传 */ suspend fun installLabel( companyId: String, @@ -95,7 +100,8 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ): String { val param = JsonObject() param.addProperty("companyId", companyId) @@ -127,6 +133,31 @@ val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return api.installLabel(requestBody) + val res = HashMap() + res["jsonMarker"] = requestBody + + val multiParts = ArrayList() + realPaths.forEachIndexed { index, s -> + val file = File(s) + val fileMultipart = MultipartBody.Part.createFormData( + "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) + ) + multiParts.add(fileMultipart) + } + + return when (multiParts.size) { + 3 -> { + api.installLabel(res, multiParts[0], multiParts[1], multiParts[2]) + } + 2 -> { + api.installLabel(res, multiParts[0], multiParts[1], null) + } + 1 -> { + api.installLabel(res, multiParts[0], null, null) + } + else -> { + api.installLabel(res, null, null, null) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt index 5bb7fbe..e34bbb8 100644 --- a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt @@ -22,16 +22,17 @@ const val USER_NAME = "USER_NAME" const val USER_ID = "USER_ID" const val USER_COMPANY_ID = "USER_COMPANY_ID" + const val OBJECT_ID = "OBJECT_ID" const val SERVER_IP = "SERVER_IP" const val SERVER_PORT = "SERVER_PORT" const val APP_AUTHORITY = "com.casic.detector.fileprovider" val POPUP_TITLES = arrayOf("更新数据", "下载工单", "关于软件", "事件上报", "标识器补全") - var POINT_TYPE_ARRAY = arrayOf("", "管线", "管线附属物", "管线特征管点", "交叉穿越点") + var POINT_TYPE_ARRAY = arrayOf("管线", "管线附属物", "管线特征管点", "交叉穿越点") var SPINNER_ARRAY = arrayOf("标识器ID", "所属区域", "所属线路", "所属道路", "权属单位", "安装部门", "安装时间", "备注") - var PIPE_MATERIAL_ARRAY = arrayOf("", "铸铁", "塑料") - var DOWN_PIPE_TYPE_ARRAY = arrayOf("", "热力", "燃气", "供水", "电力", "通信") - var BURY_METHOD_ARRAY = arrayOf("", "直埋", "圆管", "管块", "管沟", "架空") + var PIPE_MATERIAL_ARRAY = arrayOf("铸铁", "塑料") + var DOWN_PIPE_TYPE_ARRAY = arrayOf("热力", "燃气", "供水", "电力", "通信") + var BURY_METHOD_ARRAY = arrayOf("直埋", "圆管", "管块", "管沟", "架空") var IDENTIFIER_TYPE_ARRAY = arrayOf("EM30", "EM50", "EM14") var COLOR_ARRAY = arrayOf("蓝色", "橙色", "红色", "黑色", "紫色", "黄色", "绿色") } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/BigImageActivity.kt b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt new file mode 100644 index 0000000..ca6c7d7 --- /dev/null +++ b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt @@ -0,0 +1,87 @@ +package com.casic.detector.view + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant +import com.pengxh.kt.lite.utils.ImmerseStatusBarUtil +import kotlinx.android.synthetic.main.activity_big_image.* + +class BigImageActivity : KotlinBaseActivity() { + + override fun initLayoutView(): Int = R.layout.activity_big_image + + override fun setupTopBarLayout() { + ImmerseStatusBarUtil.setColor(this, Color.BLACK) + leftBackView.setOnClickListener { finish() } + } + + override fun initData() { + + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + val index: Int = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + imagePagerView.adapter = BigImageAdapter(this, urls) + imagePagerView.currentItem = index + imagePagerView.offscreenPageLimit = imageSize + imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + pageNumberView.text = String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt index d61bec9..02b455f 100644 --- a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt @@ -1,43 +1,50 @@ package com.casic.detector.view +import android.annotation.SuppressLint +import android.app.DatePickerDialog import android.content.Context +import android.content.Intent +import android.provider.Settings import android.view.View +import androidx.lifecycle.ViewModelProvider import com.amap.api.location.AMapLocation import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback +import com.casic.detector.adapter.EditableImageAdapter +import com.casic.detector.bean.LabelBean import com.casic.detector.callback.ILocationListener import com.casic.detector.callback.OnImageCompressListener import com.casic.detector.callback.OnItemSelectedListener -import com.casic.detector.extensions.compressImage -import com.casic.detector.extensions.initLayoutImmersionBar -import com.casic.detector.extensions.show -import com.casic.detector.extensions.showDatePicker +import com.casic.detector.extensions.* +import com.casic.detector.utils.DataBaseManager +import com.casic.detector.utils.LoadingDialogHub import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity +import com.casic.detector.vm.TaskViewModel import com.gyf.immersionbar.ImmersionBar import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType import com.luck.picture.lib.entity.LocalMedia import com.luck.picture.lib.interfaces.OnResultCallbackListener -import com.pengxh.kt.lite.adapter.EditableImageAdapter import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.extensions.timestampToCompleteDate +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.vm.LoadState +import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog import kotlinx.android.synthetic.main.activity_install_label.* import kotlinx.android.synthetic.main.include_base_title.* import kotlinx.android.synthetic.main.include_install_label_identifier.* import kotlinx.android.synthetic.main.include_install_label_object.* import kotlinx.android.synthetic.main.include_install_label_open_camera.* import java.io.File +import java.util.* +@SuppressLint("SetTextI18n") class InstallLabelActivity : KotlinBaseActivity() { private val kTag = "InstallLabelActivity" private val context: Context = this@InstallLabelActivity + private val calendar by lazy { Calendar.getInstance() } private lateinit var imageAdapter: EditableImageAdapter - private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 private val realPaths: ArrayList = ArrayList() //真实图片路径 private var objectTypeSelectedItem = "" private var materialSelectedItem = "" @@ -46,17 +53,33 @@ private var buryMethodSelectedItem = "" private var identifierTypeSelectedItem = "" private var colorSelectedItem = "" + private lateinit var taskViewModel: TaskViewModel override fun initData() { imageAdapter = EditableImageAdapter(this, 3, 3f) addImageRecyclerView.adapter = imageAdapter + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + //设置默认值 + markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue()) + pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue()) + buryDeepView.setText("buryDeepView".getDefaultValue()) + downPipeDiameterView.setText("downPipeDiameterView".getDefaultValue()) + downPointDeepView.setText("downPointDeepView".getDefaultValue()) + areaView.setText("areaView".getDefaultValue()) + lineView.setText("lineView".getDefaultValue()) + roadView.setText("roadView".getDefaultValue()) + ownerView.setText("ownerView".getDefaultValue()) + identifierDeepView.setText("identifierDeepView".getDefaultValue()) + personDeptView.setText("personDeptView".getDefaultValue()) } override fun initEvent() { leftBackView.setOnClickListener { finish() } /**************************************************************************************/ - objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 1, + objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { objectTypeSelectedItem = default @@ -67,7 +90,7 @@ } }) - materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { materialSelectedItem = default @@ -78,7 +101,7 @@ } }) - downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 1, + downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeSelectedItem = default @@ -89,7 +112,7 @@ } }) - downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeMaterialSelectedItem = default @@ -100,7 +123,7 @@ } }) - buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 1, + buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { buryMethodSelectedItem = default @@ -112,11 +135,15 @@ }) constructDateView.setOnClickListener { - showDatePicker(DateEntity.today(), object : DateSelectedCallback { - override fun onDateSelected(date: String) { - constructDateView.text = date - } - }) + val year = calendar.get(Calendar.YEAR) + val month = calendar.get(Calendar.MONTH) + val day = calendar.get(Calendar.DAY_OF_MONTH) + val datePicker = DatePickerDialog(this, { _, y, m, d -> + constructDateView.text = String.format( + "%s-%s-%s", y, m.appendZero(), d.appendZero() + ) + }, year, month, day) + datePicker.show() } identifierTypeSpinner.show(this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0, @@ -161,16 +188,153 @@ if (realPaths[position].isEmpty()) { "图片加载失败,无法查看大图".show(context) } else { -// context.navigatePageTo(position, realPaths) + context.navigatePageTo(position, realPaths) } } override fun onItemLongClick(view: View?, position: Int) { - imagePaths.removeAt(position) imageAdapter.deleteImage(position) } }) /**************************************************************************************/ + installButton.setOnClickListener { + if (isNetworkConnected()) { + val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + if (markerObjectTypeView.text.isNullOrBlank()) { + when (objectTypeSelectedItem) { + "管线" -> { + "请输入管线种类!".show(this) + } + "管线附属物" -> { + "请输入附属物名称!".show(this) + } + "管线特征管点" -> { + "请输入特征管点!".show(this) + } + "交叉穿越点" -> { + "请输入上层管种类!".show(this) + } + } + return@setOnClickListener + } + + if (pipelineDiameterView.text.isNullOrBlank()) { + "请输入管径".show(this) + return@setOnClickListener + } + + if (buryDeepView.text.isNullOrBlank()) { + "请输入埋深".show(this) + return@setOnClickListener + } + + if (downPipeDiameterView.text.isNullOrBlank()) { + "请输入下层管管径".show(this) + return@setOnClickListener + } + + if (areaView.text.isNullOrBlank()) { + "请输入所属区域".show(this) + return@setOnClickListener + } + + if (lineView.text.isNullOrBlank()) { + "请输入所属线路".show(this) + return@setOnClickListener + } + + if (roadView.text.isNullOrBlank()) { + "请输入所属道路".show(this) + return@setOnClickListener + } + + if (constructDateView.text.isNullOrBlank()) { + "请选择建设年代".show(this) + return@setOnClickListener + } + + if (ownerView.text.isNullOrBlank()) { + "请输入权属单位".show(this) + return@setOnClickListener + } + + if (identifierIdView.text.isNullOrBlank()) { + "请先读取标识器获取ID".show(this) + return@setOnClickListener + } + + if (identifierDeepView.text.isNullOrBlank()) { + "请输入标识器埋深".show(this) + return@setOnClickListener + } + + if (personDeptView.text.isNullOrBlank()) { + "请输入标识器安装部门".show(this) + return@setOnClickListener + } + + taskViewModel.installLabel( + companyId, + objectTypeSelectedItem.toObjectType(), + markerObjectTypeView.text.toString(), + materialSelectedItem, + "${pipelineDiameterView.text}mm", + "${buryDeepView.text}mm", + downPipeSelectedItem, + downPipeMaterialSelectedItem, + "${downPipeDiameterView.text}mm", + "${downPointDeepView.text}mm", + buryMethodSelectedItem, + areaView.text.toString(), + lineView.text.toString(), + roadView.text.toString(), + constructDateView.text.toString(), + ownerView.text.toString(), + objectId, + identifierIdView.text.toString(), + identifierTypeSelectedItem, + "${identifierDeepView.text}mm", + personDeptView.text.toString(), + installTimeView.text.toString(), + lngView.text.toString(), + latView.text.toString(), + colorSelectedItem.toColor(), + remarkView.text.toString(), + realPaths + ) + + //保存默认值 + "markerObjectTypeView".setDefaultValue(markerObjectTypeView.text.toString()) + "pipelineDiameterView".setDefaultValue(pipelineDiameterView.text.toString()) + "buryDeepView".setDefaultValue(buryDeepView.text.toString()) + "downPipeDiameterView".setDefaultValue(downPipeDiameterView.text.toString()) + "downPointDeepView".setDefaultValue(downPointDeepView.text.toString()) + "areaView".setDefaultValue(areaView.text.toString()) + "lineView".setDefaultValue(lineView.text.toString()) + "roadView".setDefaultValue(roadView.text.toString()) + "ownerView".setDefaultValue(ownerView.text.toString()) + "identifierDeepView".setDefaultValue(identifierDeepView.text.toString()) + "personDeptView".setDefaultValue(personDeptView.text.toString()) + } else { + NoNetworkDialog.Builder() + .setContext(context) + .setOnDialogButtonClickListener(object : + NoNetworkDialog.OnDialogButtonClickListener { + override fun onButtonClick() { + val intent = Intent(Settings.ACTION_SETTINGS) + startActivity(intent) + } + }).build().show() + } + } + + //TODO 搜索标识器 + readLabelButton.setOnClickListener { + LoadingDialogHub.show(this, "正在搜索标识器,请稍后...") + identifierIdView.text = "123456789" + LoadingDialogHub.dismiss() + } } private fun takePicture() { @@ -191,11 +355,11 @@ } private fun analyticalSelectResults(result: LocalMedia) { - //压缩图片后上传 + //压缩图片 result.realPath.compressImage(this, object : OnImageCompressListener { override fun onSuccess(file: File) { - //上传图片 -// fileUploadViewModel.uploadFile(file) + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) } override fun onError(e: Throwable) { @@ -207,7 +371,51 @@ override fun initLayoutView(): Int = R.layout.activity_install_label override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...") + LoadState.Success -> { + saveLabelInLocal() + LoadingDialogHub.dismiss() + finish() + } + else -> LoadingDialogHub.dismiss() + } + } + } + //安装成功后将标识器保存在本地 + private fun saveLabelInLocal() { + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + + val labelBean = LabelBean() + labelBean.objectType = objectTypeSelectedItem + labelBean.pipelineType = markerObjectTypeView.text.toString() + labelBean.pipelineMaterial = materialSelectedItem + labelBean.pipelineDiameter = "${pipelineDiameterView.text}mm" + labelBean.buryDeep = "${buryDeepView.text}mm" + labelBean.lowerType = downPipeSelectedItem + labelBean.lowerMaterial = downPipeMaterialSelectedItem + labelBean.lowerDiameter = "${downPipeDiameterView.text}mm" + labelBean.lowerDeep = "${downPointDeepView.text}mm" + labelBean.buryMethod = buryMethodSelectedItem + labelBean.area = areaView.text.toString() + labelBean.line = lineView.text.toString() + labelBean.road = roadView.text.toString() + labelBean.constructTime = constructDateView.text.toString() + labelBean.owner = ownerView.text.toString() + labelBean.objectId = objectId + labelBean.identifierId = identifierIdView.text.toString() + labelBean.identifierType = identifierTypeSelectedItem + labelBean.identifierDeep = "${identifierDeepView.text}mm" + labelBean.person = personDeptView.text.toString() + labelBean.installTime = installTimeView.text.toString() + labelBean.lng = lngView.text.toString() + labelBean.lat = latView.text.toString() + labelBean.color = colorSelectedItem.toColor() + labelBean.remark = remarkView.text.toString() + + DataBaseManager.get.insertTaskLabel(labelBean) } override fun setupTopBarLayout() { diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Int.kt b/app/src/main/java/com/casic/detector/extensions/Int.kt index 10275bb..d67cac8 100644 --- a/app/src/main/java/com/casic/detector/extensions/Int.kt +++ b/app/src/main/java/com/casic/detector/extensions/Int.kt @@ -13,4 +13,12 @@ paint.color = color canvas.drawArc(rectF, 0f, 360f, true, paint) return bitmap +} + +fun Int.appendZero(): String { + return if (this < 10) { + "0$this" + } else { + this.toString() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index 7352dc1..aacd89d 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -45,6 +45,36 @@ } } +fun String.toObjectType(): String { + return if (this == LocaleConstant.POINT_TYPE_ARRAY[0]) { + "1" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[1]) { + "2" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[2]) { + "3" + } else { + "4" + } +} + +fun String.toColor(): String { + return if (this == LocaleConstant.COLOR_ARRAY[0]) { + "0" + } else if (this == LocaleConstant.COLOR_ARRAY[1]) { + "1" + } else if (this == LocaleConstant.COLOR_ARRAY[2]) { + "2" + } else if (this == LocaleConstant.COLOR_ARRAY[3]) { + "3" + } else if (this == LocaleConstant.COLOR_ARRAY[4]) { + "4" + } else if (this == LocaleConstant.COLOR_ARRAY[5]) { + "5" + } else { + "6" + } +} + fun String.compressImage(context: Context, listener: OnImageCompressListener) { Luban.with(context) .load(this) @@ -63,4 +93,14 @@ listener.onError(e) } }).launch() +} + +//根据控件名字存默认值 +fun String.setDefaultValue(value: String) { + SaveKeyValues.putValue(this, value) +} + +//根据控件名字取默认值 +fun String.getDefaultValue(): String { + return SaveKeyValues.getValue(this, "") as String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 6ee3191..9e862aa 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -1,10 +1,8 @@ package com.casic.detector.retrofit +import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query +import retrofit2.http.* interface RetrofitService { /** @@ -56,6 +54,12 @@ /** * 安装新标识器 */ + @Multipart @POST("/ems/marker/save-marker-photo.do") - suspend fun installLabel(@Body requestBody: RequestBody): String + suspend fun installLabel( + @PartMap jsonMarker: Map, + @Part fileBuffer1: MultipartBody.Part?, + @Part fileBuffer2: MultipartBody.Part?, + @Part fileBuffer3: MultipartBody.Part? + ): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 1549f93..6e6f1ae 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -7,7 +7,11 @@ import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody +import java.io.File object RetrofitServiceManager { private val api by lazy { @@ -68,6 +72,7 @@ /** * 安装新标识器 + * Multipart上传图片,文件,带多参数上传 */ suspend fun installLabel( companyId: String, @@ -95,7 +100,8 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ): String { val param = JsonObject() param.addProperty("companyId", companyId) @@ -127,6 +133,31 @@ val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return api.installLabel(requestBody) + val res = HashMap() + res["jsonMarker"] = requestBody + + val multiParts = ArrayList() + realPaths.forEachIndexed { index, s -> + val file = File(s) + val fileMultipart = MultipartBody.Part.createFormData( + "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) + ) + multiParts.add(fileMultipart) + } + + return when (multiParts.size) { + 3 -> { + api.installLabel(res, multiParts[0], multiParts[1], multiParts[2]) + } + 2 -> { + api.installLabel(res, multiParts[0], multiParts[1], null) + } + 1 -> { + api.installLabel(res, multiParts[0], null, null) + } + else -> { + api.installLabel(res, null, null, null) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt index 5bb7fbe..e34bbb8 100644 --- a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt @@ -22,16 +22,17 @@ const val USER_NAME = "USER_NAME" const val USER_ID = "USER_ID" const val USER_COMPANY_ID = "USER_COMPANY_ID" + const val OBJECT_ID = "OBJECT_ID" const val SERVER_IP = "SERVER_IP" const val SERVER_PORT = "SERVER_PORT" const val APP_AUTHORITY = "com.casic.detector.fileprovider" val POPUP_TITLES = arrayOf("更新数据", "下载工单", "关于软件", "事件上报", "标识器补全") - var POINT_TYPE_ARRAY = arrayOf("", "管线", "管线附属物", "管线特征管点", "交叉穿越点") + var POINT_TYPE_ARRAY = arrayOf("管线", "管线附属物", "管线特征管点", "交叉穿越点") var SPINNER_ARRAY = arrayOf("标识器ID", "所属区域", "所属线路", "所属道路", "权属单位", "安装部门", "安装时间", "备注") - var PIPE_MATERIAL_ARRAY = arrayOf("", "铸铁", "塑料") - var DOWN_PIPE_TYPE_ARRAY = arrayOf("", "热力", "燃气", "供水", "电力", "通信") - var BURY_METHOD_ARRAY = arrayOf("", "直埋", "圆管", "管块", "管沟", "架空") + var PIPE_MATERIAL_ARRAY = arrayOf("铸铁", "塑料") + var DOWN_PIPE_TYPE_ARRAY = arrayOf("热力", "燃气", "供水", "电力", "通信") + var BURY_METHOD_ARRAY = arrayOf("直埋", "圆管", "管块", "管沟", "架空") var IDENTIFIER_TYPE_ARRAY = arrayOf("EM30", "EM50", "EM14") var COLOR_ARRAY = arrayOf("蓝色", "橙色", "红色", "黑色", "紫色", "黄色", "绿色") } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/BigImageActivity.kt b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt new file mode 100644 index 0000000..ca6c7d7 --- /dev/null +++ b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt @@ -0,0 +1,87 @@ +package com.casic.detector.view + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant +import com.pengxh.kt.lite.utils.ImmerseStatusBarUtil +import kotlinx.android.synthetic.main.activity_big_image.* + +class BigImageActivity : KotlinBaseActivity() { + + override fun initLayoutView(): Int = R.layout.activity_big_image + + override fun setupTopBarLayout() { + ImmerseStatusBarUtil.setColor(this, Color.BLACK) + leftBackView.setOnClickListener { finish() } + } + + override fun initData() { + + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + val index: Int = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + imagePagerView.adapter = BigImageAdapter(this, urls) + imagePagerView.currentItem = index + imagePagerView.offscreenPageLimit = imageSize + imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + pageNumberView.text = String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt index d61bec9..02b455f 100644 --- a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt @@ -1,43 +1,50 @@ package com.casic.detector.view +import android.annotation.SuppressLint +import android.app.DatePickerDialog import android.content.Context +import android.content.Intent +import android.provider.Settings import android.view.View +import androidx.lifecycle.ViewModelProvider import com.amap.api.location.AMapLocation import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback +import com.casic.detector.adapter.EditableImageAdapter +import com.casic.detector.bean.LabelBean import com.casic.detector.callback.ILocationListener import com.casic.detector.callback.OnImageCompressListener import com.casic.detector.callback.OnItemSelectedListener -import com.casic.detector.extensions.compressImage -import com.casic.detector.extensions.initLayoutImmersionBar -import com.casic.detector.extensions.show -import com.casic.detector.extensions.showDatePicker +import com.casic.detector.extensions.* +import com.casic.detector.utils.DataBaseManager +import com.casic.detector.utils.LoadingDialogHub import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity +import com.casic.detector.vm.TaskViewModel import com.gyf.immersionbar.ImmersionBar import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType import com.luck.picture.lib.entity.LocalMedia import com.luck.picture.lib.interfaces.OnResultCallbackListener -import com.pengxh.kt.lite.adapter.EditableImageAdapter import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.extensions.timestampToCompleteDate +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.vm.LoadState +import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog import kotlinx.android.synthetic.main.activity_install_label.* import kotlinx.android.synthetic.main.include_base_title.* import kotlinx.android.synthetic.main.include_install_label_identifier.* import kotlinx.android.synthetic.main.include_install_label_object.* import kotlinx.android.synthetic.main.include_install_label_open_camera.* import java.io.File +import java.util.* +@SuppressLint("SetTextI18n") class InstallLabelActivity : KotlinBaseActivity() { private val kTag = "InstallLabelActivity" private val context: Context = this@InstallLabelActivity + private val calendar by lazy { Calendar.getInstance() } private lateinit var imageAdapter: EditableImageAdapter - private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 private val realPaths: ArrayList = ArrayList() //真实图片路径 private var objectTypeSelectedItem = "" private var materialSelectedItem = "" @@ -46,17 +53,33 @@ private var buryMethodSelectedItem = "" private var identifierTypeSelectedItem = "" private var colorSelectedItem = "" + private lateinit var taskViewModel: TaskViewModel override fun initData() { imageAdapter = EditableImageAdapter(this, 3, 3f) addImageRecyclerView.adapter = imageAdapter + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + //设置默认值 + markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue()) + pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue()) + buryDeepView.setText("buryDeepView".getDefaultValue()) + downPipeDiameterView.setText("downPipeDiameterView".getDefaultValue()) + downPointDeepView.setText("downPointDeepView".getDefaultValue()) + areaView.setText("areaView".getDefaultValue()) + lineView.setText("lineView".getDefaultValue()) + roadView.setText("roadView".getDefaultValue()) + ownerView.setText("ownerView".getDefaultValue()) + identifierDeepView.setText("identifierDeepView".getDefaultValue()) + personDeptView.setText("personDeptView".getDefaultValue()) } override fun initEvent() { leftBackView.setOnClickListener { finish() } /**************************************************************************************/ - objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 1, + objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { objectTypeSelectedItem = default @@ -67,7 +90,7 @@ } }) - materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { materialSelectedItem = default @@ -78,7 +101,7 @@ } }) - downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 1, + downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeSelectedItem = default @@ -89,7 +112,7 @@ } }) - downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeMaterialSelectedItem = default @@ -100,7 +123,7 @@ } }) - buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 1, + buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { buryMethodSelectedItem = default @@ -112,11 +135,15 @@ }) constructDateView.setOnClickListener { - showDatePicker(DateEntity.today(), object : DateSelectedCallback { - override fun onDateSelected(date: String) { - constructDateView.text = date - } - }) + val year = calendar.get(Calendar.YEAR) + val month = calendar.get(Calendar.MONTH) + val day = calendar.get(Calendar.DAY_OF_MONTH) + val datePicker = DatePickerDialog(this, { _, y, m, d -> + constructDateView.text = String.format( + "%s-%s-%s", y, m.appendZero(), d.appendZero() + ) + }, year, month, day) + datePicker.show() } identifierTypeSpinner.show(this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0, @@ -161,16 +188,153 @@ if (realPaths[position].isEmpty()) { "图片加载失败,无法查看大图".show(context) } else { -// context.navigatePageTo(position, realPaths) + context.navigatePageTo(position, realPaths) } } override fun onItemLongClick(view: View?, position: Int) { - imagePaths.removeAt(position) imageAdapter.deleteImage(position) } }) /**************************************************************************************/ + installButton.setOnClickListener { + if (isNetworkConnected()) { + val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + if (markerObjectTypeView.text.isNullOrBlank()) { + when (objectTypeSelectedItem) { + "管线" -> { + "请输入管线种类!".show(this) + } + "管线附属物" -> { + "请输入附属物名称!".show(this) + } + "管线特征管点" -> { + "请输入特征管点!".show(this) + } + "交叉穿越点" -> { + "请输入上层管种类!".show(this) + } + } + return@setOnClickListener + } + + if (pipelineDiameterView.text.isNullOrBlank()) { + "请输入管径".show(this) + return@setOnClickListener + } + + if (buryDeepView.text.isNullOrBlank()) { + "请输入埋深".show(this) + return@setOnClickListener + } + + if (downPipeDiameterView.text.isNullOrBlank()) { + "请输入下层管管径".show(this) + return@setOnClickListener + } + + if (areaView.text.isNullOrBlank()) { + "请输入所属区域".show(this) + return@setOnClickListener + } + + if (lineView.text.isNullOrBlank()) { + "请输入所属线路".show(this) + return@setOnClickListener + } + + if (roadView.text.isNullOrBlank()) { + "请输入所属道路".show(this) + return@setOnClickListener + } + + if (constructDateView.text.isNullOrBlank()) { + "请选择建设年代".show(this) + return@setOnClickListener + } + + if (ownerView.text.isNullOrBlank()) { + "请输入权属单位".show(this) + return@setOnClickListener + } + + if (identifierIdView.text.isNullOrBlank()) { + "请先读取标识器获取ID".show(this) + return@setOnClickListener + } + + if (identifierDeepView.text.isNullOrBlank()) { + "请输入标识器埋深".show(this) + return@setOnClickListener + } + + if (personDeptView.text.isNullOrBlank()) { + "请输入标识器安装部门".show(this) + return@setOnClickListener + } + + taskViewModel.installLabel( + companyId, + objectTypeSelectedItem.toObjectType(), + markerObjectTypeView.text.toString(), + materialSelectedItem, + "${pipelineDiameterView.text}mm", + "${buryDeepView.text}mm", + downPipeSelectedItem, + downPipeMaterialSelectedItem, + "${downPipeDiameterView.text}mm", + "${downPointDeepView.text}mm", + buryMethodSelectedItem, + areaView.text.toString(), + lineView.text.toString(), + roadView.text.toString(), + constructDateView.text.toString(), + ownerView.text.toString(), + objectId, + identifierIdView.text.toString(), + identifierTypeSelectedItem, + "${identifierDeepView.text}mm", + personDeptView.text.toString(), + installTimeView.text.toString(), + lngView.text.toString(), + latView.text.toString(), + colorSelectedItem.toColor(), + remarkView.text.toString(), + realPaths + ) + + //保存默认值 + "markerObjectTypeView".setDefaultValue(markerObjectTypeView.text.toString()) + "pipelineDiameterView".setDefaultValue(pipelineDiameterView.text.toString()) + "buryDeepView".setDefaultValue(buryDeepView.text.toString()) + "downPipeDiameterView".setDefaultValue(downPipeDiameterView.text.toString()) + "downPointDeepView".setDefaultValue(downPointDeepView.text.toString()) + "areaView".setDefaultValue(areaView.text.toString()) + "lineView".setDefaultValue(lineView.text.toString()) + "roadView".setDefaultValue(roadView.text.toString()) + "ownerView".setDefaultValue(ownerView.text.toString()) + "identifierDeepView".setDefaultValue(identifierDeepView.text.toString()) + "personDeptView".setDefaultValue(personDeptView.text.toString()) + } else { + NoNetworkDialog.Builder() + .setContext(context) + .setOnDialogButtonClickListener(object : + NoNetworkDialog.OnDialogButtonClickListener { + override fun onButtonClick() { + val intent = Intent(Settings.ACTION_SETTINGS) + startActivity(intent) + } + }).build().show() + } + } + + //TODO 搜索标识器 + readLabelButton.setOnClickListener { + LoadingDialogHub.show(this, "正在搜索标识器,请稍后...") + identifierIdView.text = "123456789" + LoadingDialogHub.dismiss() + } } private fun takePicture() { @@ -191,11 +355,11 @@ } private fun analyticalSelectResults(result: LocalMedia) { - //压缩图片后上传 + //压缩图片 result.realPath.compressImage(this, object : OnImageCompressListener { override fun onSuccess(file: File) { - //上传图片 -// fileUploadViewModel.uploadFile(file) + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) } override fun onError(e: Throwable) { @@ -207,7 +371,51 @@ override fun initLayoutView(): Int = R.layout.activity_install_label override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...") + LoadState.Success -> { + saveLabelInLocal() + LoadingDialogHub.dismiss() + finish() + } + else -> LoadingDialogHub.dismiss() + } + } + } + //安装成功后将标识器保存在本地 + private fun saveLabelInLocal() { + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + + val labelBean = LabelBean() + labelBean.objectType = objectTypeSelectedItem + labelBean.pipelineType = markerObjectTypeView.text.toString() + labelBean.pipelineMaterial = materialSelectedItem + labelBean.pipelineDiameter = "${pipelineDiameterView.text}mm" + labelBean.buryDeep = "${buryDeepView.text}mm" + labelBean.lowerType = downPipeSelectedItem + labelBean.lowerMaterial = downPipeMaterialSelectedItem + labelBean.lowerDiameter = "${downPipeDiameterView.text}mm" + labelBean.lowerDeep = "${downPointDeepView.text}mm" + labelBean.buryMethod = buryMethodSelectedItem + labelBean.area = areaView.text.toString() + labelBean.line = lineView.text.toString() + labelBean.road = roadView.text.toString() + labelBean.constructTime = constructDateView.text.toString() + labelBean.owner = ownerView.text.toString() + labelBean.objectId = objectId + labelBean.identifierId = identifierIdView.text.toString() + labelBean.identifierType = identifierTypeSelectedItem + labelBean.identifierDeep = "${identifierDeepView.text}mm" + labelBean.person = personDeptView.text.toString() + labelBean.installTime = installTimeView.text.toString() + labelBean.lng = lngView.text.toString() + labelBean.lat = latView.text.toString() + labelBean.color = colorSelectedItem.toColor() + labelBean.remark = remarkView.text.toString() + + DataBaseManager.get.insertTaskLabel(labelBean) } override fun setupTopBarLayout() { diff --git a/app/src/main/java/com/casic/detector/view/MainActivity.kt b/app/src/main/java/com/casic/detector/view/MainActivity.kt index cd06e07..9b791e9 100644 --- a/app/src/main/java/com/casic/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/detector/view/MainActivity.kt @@ -571,7 +571,8 @@ labelBean.lng, labelBean.lat, labelBean.color, - labelBean.remark + labelBean.remark, + arrayListOf() ) } LoadingDialogHub.dismiss() diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Int.kt b/app/src/main/java/com/casic/detector/extensions/Int.kt index 10275bb..d67cac8 100644 --- a/app/src/main/java/com/casic/detector/extensions/Int.kt +++ b/app/src/main/java/com/casic/detector/extensions/Int.kt @@ -13,4 +13,12 @@ paint.color = color canvas.drawArc(rectF, 0f, 360f, true, paint) return bitmap +} + +fun Int.appendZero(): String { + return if (this < 10) { + "0$this" + } else { + this.toString() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index 7352dc1..aacd89d 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -45,6 +45,36 @@ } } +fun String.toObjectType(): String { + return if (this == LocaleConstant.POINT_TYPE_ARRAY[0]) { + "1" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[1]) { + "2" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[2]) { + "3" + } else { + "4" + } +} + +fun String.toColor(): String { + return if (this == LocaleConstant.COLOR_ARRAY[0]) { + "0" + } else if (this == LocaleConstant.COLOR_ARRAY[1]) { + "1" + } else if (this == LocaleConstant.COLOR_ARRAY[2]) { + "2" + } else if (this == LocaleConstant.COLOR_ARRAY[3]) { + "3" + } else if (this == LocaleConstant.COLOR_ARRAY[4]) { + "4" + } else if (this == LocaleConstant.COLOR_ARRAY[5]) { + "5" + } else { + "6" + } +} + fun String.compressImage(context: Context, listener: OnImageCompressListener) { Luban.with(context) .load(this) @@ -63,4 +93,14 @@ listener.onError(e) } }).launch() +} + +//根据控件名字存默认值 +fun String.setDefaultValue(value: String) { + SaveKeyValues.putValue(this, value) +} + +//根据控件名字取默认值 +fun String.getDefaultValue(): String { + return SaveKeyValues.getValue(this, "") as String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 6ee3191..9e862aa 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -1,10 +1,8 @@ package com.casic.detector.retrofit +import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query +import retrofit2.http.* interface RetrofitService { /** @@ -56,6 +54,12 @@ /** * 安装新标识器 */ + @Multipart @POST("/ems/marker/save-marker-photo.do") - suspend fun installLabel(@Body requestBody: RequestBody): String + suspend fun installLabel( + @PartMap jsonMarker: Map, + @Part fileBuffer1: MultipartBody.Part?, + @Part fileBuffer2: MultipartBody.Part?, + @Part fileBuffer3: MultipartBody.Part? + ): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 1549f93..6e6f1ae 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -7,7 +7,11 @@ import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody +import java.io.File object RetrofitServiceManager { private val api by lazy { @@ -68,6 +72,7 @@ /** * 安装新标识器 + * Multipart上传图片,文件,带多参数上传 */ suspend fun installLabel( companyId: String, @@ -95,7 +100,8 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ): String { val param = JsonObject() param.addProperty("companyId", companyId) @@ -127,6 +133,31 @@ val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return api.installLabel(requestBody) + val res = HashMap() + res["jsonMarker"] = requestBody + + val multiParts = ArrayList() + realPaths.forEachIndexed { index, s -> + val file = File(s) + val fileMultipart = MultipartBody.Part.createFormData( + "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) + ) + multiParts.add(fileMultipart) + } + + return when (multiParts.size) { + 3 -> { + api.installLabel(res, multiParts[0], multiParts[1], multiParts[2]) + } + 2 -> { + api.installLabel(res, multiParts[0], multiParts[1], null) + } + 1 -> { + api.installLabel(res, multiParts[0], null, null) + } + else -> { + api.installLabel(res, null, null, null) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt index 5bb7fbe..e34bbb8 100644 --- a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt @@ -22,16 +22,17 @@ const val USER_NAME = "USER_NAME" const val USER_ID = "USER_ID" const val USER_COMPANY_ID = "USER_COMPANY_ID" + const val OBJECT_ID = "OBJECT_ID" const val SERVER_IP = "SERVER_IP" const val SERVER_PORT = "SERVER_PORT" const val APP_AUTHORITY = "com.casic.detector.fileprovider" val POPUP_TITLES = arrayOf("更新数据", "下载工单", "关于软件", "事件上报", "标识器补全") - var POINT_TYPE_ARRAY = arrayOf("", "管线", "管线附属物", "管线特征管点", "交叉穿越点") + var POINT_TYPE_ARRAY = arrayOf("管线", "管线附属物", "管线特征管点", "交叉穿越点") var SPINNER_ARRAY = arrayOf("标识器ID", "所属区域", "所属线路", "所属道路", "权属单位", "安装部门", "安装时间", "备注") - var PIPE_MATERIAL_ARRAY = arrayOf("", "铸铁", "塑料") - var DOWN_PIPE_TYPE_ARRAY = arrayOf("", "热力", "燃气", "供水", "电力", "通信") - var BURY_METHOD_ARRAY = arrayOf("", "直埋", "圆管", "管块", "管沟", "架空") + var PIPE_MATERIAL_ARRAY = arrayOf("铸铁", "塑料") + var DOWN_PIPE_TYPE_ARRAY = arrayOf("热力", "燃气", "供水", "电力", "通信") + var BURY_METHOD_ARRAY = arrayOf("直埋", "圆管", "管块", "管沟", "架空") var IDENTIFIER_TYPE_ARRAY = arrayOf("EM30", "EM50", "EM14") var COLOR_ARRAY = arrayOf("蓝色", "橙色", "红色", "黑色", "紫色", "黄色", "绿色") } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/BigImageActivity.kt b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt new file mode 100644 index 0000000..ca6c7d7 --- /dev/null +++ b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt @@ -0,0 +1,87 @@ +package com.casic.detector.view + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant +import com.pengxh.kt.lite.utils.ImmerseStatusBarUtil +import kotlinx.android.synthetic.main.activity_big_image.* + +class BigImageActivity : KotlinBaseActivity() { + + override fun initLayoutView(): Int = R.layout.activity_big_image + + override fun setupTopBarLayout() { + ImmerseStatusBarUtil.setColor(this, Color.BLACK) + leftBackView.setOnClickListener { finish() } + } + + override fun initData() { + + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + val index: Int = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + imagePagerView.adapter = BigImageAdapter(this, urls) + imagePagerView.currentItem = index + imagePagerView.offscreenPageLimit = imageSize + imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + pageNumberView.text = String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt index d61bec9..02b455f 100644 --- a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt @@ -1,43 +1,50 @@ package com.casic.detector.view +import android.annotation.SuppressLint +import android.app.DatePickerDialog import android.content.Context +import android.content.Intent +import android.provider.Settings import android.view.View +import androidx.lifecycle.ViewModelProvider import com.amap.api.location.AMapLocation import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback +import com.casic.detector.adapter.EditableImageAdapter +import com.casic.detector.bean.LabelBean import com.casic.detector.callback.ILocationListener import com.casic.detector.callback.OnImageCompressListener import com.casic.detector.callback.OnItemSelectedListener -import com.casic.detector.extensions.compressImage -import com.casic.detector.extensions.initLayoutImmersionBar -import com.casic.detector.extensions.show -import com.casic.detector.extensions.showDatePicker +import com.casic.detector.extensions.* +import com.casic.detector.utils.DataBaseManager +import com.casic.detector.utils.LoadingDialogHub import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity +import com.casic.detector.vm.TaskViewModel import com.gyf.immersionbar.ImmersionBar import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType import com.luck.picture.lib.entity.LocalMedia import com.luck.picture.lib.interfaces.OnResultCallbackListener -import com.pengxh.kt.lite.adapter.EditableImageAdapter import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.extensions.timestampToCompleteDate +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.vm.LoadState +import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog import kotlinx.android.synthetic.main.activity_install_label.* import kotlinx.android.synthetic.main.include_base_title.* import kotlinx.android.synthetic.main.include_install_label_identifier.* import kotlinx.android.synthetic.main.include_install_label_object.* import kotlinx.android.synthetic.main.include_install_label_open_camera.* import java.io.File +import java.util.* +@SuppressLint("SetTextI18n") class InstallLabelActivity : KotlinBaseActivity() { private val kTag = "InstallLabelActivity" private val context: Context = this@InstallLabelActivity + private val calendar by lazy { Calendar.getInstance() } private lateinit var imageAdapter: EditableImageAdapter - private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 private val realPaths: ArrayList = ArrayList() //真实图片路径 private var objectTypeSelectedItem = "" private var materialSelectedItem = "" @@ -46,17 +53,33 @@ private var buryMethodSelectedItem = "" private var identifierTypeSelectedItem = "" private var colorSelectedItem = "" + private lateinit var taskViewModel: TaskViewModel override fun initData() { imageAdapter = EditableImageAdapter(this, 3, 3f) addImageRecyclerView.adapter = imageAdapter + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + //设置默认值 + markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue()) + pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue()) + buryDeepView.setText("buryDeepView".getDefaultValue()) + downPipeDiameterView.setText("downPipeDiameterView".getDefaultValue()) + downPointDeepView.setText("downPointDeepView".getDefaultValue()) + areaView.setText("areaView".getDefaultValue()) + lineView.setText("lineView".getDefaultValue()) + roadView.setText("roadView".getDefaultValue()) + ownerView.setText("ownerView".getDefaultValue()) + identifierDeepView.setText("identifierDeepView".getDefaultValue()) + personDeptView.setText("personDeptView".getDefaultValue()) } override fun initEvent() { leftBackView.setOnClickListener { finish() } /**************************************************************************************/ - objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 1, + objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { objectTypeSelectedItem = default @@ -67,7 +90,7 @@ } }) - materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { materialSelectedItem = default @@ -78,7 +101,7 @@ } }) - downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 1, + downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeSelectedItem = default @@ -89,7 +112,7 @@ } }) - downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeMaterialSelectedItem = default @@ -100,7 +123,7 @@ } }) - buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 1, + buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { buryMethodSelectedItem = default @@ -112,11 +135,15 @@ }) constructDateView.setOnClickListener { - showDatePicker(DateEntity.today(), object : DateSelectedCallback { - override fun onDateSelected(date: String) { - constructDateView.text = date - } - }) + val year = calendar.get(Calendar.YEAR) + val month = calendar.get(Calendar.MONTH) + val day = calendar.get(Calendar.DAY_OF_MONTH) + val datePicker = DatePickerDialog(this, { _, y, m, d -> + constructDateView.text = String.format( + "%s-%s-%s", y, m.appendZero(), d.appendZero() + ) + }, year, month, day) + datePicker.show() } identifierTypeSpinner.show(this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0, @@ -161,16 +188,153 @@ if (realPaths[position].isEmpty()) { "图片加载失败,无法查看大图".show(context) } else { -// context.navigatePageTo(position, realPaths) + context.navigatePageTo(position, realPaths) } } override fun onItemLongClick(view: View?, position: Int) { - imagePaths.removeAt(position) imageAdapter.deleteImage(position) } }) /**************************************************************************************/ + installButton.setOnClickListener { + if (isNetworkConnected()) { + val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + if (markerObjectTypeView.text.isNullOrBlank()) { + when (objectTypeSelectedItem) { + "管线" -> { + "请输入管线种类!".show(this) + } + "管线附属物" -> { + "请输入附属物名称!".show(this) + } + "管线特征管点" -> { + "请输入特征管点!".show(this) + } + "交叉穿越点" -> { + "请输入上层管种类!".show(this) + } + } + return@setOnClickListener + } + + if (pipelineDiameterView.text.isNullOrBlank()) { + "请输入管径".show(this) + return@setOnClickListener + } + + if (buryDeepView.text.isNullOrBlank()) { + "请输入埋深".show(this) + return@setOnClickListener + } + + if (downPipeDiameterView.text.isNullOrBlank()) { + "请输入下层管管径".show(this) + return@setOnClickListener + } + + if (areaView.text.isNullOrBlank()) { + "请输入所属区域".show(this) + return@setOnClickListener + } + + if (lineView.text.isNullOrBlank()) { + "请输入所属线路".show(this) + return@setOnClickListener + } + + if (roadView.text.isNullOrBlank()) { + "请输入所属道路".show(this) + return@setOnClickListener + } + + if (constructDateView.text.isNullOrBlank()) { + "请选择建设年代".show(this) + return@setOnClickListener + } + + if (ownerView.text.isNullOrBlank()) { + "请输入权属单位".show(this) + return@setOnClickListener + } + + if (identifierIdView.text.isNullOrBlank()) { + "请先读取标识器获取ID".show(this) + return@setOnClickListener + } + + if (identifierDeepView.text.isNullOrBlank()) { + "请输入标识器埋深".show(this) + return@setOnClickListener + } + + if (personDeptView.text.isNullOrBlank()) { + "请输入标识器安装部门".show(this) + return@setOnClickListener + } + + taskViewModel.installLabel( + companyId, + objectTypeSelectedItem.toObjectType(), + markerObjectTypeView.text.toString(), + materialSelectedItem, + "${pipelineDiameterView.text}mm", + "${buryDeepView.text}mm", + downPipeSelectedItem, + downPipeMaterialSelectedItem, + "${downPipeDiameterView.text}mm", + "${downPointDeepView.text}mm", + buryMethodSelectedItem, + areaView.text.toString(), + lineView.text.toString(), + roadView.text.toString(), + constructDateView.text.toString(), + ownerView.text.toString(), + objectId, + identifierIdView.text.toString(), + identifierTypeSelectedItem, + "${identifierDeepView.text}mm", + personDeptView.text.toString(), + installTimeView.text.toString(), + lngView.text.toString(), + latView.text.toString(), + colorSelectedItem.toColor(), + remarkView.text.toString(), + realPaths + ) + + //保存默认值 + "markerObjectTypeView".setDefaultValue(markerObjectTypeView.text.toString()) + "pipelineDiameterView".setDefaultValue(pipelineDiameterView.text.toString()) + "buryDeepView".setDefaultValue(buryDeepView.text.toString()) + "downPipeDiameterView".setDefaultValue(downPipeDiameterView.text.toString()) + "downPointDeepView".setDefaultValue(downPointDeepView.text.toString()) + "areaView".setDefaultValue(areaView.text.toString()) + "lineView".setDefaultValue(lineView.text.toString()) + "roadView".setDefaultValue(roadView.text.toString()) + "ownerView".setDefaultValue(ownerView.text.toString()) + "identifierDeepView".setDefaultValue(identifierDeepView.text.toString()) + "personDeptView".setDefaultValue(personDeptView.text.toString()) + } else { + NoNetworkDialog.Builder() + .setContext(context) + .setOnDialogButtonClickListener(object : + NoNetworkDialog.OnDialogButtonClickListener { + override fun onButtonClick() { + val intent = Intent(Settings.ACTION_SETTINGS) + startActivity(intent) + } + }).build().show() + } + } + + //TODO 搜索标识器 + readLabelButton.setOnClickListener { + LoadingDialogHub.show(this, "正在搜索标识器,请稍后...") + identifierIdView.text = "123456789" + LoadingDialogHub.dismiss() + } } private fun takePicture() { @@ -191,11 +355,11 @@ } private fun analyticalSelectResults(result: LocalMedia) { - //压缩图片后上传 + //压缩图片 result.realPath.compressImage(this, object : OnImageCompressListener { override fun onSuccess(file: File) { - //上传图片 -// fileUploadViewModel.uploadFile(file) + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) } override fun onError(e: Throwable) { @@ -207,7 +371,51 @@ override fun initLayoutView(): Int = R.layout.activity_install_label override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...") + LoadState.Success -> { + saveLabelInLocal() + LoadingDialogHub.dismiss() + finish() + } + else -> LoadingDialogHub.dismiss() + } + } + } + //安装成功后将标识器保存在本地 + private fun saveLabelInLocal() { + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + + val labelBean = LabelBean() + labelBean.objectType = objectTypeSelectedItem + labelBean.pipelineType = markerObjectTypeView.text.toString() + labelBean.pipelineMaterial = materialSelectedItem + labelBean.pipelineDiameter = "${pipelineDiameterView.text}mm" + labelBean.buryDeep = "${buryDeepView.text}mm" + labelBean.lowerType = downPipeSelectedItem + labelBean.lowerMaterial = downPipeMaterialSelectedItem + labelBean.lowerDiameter = "${downPipeDiameterView.text}mm" + labelBean.lowerDeep = "${downPointDeepView.text}mm" + labelBean.buryMethod = buryMethodSelectedItem + labelBean.area = areaView.text.toString() + labelBean.line = lineView.text.toString() + labelBean.road = roadView.text.toString() + labelBean.constructTime = constructDateView.text.toString() + labelBean.owner = ownerView.text.toString() + labelBean.objectId = objectId + labelBean.identifierId = identifierIdView.text.toString() + labelBean.identifierType = identifierTypeSelectedItem + labelBean.identifierDeep = "${identifierDeepView.text}mm" + labelBean.person = personDeptView.text.toString() + labelBean.installTime = installTimeView.text.toString() + labelBean.lng = lngView.text.toString() + labelBean.lat = latView.text.toString() + labelBean.color = colorSelectedItem.toColor() + labelBean.remark = remarkView.text.toString() + + DataBaseManager.get.insertTaskLabel(labelBean) } override fun setupTopBarLayout() { diff --git a/app/src/main/java/com/casic/detector/view/MainActivity.kt b/app/src/main/java/com/casic/detector/view/MainActivity.kt index cd06e07..9b791e9 100644 --- a/app/src/main/java/com/casic/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/detector/view/MainActivity.kt @@ -571,7 +571,8 @@ labelBean.lng, labelBean.lat, labelBean.color, - labelBean.remark + labelBean.remark, + arrayListOf() ) } LoadingDialogHub.dismiss() diff --git a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt index 082ee39..82813ff 100644 --- a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt @@ -39,7 +39,7 @@ objectJson, object : TypeToken() {}.type ) - objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt()] + objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt() - 1] pipelineTypeView.text = labelBean.pipelineType pipelineDiameterView.text = labelBean.pipelineDiameter pipelineMaterialView.text = labelBean.pipelineMaterial diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Int.kt b/app/src/main/java/com/casic/detector/extensions/Int.kt index 10275bb..d67cac8 100644 --- a/app/src/main/java/com/casic/detector/extensions/Int.kt +++ b/app/src/main/java/com/casic/detector/extensions/Int.kt @@ -13,4 +13,12 @@ paint.color = color canvas.drawArc(rectF, 0f, 360f, true, paint) return bitmap +} + +fun Int.appendZero(): String { + return if (this < 10) { + "0$this" + } else { + this.toString() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index 7352dc1..aacd89d 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -45,6 +45,36 @@ } } +fun String.toObjectType(): String { + return if (this == LocaleConstant.POINT_TYPE_ARRAY[0]) { + "1" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[1]) { + "2" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[2]) { + "3" + } else { + "4" + } +} + +fun String.toColor(): String { + return if (this == LocaleConstant.COLOR_ARRAY[0]) { + "0" + } else if (this == LocaleConstant.COLOR_ARRAY[1]) { + "1" + } else if (this == LocaleConstant.COLOR_ARRAY[2]) { + "2" + } else if (this == LocaleConstant.COLOR_ARRAY[3]) { + "3" + } else if (this == LocaleConstant.COLOR_ARRAY[4]) { + "4" + } else if (this == LocaleConstant.COLOR_ARRAY[5]) { + "5" + } else { + "6" + } +} + fun String.compressImage(context: Context, listener: OnImageCompressListener) { Luban.with(context) .load(this) @@ -63,4 +93,14 @@ listener.onError(e) } }).launch() +} + +//根据控件名字存默认值 +fun String.setDefaultValue(value: String) { + SaveKeyValues.putValue(this, value) +} + +//根据控件名字取默认值 +fun String.getDefaultValue(): String { + return SaveKeyValues.getValue(this, "") as String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 6ee3191..9e862aa 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -1,10 +1,8 @@ package com.casic.detector.retrofit +import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query +import retrofit2.http.* interface RetrofitService { /** @@ -56,6 +54,12 @@ /** * 安装新标识器 */ + @Multipart @POST("/ems/marker/save-marker-photo.do") - suspend fun installLabel(@Body requestBody: RequestBody): String + suspend fun installLabel( + @PartMap jsonMarker: Map, + @Part fileBuffer1: MultipartBody.Part?, + @Part fileBuffer2: MultipartBody.Part?, + @Part fileBuffer3: MultipartBody.Part? + ): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 1549f93..6e6f1ae 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -7,7 +7,11 @@ import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody +import java.io.File object RetrofitServiceManager { private val api by lazy { @@ -68,6 +72,7 @@ /** * 安装新标识器 + * Multipart上传图片,文件,带多参数上传 */ suspend fun installLabel( companyId: String, @@ -95,7 +100,8 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ): String { val param = JsonObject() param.addProperty("companyId", companyId) @@ -127,6 +133,31 @@ val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return api.installLabel(requestBody) + val res = HashMap() + res["jsonMarker"] = requestBody + + val multiParts = ArrayList() + realPaths.forEachIndexed { index, s -> + val file = File(s) + val fileMultipart = MultipartBody.Part.createFormData( + "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) + ) + multiParts.add(fileMultipart) + } + + return when (multiParts.size) { + 3 -> { + api.installLabel(res, multiParts[0], multiParts[1], multiParts[2]) + } + 2 -> { + api.installLabel(res, multiParts[0], multiParts[1], null) + } + 1 -> { + api.installLabel(res, multiParts[0], null, null) + } + else -> { + api.installLabel(res, null, null, null) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt index 5bb7fbe..e34bbb8 100644 --- a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt @@ -22,16 +22,17 @@ const val USER_NAME = "USER_NAME" const val USER_ID = "USER_ID" const val USER_COMPANY_ID = "USER_COMPANY_ID" + const val OBJECT_ID = "OBJECT_ID" const val SERVER_IP = "SERVER_IP" const val SERVER_PORT = "SERVER_PORT" const val APP_AUTHORITY = "com.casic.detector.fileprovider" val POPUP_TITLES = arrayOf("更新数据", "下载工单", "关于软件", "事件上报", "标识器补全") - var POINT_TYPE_ARRAY = arrayOf("", "管线", "管线附属物", "管线特征管点", "交叉穿越点") + var POINT_TYPE_ARRAY = arrayOf("管线", "管线附属物", "管线特征管点", "交叉穿越点") var SPINNER_ARRAY = arrayOf("标识器ID", "所属区域", "所属线路", "所属道路", "权属单位", "安装部门", "安装时间", "备注") - var PIPE_MATERIAL_ARRAY = arrayOf("", "铸铁", "塑料") - var DOWN_PIPE_TYPE_ARRAY = arrayOf("", "热力", "燃气", "供水", "电力", "通信") - var BURY_METHOD_ARRAY = arrayOf("", "直埋", "圆管", "管块", "管沟", "架空") + var PIPE_MATERIAL_ARRAY = arrayOf("铸铁", "塑料") + var DOWN_PIPE_TYPE_ARRAY = arrayOf("热力", "燃气", "供水", "电力", "通信") + var BURY_METHOD_ARRAY = arrayOf("直埋", "圆管", "管块", "管沟", "架空") var IDENTIFIER_TYPE_ARRAY = arrayOf("EM30", "EM50", "EM14") var COLOR_ARRAY = arrayOf("蓝色", "橙色", "红色", "黑色", "紫色", "黄色", "绿色") } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/BigImageActivity.kt b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt new file mode 100644 index 0000000..ca6c7d7 --- /dev/null +++ b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt @@ -0,0 +1,87 @@ +package com.casic.detector.view + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant +import com.pengxh.kt.lite.utils.ImmerseStatusBarUtil +import kotlinx.android.synthetic.main.activity_big_image.* + +class BigImageActivity : KotlinBaseActivity() { + + override fun initLayoutView(): Int = R.layout.activity_big_image + + override fun setupTopBarLayout() { + ImmerseStatusBarUtil.setColor(this, Color.BLACK) + leftBackView.setOnClickListener { finish() } + } + + override fun initData() { + + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + val index: Int = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + imagePagerView.adapter = BigImageAdapter(this, urls) + imagePagerView.currentItem = index + imagePagerView.offscreenPageLimit = imageSize + imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + pageNumberView.text = String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt index d61bec9..02b455f 100644 --- a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt @@ -1,43 +1,50 @@ package com.casic.detector.view +import android.annotation.SuppressLint +import android.app.DatePickerDialog import android.content.Context +import android.content.Intent +import android.provider.Settings import android.view.View +import androidx.lifecycle.ViewModelProvider import com.amap.api.location.AMapLocation import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback +import com.casic.detector.adapter.EditableImageAdapter +import com.casic.detector.bean.LabelBean import com.casic.detector.callback.ILocationListener import com.casic.detector.callback.OnImageCompressListener import com.casic.detector.callback.OnItemSelectedListener -import com.casic.detector.extensions.compressImage -import com.casic.detector.extensions.initLayoutImmersionBar -import com.casic.detector.extensions.show -import com.casic.detector.extensions.showDatePicker +import com.casic.detector.extensions.* +import com.casic.detector.utils.DataBaseManager +import com.casic.detector.utils.LoadingDialogHub import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity +import com.casic.detector.vm.TaskViewModel import com.gyf.immersionbar.ImmersionBar import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType import com.luck.picture.lib.entity.LocalMedia import com.luck.picture.lib.interfaces.OnResultCallbackListener -import com.pengxh.kt.lite.adapter.EditableImageAdapter import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.extensions.timestampToCompleteDate +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.vm.LoadState +import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog import kotlinx.android.synthetic.main.activity_install_label.* import kotlinx.android.synthetic.main.include_base_title.* import kotlinx.android.synthetic.main.include_install_label_identifier.* import kotlinx.android.synthetic.main.include_install_label_object.* import kotlinx.android.synthetic.main.include_install_label_open_camera.* import java.io.File +import java.util.* +@SuppressLint("SetTextI18n") class InstallLabelActivity : KotlinBaseActivity() { private val kTag = "InstallLabelActivity" private val context: Context = this@InstallLabelActivity + private val calendar by lazy { Calendar.getInstance() } private lateinit var imageAdapter: EditableImageAdapter - private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 private val realPaths: ArrayList = ArrayList() //真实图片路径 private var objectTypeSelectedItem = "" private var materialSelectedItem = "" @@ -46,17 +53,33 @@ private var buryMethodSelectedItem = "" private var identifierTypeSelectedItem = "" private var colorSelectedItem = "" + private lateinit var taskViewModel: TaskViewModel override fun initData() { imageAdapter = EditableImageAdapter(this, 3, 3f) addImageRecyclerView.adapter = imageAdapter + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + //设置默认值 + markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue()) + pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue()) + buryDeepView.setText("buryDeepView".getDefaultValue()) + downPipeDiameterView.setText("downPipeDiameterView".getDefaultValue()) + downPointDeepView.setText("downPointDeepView".getDefaultValue()) + areaView.setText("areaView".getDefaultValue()) + lineView.setText("lineView".getDefaultValue()) + roadView.setText("roadView".getDefaultValue()) + ownerView.setText("ownerView".getDefaultValue()) + identifierDeepView.setText("identifierDeepView".getDefaultValue()) + personDeptView.setText("personDeptView".getDefaultValue()) } override fun initEvent() { leftBackView.setOnClickListener { finish() } /**************************************************************************************/ - objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 1, + objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { objectTypeSelectedItem = default @@ -67,7 +90,7 @@ } }) - materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { materialSelectedItem = default @@ -78,7 +101,7 @@ } }) - downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 1, + downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeSelectedItem = default @@ -89,7 +112,7 @@ } }) - downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeMaterialSelectedItem = default @@ -100,7 +123,7 @@ } }) - buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 1, + buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { buryMethodSelectedItem = default @@ -112,11 +135,15 @@ }) constructDateView.setOnClickListener { - showDatePicker(DateEntity.today(), object : DateSelectedCallback { - override fun onDateSelected(date: String) { - constructDateView.text = date - } - }) + val year = calendar.get(Calendar.YEAR) + val month = calendar.get(Calendar.MONTH) + val day = calendar.get(Calendar.DAY_OF_MONTH) + val datePicker = DatePickerDialog(this, { _, y, m, d -> + constructDateView.text = String.format( + "%s-%s-%s", y, m.appendZero(), d.appendZero() + ) + }, year, month, day) + datePicker.show() } identifierTypeSpinner.show(this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0, @@ -161,16 +188,153 @@ if (realPaths[position].isEmpty()) { "图片加载失败,无法查看大图".show(context) } else { -// context.navigatePageTo(position, realPaths) + context.navigatePageTo(position, realPaths) } } override fun onItemLongClick(view: View?, position: Int) { - imagePaths.removeAt(position) imageAdapter.deleteImage(position) } }) /**************************************************************************************/ + installButton.setOnClickListener { + if (isNetworkConnected()) { + val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + if (markerObjectTypeView.text.isNullOrBlank()) { + when (objectTypeSelectedItem) { + "管线" -> { + "请输入管线种类!".show(this) + } + "管线附属物" -> { + "请输入附属物名称!".show(this) + } + "管线特征管点" -> { + "请输入特征管点!".show(this) + } + "交叉穿越点" -> { + "请输入上层管种类!".show(this) + } + } + return@setOnClickListener + } + + if (pipelineDiameterView.text.isNullOrBlank()) { + "请输入管径".show(this) + return@setOnClickListener + } + + if (buryDeepView.text.isNullOrBlank()) { + "请输入埋深".show(this) + return@setOnClickListener + } + + if (downPipeDiameterView.text.isNullOrBlank()) { + "请输入下层管管径".show(this) + return@setOnClickListener + } + + if (areaView.text.isNullOrBlank()) { + "请输入所属区域".show(this) + return@setOnClickListener + } + + if (lineView.text.isNullOrBlank()) { + "请输入所属线路".show(this) + return@setOnClickListener + } + + if (roadView.text.isNullOrBlank()) { + "请输入所属道路".show(this) + return@setOnClickListener + } + + if (constructDateView.text.isNullOrBlank()) { + "请选择建设年代".show(this) + return@setOnClickListener + } + + if (ownerView.text.isNullOrBlank()) { + "请输入权属单位".show(this) + return@setOnClickListener + } + + if (identifierIdView.text.isNullOrBlank()) { + "请先读取标识器获取ID".show(this) + return@setOnClickListener + } + + if (identifierDeepView.text.isNullOrBlank()) { + "请输入标识器埋深".show(this) + return@setOnClickListener + } + + if (personDeptView.text.isNullOrBlank()) { + "请输入标识器安装部门".show(this) + return@setOnClickListener + } + + taskViewModel.installLabel( + companyId, + objectTypeSelectedItem.toObjectType(), + markerObjectTypeView.text.toString(), + materialSelectedItem, + "${pipelineDiameterView.text}mm", + "${buryDeepView.text}mm", + downPipeSelectedItem, + downPipeMaterialSelectedItem, + "${downPipeDiameterView.text}mm", + "${downPointDeepView.text}mm", + buryMethodSelectedItem, + areaView.text.toString(), + lineView.text.toString(), + roadView.text.toString(), + constructDateView.text.toString(), + ownerView.text.toString(), + objectId, + identifierIdView.text.toString(), + identifierTypeSelectedItem, + "${identifierDeepView.text}mm", + personDeptView.text.toString(), + installTimeView.text.toString(), + lngView.text.toString(), + latView.text.toString(), + colorSelectedItem.toColor(), + remarkView.text.toString(), + realPaths + ) + + //保存默认值 + "markerObjectTypeView".setDefaultValue(markerObjectTypeView.text.toString()) + "pipelineDiameterView".setDefaultValue(pipelineDiameterView.text.toString()) + "buryDeepView".setDefaultValue(buryDeepView.text.toString()) + "downPipeDiameterView".setDefaultValue(downPipeDiameterView.text.toString()) + "downPointDeepView".setDefaultValue(downPointDeepView.text.toString()) + "areaView".setDefaultValue(areaView.text.toString()) + "lineView".setDefaultValue(lineView.text.toString()) + "roadView".setDefaultValue(roadView.text.toString()) + "ownerView".setDefaultValue(ownerView.text.toString()) + "identifierDeepView".setDefaultValue(identifierDeepView.text.toString()) + "personDeptView".setDefaultValue(personDeptView.text.toString()) + } else { + NoNetworkDialog.Builder() + .setContext(context) + .setOnDialogButtonClickListener(object : + NoNetworkDialog.OnDialogButtonClickListener { + override fun onButtonClick() { + val intent = Intent(Settings.ACTION_SETTINGS) + startActivity(intent) + } + }).build().show() + } + } + + //TODO 搜索标识器 + readLabelButton.setOnClickListener { + LoadingDialogHub.show(this, "正在搜索标识器,请稍后...") + identifierIdView.text = "123456789" + LoadingDialogHub.dismiss() + } } private fun takePicture() { @@ -191,11 +355,11 @@ } private fun analyticalSelectResults(result: LocalMedia) { - //压缩图片后上传 + //压缩图片 result.realPath.compressImage(this, object : OnImageCompressListener { override fun onSuccess(file: File) { - //上传图片 -// fileUploadViewModel.uploadFile(file) + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) } override fun onError(e: Throwable) { @@ -207,7 +371,51 @@ override fun initLayoutView(): Int = R.layout.activity_install_label override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...") + LoadState.Success -> { + saveLabelInLocal() + LoadingDialogHub.dismiss() + finish() + } + else -> LoadingDialogHub.dismiss() + } + } + } + //安装成功后将标识器保存在本地 + private fun saveLabelInLocal() { + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + + val labelBean = LabelBean() + labelBean.objectType = objectTypeSelectedItem + labelBean.pipelineType = markerObjectTypeView.text.toString() + labelBean.pipelineMaterial = materialSelectedItem + labelBean.pipelineDiameter = "${pipelineDiameterView.text}mm" + labelBean.buryDeep = "${buryDeepView.text}mm" + labelBean.lowerType = downPipeSelectedItem + labelBean.lowerMaterial = downPipeMaterialSelectedItem + labelBean.lowerDiameter = "${downPipeDiameterView.text}mm" + labelBean.lowerDeep = "${downPointDeepView.text}mm" + labelBean.buryMethod = buryMethodSelectedItem + labelBean.area = areaView.text.toString() + labelBean.line = lineView.text.toString() + labelBean.road = roadView.text.toString() + labelBean.constructTime = constructDateView.text.toString() + labelBean.owner = ownerView.text.toString() + labelBean.objectId = objectId + labelBean.identifierId = identifierIdView.text.toString() + labelBean.identifierType = identifierTypeSelectedItem + labelBean.identifierDeep = "${identifierDeepView.text}mm" + labelBean.person = personDeptView.text.toString() + labelBean.installTime = installTimeView.text.toString() + labelBean.lng = lngView.text.toString() + labelBean.lat = latView.text.toString() + labelBean.color = colorSelectedItem.toColor() + labelBean.remark = remarkView.text.toString() + + DataBaseManager.get.insertTaskLabel(labelBean) } override fun setupTopBarLayout() { diff --git a/app/src/main/java/com/casic/detector/view/MainActivity.kt b/app/src/main/java/com/casic/detector/view/MainActivity.kt index cd06e07..9b791e9 100644 --- a/app/src/main/java/com/casic/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/detector/view/MainActivity.kt @@ -571,7 +571,8 @@ labelBean.lng, labelBean.lat, labelBean.color, - labelBean.remark + labelBean.remark, + arrayListOf() ) } LoadingDialogHub.dismiss() diff --git a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt index 082ee39..82813ff 100644 --- a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt @@ -39,7 +39,7 @@ objectJson, object : TypeToken() {}.type ) - objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt()] + objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt() - 1] pipelineTypeView.text = labelBean.pipelineType pipelineDiameterView.text = labelBean.pipelineDiameter pipelineMaterialView.text = labelBean.pipelineMaterial diff --git a/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt index 845b2b8..2475f0d 100644 --- a/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt @@ -89,8 +89,10 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ) = launch({ + loadState.value = LoadState.Loading val response = RetrofitServiceManager.installLabel( companyId, recordType, @@ -117,16 +119,17 @@ longitude, latitude, colorType, - memo + memo, + realPaths ) if (response.separateResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + loadState.value = LoadState.Success } else { + loadState.value = LoadState.Fail response.toErrorMessage().show(BaseApplication.get()) } }, { + loadState.value = LoadState.Fail it.convertChinese().show(BaseApplication.get()) }) diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Int.kt b/app/src/main/java/com/casic/detector/extensions/Int.kt index 10275bb..d67cac8 100644 --- a/app/src/main/java/com/casic/detector/extensions/Int.kt +++ b/app/src/main/java/com/casic/detector/extensions/Int.kt @@ -13,4 +13,12 @@ paint.color = color canvas.drawArc(rectF, 0f, 360f, true, paint) return bitmap +} + +fun Int.appendZero(): String { + return if (this < 10) { + "0$this" + } else { + this.toString() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index 7352dc1..aacd89d 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -45,6 +45,36 @@ } } +fun String.toObjectType(): String { + return if (this == LocaleConstant.POINT_TYPE_ARRAY[0]) { + "1" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[1]) { + "2" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[2]) { + "3" + } else { + "4" + } +} + +fun String.toColor(): String { + return if (this == LocaleConstant.COLOR_ARRAY[0]) { + "0" + } else if (this == LocaleConstant.COLOR_ARRAY[1]) { + "1" + } else if (this == LocaleConstant.COLOR_ARRAY[2]) { + "2" + } else if (this == LocaleConstant.COLOR_ARRAY[3]) { + "3" + } else if (this == LocaleConstant.COLOR_ARRAY[4]) { + "4" + } else if (this == LocaleConstant.COLOR_ARRAY[5]) { + "5" + } else { + "6" + } +} + fun String.compressImage(context: Context, listener: OnImageCompressListener) { Luban.with(context) .load(this) @@ -63,4 +93,14 @@ listener.onError(e) } }).launch() +} + +//根据控件名字存默认值 +fun String.setDefaultValue(value: String) { + SaveKeyValues.putValue(this, value) +} + +//根据控件名字取默认值 +fun String.getDefaultValue(): String { + return SaveKeyValues.getValue(this, "") as String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 6ee3191..9e862aa 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -1,10 +1,8 @@ package com.casic.detector.retrofit +import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query +import retrofit2.http.* interface RetrofitService { /** @@ -56,6 +54,12 @@ /** * 安装新标识器 */ + @Multipart @POST("/ems/marker/save-marker-photo.do") - suspend fun installLabel(@Body requestBody: RequestBody): String + suspend fun installLabel( + @PartMap jsonMarker: Map, + @Part fileBuffer1: MultipartBody.Part?, + @Part fileBuffer2: MultipartBody.Part?, + @Part fileBuffer3: MultipartBody.Part? + ): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 1549f93..6e6f1ae 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -7,7 +7,11 @@ import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody +import java.io.File object RetrofitServiceManager { private val api by lazy { @@ -68,6 +72,7 @@ /** * 安装新标识器 + * Multipart上传图片,文件,带多参数上传 */ suspend fun installLabel( companyId: String, @@ -95,7 +100,8 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ): String { val param = JsonObject() param.addProperty("companyId", companyId) @@ -127,6 +133,31 @@ val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return api.installLabel(requestBody) + val res = HashMap() + res["jsonMarker"] = requestBody + + val multiParts = ArrayList() + realPaths.forEachIndexed { index, s -> + val file = File(s) + val fileMultipart = MultipartBody.Part.createFormData( + "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) + ) + multiParts.add(fileMultipart) + } + + return when (multiParts.size) { + 3 -> { + api.installLabel(res, multiParts[0], multiParts[1], multiParts[2]) + } + 2 -> { + api.installLabel(res, multiParts[0], multiParts[1], null) + } + 1 -> { + api.installLabel(res, multiParts[0], null, null) + } + else -> { + api.installLabel(res, null, null, null) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt index 5bb7fbe..e34bbb8 100644 --- a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt @@ -22,16 +22,17 @@ const val USER_NAME = "USER_NAME" const val USER_ID = "USER_ID" const val USER_COMPANY_ID = "USER_COMPANY_ID" + const val OBJECT_ID = "OBJECT_ID" const val SERVER_IP = "SERVER_IP" const val SERVER_PORT = "SERVER_PORT" const val APP_AUTHORITY = "com.casic.detector.fileprovider" val POPUP_TITLES = arrayOf("更新数据", "下载工单", "关于软件", "事件上报", "标识器补全") - var POINT_TYPE_ARRAY = arrayOf("", "管线", "管线附属物", "管线特征管点", "交叉穿越点") + var POINT_TYPE_ARRAY = arrayOf("管线", "管线附属物", "管线特征管点", "交叉穿越点") var SPINNER_ARRAY = arrayOf("标识器ID", "所属区域", "所属线路", "所属道路", "权属单位", "安装部门", "安装时间", "备注") - var PIPE_MATERIAL_ARRAY = arrayOf("", "铸铁", "塑料") - var DOWN_PIPE_TYPE_ARRAY = arrayOf("", "热力", "燃气", "供水", "电力", "通信") - var BURY_METHOD_ARRAY = arrayOf("", "直埋", "圆管", "管块", "管沟", "架空") + var PIPE_MATERIAL_ARRAY = arrayOf("铸铁", "塑料") + var DOWN_PIPE_TYPE_ARRAY = arrayOf("热力", "燃气", "供水", "电力", "通信") + var BURY_METHOD_ARRAY = arrayOf("直埋", "圆管", "管块", "管沟", "架空") var IDENTIFIER_TYPE_ARRAY = arrayOf("EM30", "EM50", "EM14") var COLOR_ARRAY = arrayOf("蓝色", "橙色", "红色", "黑色", "紫色", "黄色", "绿色") } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/BigImageActivity.kt b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt new file mode 100644 index 0000000..ca6c7d7 --- /dev/null +++ b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt @@ -0,0 +1,87 @@ +package com.casic.detector.view + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant +import com.pengxh.kt.lite.utils.ImmerseStatusBarUtil +import kotlinx.android.synthetic.main.activity_big_image.* + +class BigImageActivity : KotlinBaseActivity() { + + override fun initLayoutView(): Int = R.layout.activity_big_image + + override fun setupTopBarLayout() { + ImmerseStatusBarUtil.setColor(this, Color.BLACK) + leftBackView.setOnClickListener { finish() } + } + + override fun initData() { + + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + val index: Int = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + imagePagerView.adapter = BigImageAdapter(this, urls) + imagePagerView.currentItem = index + imagePagerView.offscreenPageLimit = imageSize + imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + pageNumberView.text = String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt index d61bec9..02b455f 100644 --- a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt @@ -1,43 +1,50 @@ package com.casic.detector.view +import android.annotation.SuppressLint +import android.app.DatePickerDialog import android.content.Context +import android.content.Intent +import android.provider.Settings import android.view.View +import androidx.lifecycle.ViewModelProvider import com.amap.api.location.AMapLocation import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback +import com.casic.detector.adapter.EditableImageAdapter +import com.casic.detector.bean.LabelBean import com.casic.detector.callback.ILocationListener import com.casic.detector.callback.OnImageCompressListener import com.casic.detector.callback.OnItemSelectedListener -import com.casic.detector.extensions.compressImage -import com.casic.detector.extensions.initLayoutImmersionBar -import com.casic.detector.extensions.show -import com.casic.detector.extensions.showDatePicker +import com.casic.detector.extensions.* +import com.casic.detector.utils.DataBaseManager +import com.casic.detector.utils.LoadingDialogHub import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity +import com.casic.detector.vm.TaskViewModel import com.gyf.immersionbar.ImmersionBar import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType import com.luck.picture.lib.entity.LocalMedia import com.luck.picture.lib.interfaces.OnResultCallbackListener -import com.pengxh.kt.lite.adapter.EditableImageAdapter import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.extensions.timestampToCompleteDate +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.vm.LoadState +import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog import kotlinx.android.synthetic.main.activity_install_label.* import kotlinx.android.synthetic.main.include_base_title.* import kotlinx.android.synthetic.main.include_install_label_identifier.* import kotlinx.android.synthetic.main.include_install_label_object.* import kotlinx.android.synthetic.main.include_install_label_open_camera.* import java.io.File +import java.util.* +@SuppressLint("SetTextI18n") class InstallLabelActivity : KotlinBaseActivity() { private val kTag = "InstallLabelActivity" private val context: Context = this@InstallLabelActivity + private val calendar by lazy { Calendar.getInstance() } private lateinit var imageAdapter: EditableImageAdapter - private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 private val realPaths: ArrayList = ArrayList() //真实图片路径 private var objectTypeSelectedItem = "" private var materialSelectedItem = "" @@ -46,17 +53,33 @@ private var buryMethodSelectedItem = "" private var identifierTypeSelectedItem = "" private var colorSelectedItem = "" + private lateinit var taskViewModel: TaskViewModel override fun initData() { imageAdapter = EditableImageAdapter(this, 3, 3f) addImageRecyclerView.adapter = imageAdapter + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + //设置默认值 + markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue()) + pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue()) + buryDeepView.setText("buryDeepView".getDefaultValue()) + downPipeDiameterView.setText("downPipeDiameterView".getDefaultValue()) + downPointDeepView.setText("downPointDeepView".getDefaultValue()) + areaView.setText("areaView".getDefaultValue()) + lineView.setText("lineView".getDefaultValue()) + roadView.setText("roadView".getDefaultValue()) + ownerView.setText("ownerView".getDefaultValue()) + identifierDeepView.setText("identifierDeepView".getDefaultValue()) + personDeptView.setText("personDeptView".getDefaultValue()) } override fun initEvent() { leftBackView.setOnClickListener { finish() } /**************************************************************************************/ - objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 1, + objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { objectTypeSelectedItem = default @@ -67,7 +90,7 @@ } }) - materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { materialSelectedItem = default @@ -78,7 +101,7 @@ } }) - downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 1, + downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeSelectedItem = default @@ -89,7 +112,7 @@ } }) - downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeMaterialSelectedItem = default @@ -100,7 +123,7 @@ } }) - buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 1, + buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { buryMethodSelectedItem = default @@ -112,11 +135,15 @@ }) constructDateView.setOnClickListener { - showDatePicker(DateEntity.today(), object : DateSelectedCallback { - override fun onDateSelected(date: String) { - constructDateView.text = date - } - }) + val year = calendar.get(Calendar.YEAR) + val month = calendar.get(Calendar.MONTH) + val day = calendar.get(Calendar.DAY_OF_MONTH) + val datePicker = DatePickerDialog(this, { _, y, m, d -> + constructDateView.text = String.format( + "%s-%s-%s", y, m.appendZero(), d.appendZero() + ) + }, year, month, day) + datePicker.show() } identifierTypeSpinner.show(this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0, @@ -161,16 +188,153 @@ if (realPaths[position].isEmpty()) { "图片加载失败,无法查看大图".show(context) } else { -// context.navigatePageTo(position, realPaths) + context.navigatePageTo(position, realPaths) } } override fun onItemLongClick(view: View?, position: Int) { - imagePaths.removeAt(position) imageAdapter.deleteImage(position) } }) /**************************************************************************************/ + installButton.setOnClickListener { + if (isNetworkConnected()) { + val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + if (markerObjectTypeView.text.isNullOrBlank()) { + when (objectTypeSelectedItem) { + "管线" -> { + "请输入管线种类!".show(this) + } + "管线附属物" -> { + "请输入附属物名称!".show(this) + } + "管线特征管点" -> { + "请输入特征管点!".show(this) + } + "交叉穿越点" -> { + "请输入上层管种类!".show(this) + } + } + return@setOnClickListener + } + + if (pipelineDiameterView.text.isNullOrBlank()) { + "请输入管径".show(this) + return@setOnClickListener + } + + if (buryDeepView.text.isNullOrBlank()) { + "请输入埋深".show(this) + return@setOnClickListener + } + + if (downPipeDiameterView.text.isNullOrBlank()) { + "请输入下层管管径".show(this) + return@setOnClickListener + } + + if (areaView.text.isNullOrBlank()) { + "请输入所属区域".show(this) + return@setOnClickListener + } + + if (lineView.text.isNullOrBlank()) { + "请输入所属线路".show(this) + return@setOnClickListener + } + + if (roadView.text.isNullOrBlank()) { + "请输入所属道路".show(this) + return@setOnClickListener + } + + if (constructDateView.text.isNullOrBlank()) { + "请选择建设年代".show(this) + return@setOnClickListener + } + + if (ownerView.text.isNullOrBlank()) { + "请输入权属单位".show(this) + return@setOnClickListener + } + + if (identifierIdView.text.isNullOrBlank()) { + "请先读取标识器获取ID".show(this) + return@setOnClickListener + } + + if (identifierDeepView.text.isNullOrBlank()) { + "请输入标识器埋深".show(this) + return@setOnClickListener + } + + if (personDeptView.text.isNullOrBlank()) { + "请输入标识器安装部门".show(this) + return@setOnClickListener + } + + taskViewModel.installLabel( + companyId, + objectTypeSelectedItem.toObjectType(), + markerObjectTypeView.text.toString(), + materialSelectedItem, + "${pipelineDiameterView.text}mm", + "${buryDeepView.text}mm", + downPipeSelectedItem, + downPipeMaterialSelectedItem, + "${downPipeDiameterView.text}mm", + "${downPointDeepView.text}mm", + buryMethodSelectedItem, + areaView.text.toString(), + lineView.text.toString(), + roadView.text.toString(), + constructDateView.text.toString(), + ownerView.text.toString(), + objectId, + identifierIdView.text.toString(), + identifierTypeSelectedItem, + "${identifierDeepView.text}mm", + personDeptView.text.toString(), + installTimeView.text.toString(), + lngView.text.toString(), + latView.text.toString(), + colorSelectedItem.toColor(), + remarkView.text.toString(), + realPaths + ) + + //保存默认值 + "markerObjectTypeView".setDefaultValue(markerObjectTypeView.text.toString()) + "pipelineDiameterView".setDefaultValue(pipelineDiameterView.text.toString()) + "buryDeepView".setDefaultValue(buryDeepView.text.toString()) + "downPipeDiameterView".setDefaultValue(downPipeDiameterView.text.toString()) + "downPointDeepView".setDefaultValue(downPointDeepView.text.toString()) + "areaView".setDefaultValue(areaView.text.toString()) + "lineView".setDefaultValue(lineView.text.toString()) + "roadView".setDefaultValue(roadView.text.toString()) + "ownerView".setDefaultValue(ownerView.text.toString()) + "identifierDeepView".setDefaultValue(identifierDeepView.text.toString()) + "personDeptView".setDefaultValue(personDeptView.text.toString()) + } else { + NoNetworkDialog.Builder() + .setContext(context) + .setOnDialogButtonClickListener(object : + NoNetworkDialog.OnDialogButtonClickListener { + override fun onButtonClick() { + val intent = Intent(Settings.ACTION_SETTINGS) + startActivity(intent) + } + }).build().show() + } + } + + //TODO 搜索标识器 + readLabelButton.setOnClickListener { + LoadingDialogHub.show(this, "正在搜索标识器,请稍后...") + identifierIdView.text = "123456789" + LoadingDialogHub.dismiss() + } } private fun takePicture() { @@ -191,11 +355,11 @@ } private fun analyticalSelectResults(result: LocalMedia) { - //压缩图片后上传 + //压缩图片 result.realPath.compressImage(this, object : OnImageCompressListener { override fun onSuccess(file: File) { - //上传图片 -// fileUploadViewModel.uploadFile(file) + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) } override fun onError(e: Throwable) { @@ -207,7 +371,51 @@ override fun initLayoutView(): Int = R.layout.activity_install_label override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...") + LoadState.Success -> { + saveLabelInLocal() + LoadingDialogHub.dismiss() + finish() + } + else -> LoadingDialogHub.dismiss() + } + } + } + //安装成功后将标识器保存在本地 + private fun saveLabelInLocal() { + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + + val labelBean = LabelBean() + labelBean.objectType = objectTypeSelectedItem + labelBean.pipelineType = markerObjectTypeView.text.toString() + labelBean.pipelineMaterial = materialSelectedItem + labelBean.pipelineDiameter = "${pipelineDiameterView.text}mm" + labelBean.buryDeep = "${buryDeepView.text}mm" + labelBean.lowerType = downPipeSelectedItem + labelBean.lowerMaterial = downPipeMaterialSelectedItem + labelBean.lowerDiameter = "${downPipeDiameterView.text}mm" + labelBean.lowerDeep = "${downPointDeepView.text}mm" + labelBean.buryMethod = buryMethodSelectedItem + labelBean.area = areaView.text.toString() + labelBean.line = lineView.text.toString() + labelBean.road = roadView.text.toString() + labelBean.constructTime = constructDateView.text.toString() + labelBean.owner = ownerView.text.toString() + labelBean.objectId = objectId + labelBean.identifierId = identifierIdView.text.toString() + labelBean.identifierType = identifierTypeSelectedItem + labelBean.identifierDeep = "${identifierDeepView.text}mm" + labelBean.person = personDeptView.text.toString() + labelBean.installTime = installTimeView.text.toString() + labelBean.lng = lngView.text.toString() + labelBean.lat = latView.text.toString() + labelBean.color = colorSelectedItem.toColor() + labelBean.remark = remarkView.text.toString() + + DataBaseManager.get.insertTaskLabel(labelBean) } override fun setupTopBarLayout() { diff --git a/app/src/main/java/com/casic/detector/view/MainActivity.kt b/app/src/main/java/com/casic/detector/view/MainActivity.kt index cd06e07..9b791e9 100644 --- a/app/src/main/java/com/casic/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/detector/view/MainActivity.kt @@ -571,7 +571,8 @@ labelBean.lng, labelBean.lat, labelBean.color, - labelBean.remark + labelBean.remark, + arrayListOf() ) } LoadingDialogHub.dismiss() diff --git a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt index 082ee39..82813ff 100644 --- a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt @@ -39,7 +39,7 @@ objectJson, object : TypeToken() {}.type ) - objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt()] + objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt() - 1] pipelineTypeView.text = labelBean.pipelineType pipelineDiameterView.text = labelBean.pipelineDiameter pipelineMaterialView.text = labelBean.pipelineMaterial diff --git a/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt index 845b2b8..2475f0d 100644 --- a/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt @@ -89,8 +89,10 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ) = launch({ + loadState.value = LoadState.Loading val response = RetrofitServiceManager.installLabel( companyId, recordType, @@ -117,16 +119,17 @@ longitude, latitude, colorType, - memo + memo, + realPaths ) if (response.separateResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + loadState.value = LoadState.Success } else { + loadState.value = LoadState.Fail response.toErrorMessage().show(BaseApplication.get()) } }, { + loadState.value = LoadState.Fail it.convertChinese().show(BaseApplication.get()) }) diff --git a/app/src/main/res/layout/activity_big_image.xml b/app/src/main/res/layout/activity_big_image.xml new file mode 100644 index 0000000..9d060f4 --- /dev/null +++ b/app/src/main/res/layout/activity_big_image.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Int.kt b/app/src/main/java/com/casic/detector/extensions/Int.kt index 10275bb..d67cac8 100644 --- a/app/src/main/java/com/casic/detector/extensions/Int.kt +++ b/app/src/main/java/com/casic/detector/extensions/Int.kt @@ -13,4 +13,12 @@ paint.color = color canvas.drawArc(rectF, 0f, 360f, true, paint) return bitmap +} + +fun Int.appendZero(): String { + return if (this < 10) { + "0$this" + } else { + this.toString() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index 7352dc1..aacd89d 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -45,6 +45,36 @@ } } +fun String.toObjectType(): String { + return if (this == LocaleConstant.POINT_TYPE_ARRAY[0]) { + "1" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[1]) { + "2" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[2]) { + "3" + } else { + "4" + } +} + +fun String.toColor(): String { + return if (this == LocaleConstant.COLOR_ARRAY[0]) { + "0" + } else if (this == LocaleConstant.COLOR_ARRAY[1]) { + "1" + } else if (this == LocaleConstant.COLOR_ARRAY[2]) { + "2" + } else if (this == LocaleConstant.COLOR_ARRAY[3]) { + "3" + } else if (this == LocaleConstant.COLOR_ARRAY[4]) { + "4" + } else if (this == LocaleConstant.COLOR_ARRAY[5]) { + "5" + } else { + "6" + } +} + fun String.compressImage(context: Context, listener: OnImageCompressListener) { Luban.with(context) .load(this) @@ -63,4 +93,14 @@ listener.onError(e) } }).launch() +} + +//根据控件名字存默认值 +fun String.setDefaultValue(value: String) { + SaveKeyValues.putValue(this, value) +} + +//根据控件名字取默认值 +fun String.getDefaultValue(): String { + return SaveKeyValues.getValue(this, "") as String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 6ee3191..9e862aa 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -1,10 +1,8 @@ package com.casic.detector.retrofit +import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query +import retrofit2.http.* interface RetrofitService { /** @@ -56,6 +54,12 @@ /** * 安装新标识器 */ + @Multipart @POST("/ems/marker/save-marker-photo.do") - suspend fun installLabel(@Body requestBody: RequestBody): String + suspend fun installLabel( + @PartMap jsonMarker: Map, + @Part fileBuffer1: MultipartBody.Part?, + @Part fileBuffer2: MultipartBody.Part?, + @Part fileBuffer3: MultipartBody.Part? + ): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 1549f93..6e6f1ae 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -7,7 +7,11 @@ import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody +import java.io.File object RetrofitServiceManager { private val api by lazy { @@ -68,6 +72,7 @@ /** * 安装新标识器 + * Multipart上传图片,文件,带多参数上传 */ suspend fun installLabel( companyId: String, @@ -95,7 +100,8 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ): String { val param = JsonObject() param.addProperty("companyId", companyId) @@ -127,6 +133,31 @@ val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return api.installLabel(requestBody) + val res = HashMap() + res["jsonMarker"] = requestBody + + val multiParts = ArrayList() + realPaths.forEachIndexed { index, s -> + val file = File(s) + val fileMultipart = MultipartBody.Part.createFormData( + "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) + ) + multiParts.add(fileMultipart) + } + + return when (multiParts.size) { + 3 -> { + api.installLabel(res, multiParts[0], multiParts[1], multiParts[2]) + } + 2 -> { + api.installLabel(res, multiParts[0], multiParts[1], null) + } + 1 -> { + api.installLabel(res, multiParts[0], null, null) + } + else -> { + api.installLabel(res, null, null, null) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt index 5bb7fbe..e34bbb8 100644 --- a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt @@ -22,16 +22,17 @@ const val USER_NAME = "USER_NAME" const val USER_ID = "USER_ID" const val USER_COMPANY_ID = "USER_COMPANY_ID" + const val OBJECT_ID = "OBJECT_ID" const val SERVER_IP = "SERVER_IP" const val SERVER_PORT = "SERVER_PORT" const val APP_AUTHORITY = "com.casic.detector.fileprovider" val POPUP_TITLES = arrayOf("更新数据", "下载工单", "关于软件", "事件上报", "标识器补全") - var POINT_TYPE_ARRAY = arrayOf("", "管线", "管线附属物", "管线特征管点", "交叉穿越点") + var POINT_TYPE_ARRAY = arrayOf("管线", "管线附属物", "管线特征管点", "交叉穿越点") var SPINNER_ARRAY = arrayOf("标识器ID", "所属区域", "所属线路", "所属道路", "权属单位", "安装部门", "安装时间", "备注") - var PIPE_MATERIAL_ARRAY = arrayOf("", "铸铁", "塑料") - var DOWN_PIPE_TYPE_ARRAY = arrayOf("", "热力", "燃气", "供水", "电力", "通信") - var BURY_METHOD_ARRAY = arrayOf("", "直埋", "圆管", "管块", "管沟", "架空") + var PIPE_MATERIAL_ARRAY = arrayOf("铸铁", "塑料") + var DOWN_PIPE_TYPE_ARRAY = arrayOf("热力", "燃气", "供水", "电力", "通信") + var BURY_METHOD_ARRAY = arrayOf("直埋", "圆管", "管块", "管沟", "架空") var IDENTIFIER_TYPE_ARRAY = arrayOf("EM30", "EM50", "EM14") var COLOR_ARRAY = arrayOf("蓝色", "橙色", "红色", "黑色", "紫色", "黄色", "绿色") } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/BigImageActivity.kt b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt new file mode 100644 index 0000000..ca6c7d7 --- /dev/null +++ b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt @@ -0,0 +1,87 @@ +package com.casic.detector.view + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant +import com.pengxh.kt.lite.utils.ImmerseStatusBarUtil +import kotlinx.android.synthetic.main.activity_big_image.* + +class BigImageActivity : KotlinBaseActivity() { + + override fun initLayoutView(): Int = R.layout.activity_big_image + + override fun setupTopBarLayout() { + ImmerseStatusBarUtil.setColor(this, Color.BLACK) + leftBackView.setOnClickListener { finish() } + } + + override fun initData() { + + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + val index: Int = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + imagePagerView.adapter = BigImageAdapter(this, urls) + imagePagerView.currentItem = index + imagePagerView.offscreenPageLimit = imageSize + imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + pageNumberView.text = String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt index d61bec9..02b455f 100644 --- a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt @@ -1,43 +1,50 @@ package com.casic.detector.view +import android.annotation.SuppressLint +import android.app.DatePickerDialog import android.content.Context +import android.content.Intent +import android.provider.Settings import android.view.View +import androidx.lifecycle.ViewModelProvider import com.amap.api.location.AMapLocation import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback +import com.casic.detector.adapter.EditableImageAdapter +import com.casic.detector.bean.LabelBean import com.casic.detector.callback.ILocationListener import com.casic.detector.callback.OnImageCompressListener import com.casic.detector.callback.OnItemSelectedListener -import com.casic.detector.extensions.compressImage -import com.casic.detector.extensions.initLayoutImmersionBar -import com.casic.detector.extensions.show -import com.casic.detector.extensions.showDatePicker +import com.casic.detector.extensions.* +import com.casic.detector.utils.DataBaseManager +import com.casic.detector.utils.LoadingDialogHub import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity +import com.casic.detector.vm.TaskViewModel import com.gyf.immersionbar.ImmersionBar import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType import com.luck.picture.lib.entity.LocalMedia import com.luck.picture.lib.interfaces.OnResultCallbackListener -import com.pengxh.kt.lite.adapter.EditableImageAdapter import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.extensions.timestampToCompleteDate +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.vm.LoadState +import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog import kotlinx.android.synthetic.main.activity_install_label.* import kotlinx.android.synthetic.main.include_base_title.* import kotlinx.android.synthetic.main.include_install_label_identifier.* import kotlinx.android.synthetic.main.include_install_label_object.* import kotlinx.android.synthetic.main.include_install_label_open_camera.* import java.io.File +import java.util.* +@SuppressLint("SetTextI18n") class InstallLabelActivity : KotlinBaseActivity() { private val kTag = "InstallLabelActivity" private val context: Context = this@InstallLabelActivity + private val calendar by lazy { Calendar.getInstance() } private lateinit var imageAdapter: EditableImageAdapter - private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 private val realPaths: ArrayList = ArrayList() //真实图片路径 private var objectTypeSelectedItem = "" private var materialSelectedItem = "" @@ -46,17 +53,33 @@ private var buryMethodSelectedItem = "" private var identifierTypeSelectedItem = "" private var colorSelectedItem = "" + private lateinit var taskViewModel: TaskViewModel override fun initData() { imageAdapter = EditableImageAdapter(this, 3, 3f) addImageRecyclerView.adapter = imageAdapter + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + //设置默认值 + markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue()) + pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue()) + buryDeepView.setText("buryDeepView".getDefaultValue()) + downPipeDiameterView.setText("downPipeDiameterView".getDefaultValue()) + downPointDeepView.setText("downPointDeepView".getDefaultValue()) + areaView.setText("areaView".getDefaultValue()) + lineView.setText("lineView".getDefaultValue()) + roadView.setText("roadView".getDefaultValue()) + ownerView.setText("ownerView".getDefaultValue()) + identifierDeepView.setText("identifierDeepView".getDefaultValue()) + personDeptView.setText("personDeptView".getDefaultValue()) } override fun initEvent() { leftBackView.setOnClickListener { finish() } /**************************************************************************************/ - objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 1, + objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { objectTypeSelectedItem = default @@ -67,7 +90,7 @@ } }) - materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { materialSelectedItem = default @@ -78,7 +101,7 @@ } }) - downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 1, + downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeSelectedItem = default @@ -89,7 +112,7 @@ } }) - downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeMaterialSelectedItem = default @@ -100,7 +123,7 @@ } }) - buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 1, + buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { buryMethodSelectedItem = default @@ -112,11 +135,15 @@ }) constructDateView.setOnClickListener { - showDatePicker(DateEntity.today(), object : DateSelectedCallback { - override fun onDateSelected(date: String) { - constructDateView.text = date - } - }) + val year = calendar.get(Calendar.YEAR) + val month = calendar.get(Calendar.MONTH) + val day = calendar.get(Calendar.DAY_OF_MONTH) + val datePicker = DatePickerDialog(this, { _, y, m, d -> + constructDateView.text = String.format( + "%s-%s-%s", y, m.appendZero(), d.appendZero() + ) + }, year, month, day) + datePicker.show() } identifierTypeSpinner.show(this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0, @@ -161,16 +188,153 @@ if (realPaths[position].isEmpty()) { "图片加载失败,无法查看大图".show(context) } else { -// context.navigatePageTo(position, realPaths) + context.navigatePageTo(position, realPaths) } } override fun onItemLongClick(view: View?, position: Int) { - imagePaths.removeAt(position) imageAdapter.deleteImage(position) } }) /**************************************************************************************/ + installButton.setOnClickListener { + if (isNetworkConnected()) { + val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + if (markerObjectTypeView.text.isNullOrBlank()) { + when (objectTypeSelectedItem) { + "管线" -> { + "请输入管线种类!".show(this) + } + "管线附属物" -> { + "请输入附属物名称!".show(this) + } + "管线特征管点" -> { + "请输入特征管点!".show(this) + } + "交叉穿越点" -> { + "请输入上层管种类!".show(this) + } + } + return@setOnClickListener + } + + if (pipelineDiameterView.text.isNullOrBlank()) { + "请输入管径".show(this) + return@setOnClickListener + } + + if (buryDeepView.text.isNullOrBlank()) { + "请输入埋深".show(this) + return@setOnClickListener + } + + if (downPipeDiameterView.text.isNullOrBlank()) { + "请输入下层管管径".show(this) + return@setOnClickListener + } + + if (areaView.text.isNullOrBlank()) { + "请输入所属区域".show(this) + return@setOnClickListener + } + + if (lineView.text.isNullOrBlank()) { + "请输入所属线路".show(this) + return@setOnClickListener + } + + if (roadView.text.isNullOrBlank()) { + "请输入所属道路".show(this) + return@setOnClickListener + } + + if (constructDateView.text.isNullOrBlank()) { + "请选择建设年代".show(this) + return@setOnClickListener + } + + if (ownerView.text.isNullOrBlank()) { + "请输入权属单位".show(this) + return@setOnClickListener + } + + if (identifierIdView.text.isNullOrBlank()) { + "请先读取标识器获取ID".show(this) + return@setOnClickListener + } + + if (identifierDeepView.text.isNullOrBlank()) { + "请输入标识器埋深".show(this) + return@setOnClickListener + } + + if (personDeptView.text.isNullOrBlank()) { + "请输入标识器安装部门".show(this) + return@setOnClickListener + } + + taskViewModel.installLabel( + companyId, + objectTypeSelectedItem.toObjectType(), + markerObjectTypeView.text.toString(), + materialSelectedItem, + "${pipelineDiameterView.text}mm", + "${buryDeepView.text}mm", + downPipeSelectedItem, + downPipeMaterialSelectedItem, + "${downPipeDiameterView.text}mm", + "${downPointDeepView.text}mm", + buryMethodSelectedItem, + areaView.text.toString(), + lineView.text.toString(), + roadView.text.toString(), + constructDateView.text.toString(), + ownerView.text.toString(), + objectId, + identifierIdView.text.toString(), + identifierTypeSelectedItem, + "${identifierDeepView.text}mm", + personDeptView.text.toString(), + installTimeView.text.toString(), + lngView.text.toString(), + latView.text.toString(), + colorSelectedItem.toColor(), + remarkView.text.toString(), + realPaths + ) + + //保存默认值 + "markerObjectTypeView".setDefaultValue(markerObjectTypeView.text.toString()) + "pipelineDiameterView".setDefaultValue(pipelineDiameterView.text.toString()) + "buryDeepView".setDefaultValue(buryDeepView.text.toString()) + "downPipeDiameterView".setDefaultValue(downPipeDiameterView.text.toString()) + "downPointDeepView".setDefaultValue(downPointDeepView.text.toString()) + "areaView".setDefaultValue(areaView.text.toString()) + "lineView".setDefaultValue(lineView.text.toString()) + "roadView".setDefaultValue(roadView.text.toString()) + "ownerView".setDefaultValue(ownerView.text.toString()) + "identifierDeepView".setDefaultValue(identifierDeepView.text.toString()) + "personDeptView".setDefaultValue(personDeptView.text.toString()) + } else { + NoNetworkDialog.Builder() + .setContext(context) + .setOnDialogButtonClickListener(object : + NoNetworkDialog.OnDialogButtonClickListener { + override fun onButtonClick() { + val intent = Intent(Settings.ACTION_SETTINGS) + startActivity(intent) + } + }).build().show() + } + } + + //TODO 搜索标识器 + readLabelButton.setOnClickListener { + LoadingDialogHub.show(this, "正在搜索标识器,请稍后...") + identifierIdView.text = "123456789" + LoadingDialogHub.dismiss() + } } private fun takePicture() { @@ -191,11 +355,11 @@ } private fun analyticalSelectResults(result: LocalMedia) { - //压缩图片后上传 + //压缩图片 result.realPath.compressImage(this, object : OnImageCompressListener { override fun onSuccess(file: File) { - //上传图片 -// fileUploadViewModel.uploadFile(file) + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) } override fun onError(e: Throwable) { @@ -207,7 +371,51 @@ override fun initLayoutView(): Int = R.layout.activity_install_label override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...") + LoadState.Success -> { + saveLabelInLocal() + LoadingDialogHub.dismiss() + finish() + } + else -> LoadingDialogHub.dismiss() + } + } + } + //安装成功后将标识器保存在本地 + private fun saveLabelInLocal() { + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + + val labelBean = LabelBean() + labelBean.objectType = objectTypeSelectedItem + labelBean.pipelineType = markerObjectTypeView.text.toString() + labelBean.pipelineMaterial = materialSelectedItem + labelBean.pipelineDiameter = "${pipelineDiameterView.text}mm" + labelBean.buryDeep = "${buryDeepView.text}mm" + labelBean.lowerType = downPipeSelectedItem + labelBean.lowerMaterial = downPipeMaterialSelectedItem + labelBean.lowerDiameter = "${downPipeDiameterView.text}mm" + labelBean.lowerDeep = "${downPointDeepView.text}mm" + labelBean.buryMethod = buryMethodSelectedItem + labelBean.area = areaView.text.toString() + labelBean.line = lineView.text.toString() + labelBean.road = roadView.text.toString() + labelBean.constructTime = constructDateView.text.toString() + labelBean.owner = ownerView.text.toString() + labelBean.objectId = objectId + labelBean.identifierId = identifierIdView.text.toString() + labelBean.identifierType = identifierTypeSelectedItem + labelBean.identifierDeep = "${identifierDeepView.text}mm" + labelBean.person = personDeptView.text.toString() + labelBean.installTime = installTimeView.text.toString() + labelBean.lng = lngView.text.toString() + labelBean.lat = latView.text.toString() + labelBean.color = colorSelectedItem.toColor() + labelBean.remark = remarkView.text.toString() + + DataBaseManager.get.insertTaskLabel(labelBean) } override fun setupTopBarLayout() { diff --git a/app/src/main/java/com/casic/detector/view/MainActivity.kt b/app/src/main/java/com/casic/detector/view/MainActivity.kt index cd06e07..9b791e9 100644 --- a/app/src/main/java/com/casic/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/detector/view/MainActivity.kt @@ -571,7 +571,8 @@ labelBean.lng, labelBean.lat, labelBean.color, - labelBean.remark + labelBean.remark, + arrayListOf() ) } LoadingDialogHub.dismiss() diff --git a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt index 082ee39..82813ff 100644 --- a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt @@ -39,7 +39,7 @@ objectJson, object : TypeToken() {}.type ) - objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt()] + objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt() - 1] pipelineTypeView.text = labelBean.pipelineType pipelineDiameterView.text = labelBean.pipelineDiameter pipelineMaterialView.text = labelBean.pipelineMaterial diff --git a/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt index 845b2b8..2475f0d 100644 --- a/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt @@ -89,8 +89,10 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ) = launch({ + loadState.value = LoadState.Loading val response = RetrofitServiceManager.installLabel( companyId, recordType, @@ -117,16 +119,17 @@ longitude, latitude, colorType, - memo + memo, + realPaths ) if (response.separateResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + loadState.value = LoadState.Success } else { + loadState.value = LoadState.Fail response.toErrorMessage().show(BaseApplication.get()) } }, { + loadState.value = LoadState.Fail it.convertChinese().show(BaseApplication.get()) }) diff --git a/app/src/main/res/layout/activity_big_image.xml b/app/src/main/res/layout/activity_big_image.xml new file mode 100644 index 0000000..9d060f4 --- /dev/null +++ b/app/src/main/res/layout/activity_big_image.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_install_label.xml b/app/src/main/res/layout/activity_install_label.xml index 10dfdc2..e191ec8 100644 --- a/app/src/main/res/layout/activity_install_label.xml +++ b/app/src/main/res/layout/activity_install_label.xml @@ -64,9 +64,11 @@ android:textSize="@dimen/sp_18" /> + android:layout_height="@dimen/dp_100" + android:gravity="top" + android:paddingVertical="@dimen/dp_5" /> diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Int.kt b/app/src/main/java/com/casic/detector/extensions/Int.kt index 10275bb..d67cac8 100644 --- a/app/src/main/java/com/casic/detector/extensions/Int.kt +++ b/app/src/main/java/com/casic/detector/extensions/Int.kt @@ -13,4 +13,12 @@ paint.color = color canvas.drawArc(rectF, 0f, 360f, true, paint) return bitmap +} + +fun Int.appendZero(): String { + return if (this < 10) { + "0$this" + } else { + this.toString() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index 7352dc1..aacd89d 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -45,6 +45,36 @@ } } +fun String.toObjectType(): String { + return if (this == LocaleConstant.POINT_TYPE_ARRAY[0]) { + "1" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[1]) { + "2" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[2]) { + "3" + } else { + "4" + } +} + +fun String.toColor(): String { + return if (this == LocaleConstant.COLOR_ARRAY[0]) { + "0" + } else if (this == LocaleConstant.COLOR_ARRAY[1]) { + "1" + } else if (this == LocaleConstant.COLOR_ARRAY[2]) { + "2" + } else if (this == LocaleConstant.COLOR_ARRAY[3]) { + "3" + } else if (this == LocaleConstant.COLOR_ARRAY[4]) { + "4" + } else if (this == LocaleConstant.COLOR_ARRAY[5]) { + "5" + } else { + "6" + } +} + fun String.compressImage(context: Context, listener: OnImageCompressListener) { Luban.with(context) .load(this) @@ -63,4 +93,14 @@ listener.onError(e) } }).launch() +} + +//根据控件名字存默认值 +fun String.setDefaultValue(value: String) { + SaveKeyValues.putValue(this, value) +} + +//根据控件名字取默认值 +fun String.getDefaultValue(): String { + return SaveKeyValues.getValue(this, "") as String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 6ee3191..9e862aa 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -1,10 +1,8 @@ package com.casic.detector.retrofit +import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query +import retrofit2.http.* interface RetrofitService { /** @@ -56,6 +54,12 @@ /** * 安装新标识器 */ + @Multipart @POST("/ems/marker/save-marker-photo.do") - suspend fun installLabel(@Body requestBody: RequestBody): String + suspend fun installLabel( + @PartMap jsonMarker: Map, + @Part fileBuffer1: MultipartBody.Part?, + @Part fileBuffer2: MultipartBody.Part?, + @Part fileBuffer3: MultipartBody.Part? + ): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 1549f93..6e6f1ae 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -7,7 +7,11 @@ import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody +import java.io.File object RetrofitServiceManager { private val api by lazy { @@ -68,6 +72,7 @@ /** * 安装新标识器 + * Multipart上传图片,文件,带多参数上传 */ suspend fun installLabel( companyId: String, @@ -95,7 +100,8 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ): String { val param = JsonObject() param.addProperty("companyId", companyId) @@ -127,6 +133,31 @@ val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return api.installLabel(requestBody) + val res = HashMap() + res["jsonMarker"] = requestBody + + val multiParts = ArrayList() + realPaths.forEachIndexed { index, s -> + val file = File(s) + val fileMultipart = MultipartBody.Part.createFormData( + "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) + ) + multiParts.add(fileMultipart) + } + + return when (multiParts.size) { + 3 -> { + api.installLabel(res, multiParts[0], multiParts[1], multiParts[2]) + } + 2 -> { + api.installLabel(res, multiParts[0], multiParts[1], null) + } + 1 -> { + api.installLabel(res, multiParts[0], null, null) + } + else -> { + api.installLabel(res, null, null, null) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt index 5bb7fbe..e34bbb8 100644 --- a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt @@ -22,16 +22,17 @@ const val USER_NAME = "USER_NAME" const val USER_ID = "USER_ID" const val USER_COMPANY_ID = "USER_COMPANY_ID" + const val OBJECT_ID = "OBJECT_ID" const val SERVER_IP = "SERVER_IP" const val SERVER_PORT = "SERVER_PORT" const val APP_AUTHORITY = "com.casic.detector.fileprovider" val POPUP_TITLES = arrayOf("更新数据", "下载工单", "关于软件", "事件上报", "标识器补全") - var POINT_TYPE_ARRAY = arrayOf("", "管线", "管线附属物", "管线特征管点", "交叉穿越点") + var POINT_TYPE_ARRAY = arrayOf("管线", "管线附属物", "管线特征管点", "交叉穿越点") var SPINNER_ARRAY = arrayOf("标识器ID", "所属区域", "所属线路", "所属道路", "权属单位", "安装部门", "安装时间", "备注") - var PIPE_MATERIAL_ARRAY = arrayOf("", "铸铁", "塑料") - var DOWN_PIPE_TYPE_ARRAY = arrayOf("", "热力", "燃气", "供水", "电力", "通信") - var BURY_METHOD_ARRAY = arrayOf("", "直埋", "圆管", "管块", "管沟", "架空") + var PIPE_MATERIAL_ARRAY = arrayOf("铸铁", "塑料") + var DOWN_PIPE_TYPE_ARRAY = arrayOf("热力", "燃气", "供水", "电力", "通信") + var BURY_METHOD_ARRAY = arrayOf("直埋", "圆管", "管块", "管沟", "架空") var IDENTIFIER_TYPE_ARRAY = arrayOf("EM30", "EM50", "EM14") var COLOR_ARRAY = arrayOf("蓝色", "橙色", "红色", "黑色", "紫色", "黄色", "绿色") } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/BigImageActivity.kt b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt new file mode 100644 index 0000000..ca6c7d7 --- /dev/null +++ b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt @@ -0,0 +1,87 @@ +package com.casic.detector.view + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant +import com.pengxh.kt.lite.utils.ImmerseStatusBarUtil +import kotlinx.android.synthetic.main.activity_big_image.* + +class BigImageActivity : KotlinBaseActivity() { + + override fun initLayoutView(): Int = R.layout.activity_big_image + + override fun setupTopBarLayout() { + ImmerseStatusBarUtil.setColor(this, Color.BLACK) + leftBackView.setOnClickListener { finish() } + } + + override fun initData() { + + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + val index: Int = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + imagePagerView.adapter = BigImageAdapter(this, urls) + imagePagerView.currentItem = index + imagePagerView.offscreenPageLimit = imageSize + imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + pageNumberView.text = String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt index d61bec9..02b455f 100644 --- a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt @@ -1,43 +1,50 @@ package com.casic.detector.view +import android.annotation.SuppressLint +import android.app.DatePickerDialog import android.content.Context +import android.content.Intent +import android.provider.Settings import android.view.View +import androidx.lifecycle.ViewModelProvider import com.amap.api.location.AMapLocation import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback +import com.casic.detector.adapter.EditableImageAdapter +import com.casic.detector.bean.LabelBean import com.casic.detector.callback.ILocationListener import com.casic.detector.callback.OnImageCompressListener import com.casic.detector.callback.OnItemSelectedListener -import com.casic.detector.extensions.compressImage -import com.casic.detector.extensions.initLayoutImmersionBar -import com.casic.detector.extensions.show -import com.casic.detector.extensions.showDatePicker +import com.casic.detector.extensions.* +import com.casic.detector.utils.DataBaseManager +import com.casic.detector.utils.LoadingDialogHub import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity +import com.casic.detector.vm.TaskViewModel import com.gyf.immersionbar.ImmersionBar import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType import com.luck.picture.lib.entity.LocalMedia import com.luck.picture.lib.interfaces.OnResultCallbackListener -import com.pengxh.kt.lite.adapter.EditableImageAdapter import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.extensions.timestampToCompleteDate +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.vm.LoadState +import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog import kotlinx.android.synthetic.main.activity_install_label.* import kotlinx.android.synthetic.main.include_base_title.* import kotlinx.android.synthetic.main.include_install_label_identifier.* import kotlinx.android.synthetic.main.include_install_label_object.* import kotlinx.android.synthetic.main.include_install_label_open_camera.* import java.io.File +import java.util.* +@SuppressLint("SetTextI18n") class InstallLabelActivity : KotlinBaseActivity() { private val kTag = "InstallLabelActivity" private val context: Context = this@InstallLabelActivity + private val calendar by lazy { Calendar.getInstance() } private lateinit var imageAdapter: EditableImageAdapter - private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 private val realPaths: ArrayList = ArrayList() //真实图片路径 private var objectTypeSelectedItem = "" private var materialSelectedItem = "" @@ -46,17 +53,33 @@ private var buryMethodSelectedItem = "" private var identifierTypeSelectedItem = "" private var colorSelectedItem = "" + private lateinit var taskViewModel: TaskViewModel override fun initData() { imageAdapter = EditableImageAdapter(this, 3, 3f) addImageRecyclerView.adapter = imageAdapter + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + //设置默认值 + markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue()) + pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue()) + buryDeepView.setText("buryDeepView".getDefaultValue()) + downPipeDiameterView.setText("downPipeDiameterView".getDefaultValue()) + downPointDeepView.setText("downPointDeepView".getDefaultValue()) + areaView.setText("areaView".getDefaultValue()) + lineView.setText("lineView".getDefaultValue()) + roadView.setText("roadView".getDefaultValue()) + ownerView.setText("ownerView".getDefaultValue()) + identifierDeepView.setText("identifierDeepView".getDefaultValue()) + personDeptView.setText("personDeptView".getDefaultValue()) } override fun initEvent() { leftBackView.setOnClickListener { finish() } /**************************************************************************************/ - objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 1, + objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { objectTypeSelectedItem = default @@ -67,7 +90,7 @@ } }) - materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { materialSelectedItem = default @@ -78,7 +101,7 @@ } }) - downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 1, + downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeSelectedItem = default @@ -89,7 +112,7 @@ } }) - downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeMaterialSelectedItem = default @@ -100,7 +123,7 @@ } }) - buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 1, + buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { buryMethodSelectedItem = default @@ -112,11 +135,15 @@ }) constructDateView.setOnClickListener { - showDatePicker(DateEntity.today(), object : DateSelectedCallback { - override fun onDateSelected(date: String) { - constructDateView.text = date - } - }) + val year = calendar.get(Calendar.YEAR) + val month = calendar.get(Calendar.MONTH) + val day = calendar.get(Calendar.DAY_OF_MONTH) + val datePicker = DatePickerDialog(this, { _, y, m, d -> + constructDateView.text = String.format( + "%s-%s-%s", y, m.appendZero(), d.appendZero() + ) + }, year, month, day) + datePicker.show() } identifierTypeSpinner.show(this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0, @@ -161,16 +188,153 @@ if (realPaths[position].isEmpty()) { "图片加载失败,无法查看大图".show(context) } else { -// context.navigatePageTo(position, realPaths) + context.navigatePageTo(position, realPaths) } } override fun onItemLongClick(view: View?, position: Int) { - imagePaths.removeAt(position) imageAdapter.deleteImage(position) } }) /**************************************************************************************/ + installButton.setOnClickListener { + if (isNetworkConnected()) { + val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + if (markerObjectTypeView.text.isNullOrBlank()) { + when (objectTypeSelectedItem) { + "管线" -> { + "请输入管线种类!".show(this) + } + "管线附属物" -> { + "请输入附属物名称!".show(this) + } + "管线特征管点" -> { + "请输入特征管点!".show(this) + } + "交叉穿越点" -> { + "请输入上层管种类!".show(this) + } + } + return@setOnClickListener + } + + if (pipelineDiameterView.text.isNullOrBlank()) { + "请输入管径".show(this) + return@setOnClickListener + } + + if (buryDeepView.text.isNullOrBlank()) { + "请输入埋深".show(this) + return@setOnClickListener + } + + if (downPipeDiameterView.text.isNullOrBlank()) { + "请输入下层管管径".show(this) + return@setOnClickListener + } + + if (areaView.text.isNullOrBlank()) { + "请输入所属区域".show(this) + return@setOnClickListener + } + + if (lineView.text.isNullOrBlank()) { + "请输入所属线路".show(this) + return@setOnClickListener + } + + if (roadView.text.isNullOrBlank()) { + "请输入所属道路".show(this) + return@setOnClickListener + } + + if (constructDateView.text.isNullOrBlank()) { + "请选择建设年代".show(this) + return@setOnClickListener + } + + if (ownerView.text.isNullOrBlank()) { + "请输入权属单位".show(this) + return@setOnClickListener + } + + if (identifierIdView.text.isNullOrBlank()) { + "请先读取标识器获取ID".show(this) + return@setOnClickListener + } + + if (identifierDeepView.text.isNullOrBlank()) { + "请输入标识器埋深".show(this) + return@setOnClickListener + } + + if (personDeptView.text.isNullOrBlank()) { + "请输入标识器安装部门".show(this) + return@setOnClickListener + } + + taskViewModel.installLabel( + companyId, + objectTypeSelectedItem.toObjectType(), + markerObjectTypeView.text.toString(), + materialSelectedItem, + "${pipelineDiameterView.text}mm", + "${buryDeepView.text}mm", + downPipeSelectedItem, + downPipeMaterialSelectedItem, + "${downPipeDiameterView.text}mm", + "${downPointDeepView.text}mm", + buryMethodSelectedItem, + areaView.text.toString(), + lineView.text.toString(), + roadView.text.toString(), + constructDateView.text.toString(), + ownerView.text.toString(), + objectId, + identifierIdView.text.toString(), + identifierTypeSelectedItem, + "${identifierDeepView.text}mm", + personDeptView.text.toString(), + installTimeView.text.toString(), + lngView.text.toString(), + latView.text.toString(), + colorSelectedItem.toColor(), + remarkView.text.toString(), + realPaths + ) + + //保存默认值 + "markerObjectTypeView".setDefaultValue(markerObjectTypeView.text.toString()) + "pipelineDiameterView".setDefaultValue(pipelineDiameterView.text.toString()) + "buryDeepView".setDefaultValue(buryDeepView.text.toString()) + "downPipeDiameterView".setDefaultValue(downPipeDiameterView.text.toString()) + "downPointDeepView".setDefaultValue(downPointDeepView.text.toString()) + "areaView".setDefaultValue(areaView.text.toString()) + "lineView".setDefaultValue(lineView.text.toString()) + "roadView".setDefaultValue(roadView.text.toString()) + "ownerView".setDefaultValue(ownerView.text.toString()) + "identifierDeepView".setDefaultValue(identifierDeepView.text.toString()) + "personDeptView".setDefaultValue(personDeptView.text.toString()) + } else { + NoNetworkDialog.Builder() + .setContext(context) + .setOnDialogButtonClickListener(object : + NoNetworkDialog.OnDialogButtonClickListener { + override fun onButtonClick() { + val intent = Intent(Settings.ACTION_SETTINGS) + startActivity(intent) + } + }).build().show() + } + } + + //TODO 搜索标识器 + readLabelButton.setOnClickListener { + LoadingDialogHub.show(this, "正在搜索标识器,请稍后...") + identifierIdView.text = "123456789" + LoadingDialogHub.dismiss() + } } private fun takePicture() { @@ -191,11 +355,11 @@ } private fun analyticalSelectResults(result: LocalMedia) { - //压缩图片后上传 + //压缩图片 result.realPath.compressImage(this, object : OnImageCompressListener { override fun onSuccess(file: File) { - //上传图片 -// fileUploadViewModel.uploadFile(file) + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) } override fun onError(e: Throwable) { @@ -207,7 +371,51 @@ override fun initLayoutView(): Int = R.layout.activity_install_label override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...") + LoadState.Success -> { + saveLabelInLocal() + LoadingDialogHub.dismiss() + finish() + } + else -> LoadingDialogHub.dismiss() + } + } + } + //安装成功后将标识器保存在本地 + private fun saveLabelInLocal() { + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + + val labelBean = LabelBean() + labelBean.objectType = objectTypeSelectedItem + labelBean.pipelineType = markerObjectTypeView.text.toString() + labelBean.pipelineMaterial = materialSelectedItem + labelBean.pipelineDiameter = "${pipelineDiameterView.text}mm" + labelBean.buryDeep = "${buryDeepView.text}mm" + labelBean.lowerType = downPipeSelectedItem + labelBean.lowerMaterial = downPipeMaterialSelectedItem + labelBean.lowerDiameter = "${downPipeDiameterView.text}mm" + labelBean.lowerDeep = "${downPointDeepView.text}mm" + labelBean.buryMethod = buryMethodSelectedItem + labelBean.area = areaView.text.toString() + labelBean.line = lineView.text.toString() + labelBean.road = roadView.text.toString() + labelBean.constructTime = constructDateView.text.toString() + labelBean.owner = ownerView.text.toString() + labelBean.objectId = objectId + labelBean.identifierId = identifierIdView.text.toString() + labelBean.identifierType = identifierTypeSelectedItem + labelBean.identifierDeep = "${identifierDeepView.text}mm" + labelBean.person = personDeptView.text.toString() + labelBean.installTime = installTimeView.text.toString() + labelBean.lng = lngView.text.toString() + labelBean.lat = latView.text.toString() + labelBean.color = colorSelectedItem.toColor() + labelBean.remark = remarkView.text.toString() + + DataBaseManager.get.insertTaskLabel(labelBean) } override fun setupTopBarLayout() { diff --git a/app/src/main/java/com/casic/detector/view/MainActivity.kt b/app/src/main/java/com/casic/detector/view/MainActivity.kt index cd06e07..9b791e9 100644 --- a/app/src/main/java/com/casic/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/detector/view/MainActivity.kt @@ -571,7 +571,8 @@ labelBean.lng, labelBean.lat, labelBean.color, - labelBean.remark + labelBean.remark, + arrayListOf() ) } LoadingDialogHub.dismiss() diff --git a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt index 082ee39..82813ff 100644 --- a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt @@ -39,7 +39,7 @@ objectJson, object : TypeToken() {}.type ) - objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt()] + objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt() - 1] pipelineTypeView.text = labelBean.pipelineType pipelineDiameterView.text = labelBean.pipelineDiameter pipelineMaterialView.text = labelBean.pipelineMaterial diff --git a/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt index 845b2b8..2475f0d 100644 --- a/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt @@ -89,8 +89,10 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ) = launch({ + loadState.value = LoadState.Loading val response = RetrofitServiceManager.installLabel( companyId, recordType, @@ -117,16 +119,17 @@ longitude, latitude, colorType, - memo + memo, + realPaths ) if (response.separateResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + loadState.value = LoadState.Success } else { + loadState.value = LoadState.Fail response.toErrorMessage().show(BaseApplication.get()) } }, { + loadState.value = LoadState.Fail it.convertChinese().show(BaseApplication.get()) }) diff --git a/app/src/main/res/layout/activity_big_image.xml b/app/src/main/res/layout/activity_big_image.xml new file mode 100644 index 0000000..9d060f4 --- /dev/null +++ b/app/src/main/res/layout/activity_big_image.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_install_label.xml b/app/src/main/res/layout/activity_install_label.xml index 10dfdc2..e191ec8 100644 --- a/app/src/main/res/layout/activity_install_label.xml +++ b/app/src/main/res/layout/activity_install_label.xml @@ -64,9 +64,11 @@ android:textSize="@dimen/sp_18" /> + android:layout_height="@dimen/dp_100" + android:gravity="top" + android:paddingVertical="@dimen/dp_5" /> diff --git a/app/src/main/res/layout/include_install_label_identifier.xml b/app/src/main/res/layout/include_install_label_identifier.xml index 87f0070..d166fd0 100644 --- a/app/src/main/res/layout/include_install_label_identifier.xml +++ b/app/src/main/res/layout/include_install_label_identifier.xml @@ -37,7 +37,10 @@ style="@style/textViewStyle" android:text="ID号:" /> - + @@ -100,7 +104,9 @@ style="@style/textViewStyle" android:text="部门:" /> - + + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Int.kt b/app/src/main/java/com/casic/detector/extensions/Int.kt index 10275bb..d67cac8 100644 --- a/app/src/main/java/com/casic/detector/extensions/Int.kt +++ b/app/src/main/java/com/casic/detector/extensions/Int.kt @@ -13,4 +13,12 @@ paint.color = color canvas.drawArc(rectF, 0f, 360f, true, paint) return bitmap +} + +fun Int.appendZero(): String { + return if (this < 10) { + "0$this" + } else { + this.toString() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index 7352dc1..aacd89d 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -45,6 +45,36 @@ } } +fun String.toObjectType(): String { + return if (this == LocaleConstant.POINT_TYPE_ARRAY[0]) { + "1" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[1]) { + "2" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[2]) { + "3" + } else { + "4" + } +} + +fun String.toColor(): String { + return if (this == LocaleConstant.COLOR_ARRAY[0]) { + "0" + } else if (this == LocaleConstant.COLOR_ARRAY[1]) { + "1" + } else if (this == LocaleConstant.COLOR_ARRAY[2]) { + "2" + } else if (this == LocaleConstant.COLOR_ARRAY[3]) { + "3" + } else if (this == LocaleConstant.COLOR_ARRAY[4]) { + "4" + } else if (this == LocaleConstant.COLOR_ARRAY[5]) { + "5" + } else { + "6" + } +} + fun String.compressImage(context: Context, listener: OnImageCompressListener) { Luban.with(context) .load(this) @@ -63,4 +93,14 @@ listener.onError(e) } }).launch() +} + +//根据控件名字存默认值 +fun String.setDefaultValue(value: String) { + SaveKeyValues.putValue(this, value) +} + +//根据控件名字取默认值 +fun String.getDefaultValue(): String { + return SaveKeyValues.getValue(this, "") as String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 6ee3191..9e862aa 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -1,10 +1,8 @@ package com.casic.detector.retrofit +import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query +import retrofit2.http.* interface RetrofitService { /** @@ -56,6 +54,12 @@ /** * 安装新标识器 */ + @Multipart @POST("/ems/marker/save-marker-photo.do") - suspend fun installLabel(@Body requestBody: RequestBody): String + suspend fun installLabel( + @PartMap jsonMarker: Map, + @Part fileBuffer1: MultipartBody.Part?, + @Part fileBuffer2: MultipartBody.Part?, + @Part fileBuffer3: MultipartBody.Part? + ): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 1549f93..6e6f1ae 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -7,7 +7,11 @@ import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody +import java.io.File object RetrofitServiceManager { private val api by lazy { @@ -68,6 +72,7 @@ /** * 安装新标识器 + * Multipart上传图片,文件,带多参数上传 */ suspend fun installLabel( companyId: String, @@ -95,7 +100,8 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ): String { val param = JsonObject() param.addProperty("companyId", companyId) @@ -127,6 +133,31 @@ val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return api.installLabel(requestBody) + val res = HashMap() + res["jsonMarker"] = requestBody + + val multiParts = ArrayList() + realPaths.forEachIndexed { index, s -> + val file = File(s) + val fileMultipart = MultipartBody.Part.createFormData( + "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) + ) + multiParts.add(fileMultipart) + } + + return when (multiParts.size) { + 3 -> { + api.installLabel(res, multiParts[0], multiParts[1], multiParts[2]) + } + 2 -> { + api.installLabel(res, multiParts[0], multiParts[1], null) + } + 1 -> { + api.installLabel(res, multiParts[0], null, null) + } + else -> { + api.installLabel(res, null, null, null) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt index 5bb7fbe..e34bbb8 100644 --- a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt @@ -22,16 +22,17 @@ const val USER_NAME = "USER_NAME" const val USER_ID = "USER_ID" const val USER_COMPANY_ID = "USER_COMPANY_ID" + const val OBJECT_ID = "OBJECT_ID" const val SERVER_IP = "SERVER_IP" const val SERVER_PORT = "SERVER_PORT" const val APP_AUTHORITY = "com.casic.detector.fileprovider" val POPUP_TITLES = arrayOf("更新数据", "下载工单", "关于软件", "事件上报", "标识器补全") - var POINT_TYPE_ARRAY = arrayOf("", "管线", "管线附属物", "管线特征管点", "交叉穿越点") + var POINT_TYPE_ARRAY = arrayOf("管线", "管线附属物", "管线特征管点", "交叉穿越点") var SPINNER_ARRAY = arrayOf("标识器ID", "所属区域", "所属线路", "所属道路", "权属单位", "安装部门", "安装时间", "备注") - var PIPE_MATERIAL_ARRAY = arrayOf("", "铸铁", "塑料") - var DOWN_PIPE_TYPE_ARRAY = arrayOf("", "热力", "燃气", "供水", "电力", "通信") - var BURY_METHOD_ARRAY = arrayOf("", "直埋", "圆管", "管块", "管沟", "架空") + var PIPE_MATERIAL_ARRAY = arrayOf("铸铁", "塑料") + var DOWN_PIPE_TYPE_ARRAY = arrayOf("热力", "燃气", "供水", "电力", "通信") + var BURY_METHOD_ARRAY = arrayOf("直埋", "圆管", "管块", "管沟", "架空") var IDENTIFIER_TYPE_ARRAY = arrayOf("EM30", "EM50", "EM14") var COLOR_ARRAY = arrayOf("蓝色", "橙色", "红色", "黑色", "紫色", "黄色", "绿色") } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/BigImageActivity.kt b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt new file mode 100644 index 0000000..ca6c7d7 --- /dev/null +++ b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt @@ -0,0 +1,87 @@ +package com.casic.detector.view + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant +import com.pengxh.kt.lite.utils.ImmerseStatusBarUtil +import kotlinx.android.synthetic.main.activity_big_image.* + +class BigImageActivity : KotlinBaseActivity() { + + override fun initLayoutView(): Int = R.layout.activity_big_image + + override fun setupTopBarLayout() { + ImmerseStatusBarUtil.setColor(this, Color.BLACK) + leftBackView.setOnClickListener { finish() } + } + + override fun initData() { + + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + val index: Int = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + imagePagerView.adapter = BigImageAdapter(this, urls) + imagePagerView.currentItem = index + imagePagerView.offscreenPageLimit = imageSize + imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + pageNumberView.text = String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt index d61bec9..02b455f 100644 --- a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt @@ -1,43 +1,50 @@ package com.casic.detector.view +import android.annotation.SuppressLint +import android.app.DatePickerDialog import android.content.Context +import android.content.Intent +import android.provider.Settings import android.view.View +import androidx.lifecycle.ViewModelProvider import com.amap.api.location.AMapLocation import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback +import com.casic.detector.adapter.EditableImageAdapter +import com.casic.detector.bean.LabelBean import com.casic.detector.callback.ILocationListener import com.casic.detector.callback.OnImageCompressListener import com.casic.detector.callback.OnItemSelectedListener -import com.casic.detector.extensions.compressImage -import com.casic.detector.extensions.initLayoutImmersionBar -import com.casic.detector.extensions.show -import com.casic.detector.extensions.showDatePicker +import com.casic.detector.extensions.* +import com.casic.detector.utils.DataBaseManager +import com.casic.detector.utils.LoadingDialogHub import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity +import com.casic.detector.vm.TaskViewModel import com.gyf.immersionbar.ImmersionBar import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType import com.luck.picture.lib.entity.LocalMedia import com.luck.picture.lib.interfaces.OnResultCallbackListener -import com.pengxh.kt.lite.adapter.EditableImageAdapter import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.extensions.timestampToCompleteDate +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.vm.LoadState +import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog import kotlinx.android.synthetic.main.activity_install_label.* import kotlinx.android.synthetic.main.include_base_title.* import kotlinx.android.synthetic.main.include_install_label_identifier.* import kotlinx.android.synthetic.main.include_install_label_object.* import kotlinx.android.synthetic.main.include_install_label_open_camera.* import java.io.File +import java.util.* +@SuppressLint("SetTextI18n") class InstallLabelActivity : KotlinBaseActivity() { private val kTag = "InstallLabelActivity" private val context: Context = this@InstallLabelActivity + private val calendar by lazy { Calendar.getInstance() } private lateinit var imageAdapter: EditableImageAdapter - private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 private val realPaths: ArrayList = ArrayList() //真实图片路径 private var objectTypeSelectedItem = "" private var materialSelectedItem = "" @@ -46,17 +53,33 @@ private var buryMethodSelectedItem = "" private var identifierTypeSelectedItem = "" private var colorSelectedItem = "" + private lateinit var taskViewModel: TaskViewModel override fun initData() { imageAdapter = EditableImageAdapter(this, 3, 3f) addImageRecyclerView.adapter = imageAdapter + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + //设置默认值 + markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue()) + pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue()) + buryDeepView.setText("buryDeepView".getDefaultValue()) + downPipeDiameterView.setText("downPipeDiameterView".getDefaultValue()) + downPointDeepView.setText("downPointDeepView".getDefaultValue()) + areaView.setText("areaView".getDefaultValue()) + lineView.setText("lineView".getDefaultValue()) + roadView.setText("roadView".getDefaultValue()) + ownerView.setText("ownerView".getDefaultValue()) + identifierDeepView.setText("identifierDeepView".getDefaultValue()) + personDeptView.setText("personDeptView".getDefaultValue()) } override fun initEvent() { leftBackView.setOnClickListener { finish() } /**************************************************************************************/ - objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 1, + objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { objectTypeSelectedItem = default @@ -67,7 +90,7 @@ } }) - materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { materialSelectedItem = default @@ -78,7 +101,7 @@ } }) - downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 1, + downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeSelectedItem = default @@ -89,7 +112,7 @@ } }) - downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeMaterialSelectedItem = default @@ -100,7 +123,7 @@ } }) - buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 1, + buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { buryMethodSelectedItem = default @@ -112,11 +135,15 @@ }) constructDateView.setOnClickListener { - showDatePicker(DateEntity.today(), object : DateSelectedCallback { - override fun onDateSelected(date: String) { - constructDateView.text = date - } - }) + val year = calendar.get(Calendar.YEAR) + val month = calendar.get(Calendar.MONTH) + val day = calendar.get(Calendar.DAY_OF_MONTH) + val datePicker = DatePickerDialog(this, { _, y, m, d -> + constructDateView.text = String.format( + "%s-%s-%s", y, m.appendZero(), d.appendZero() + ) + }, year, month, day) + datePicker.show() } identifierTypeSpinner.show(this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0, @@ -161,16 +188,153 @@ if (realPaths[position].isEmpty()) { "图片加载失败,无法查看大图".show(context) } else { -// context.navigatePageTo(position, realPaths) + context.navigatePageTo(position, realPaths) } } override fun onItemLongClick(view: View?, position: Int) { - imagePaths.removeAt(position) imageAdapter.deleteImage(position) } }) /**************************************************************************************/ + installButton.setOnClickListener { + if (isNetworkConnected()) { + val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + if (markerObjectTypeView.text.isNullOrBlank()) { + when (objectTypeSelectedItem) { + "管线" -> { + "请输入管线种类!".show(this) + } + "管线附属物" -> { + "请输入附属物名称!".show(this) + } + "管线特征管点" -> { + "请输入特征管点!".show(this) + } + "交叉穿越点" -> { + "请输入上层管种类!".show(this) + } + } + return@setOnClickListener + } + + if (pipelineDiameterView.text.isNullOrBlank()) { + "请输入管径".show(this) + return@setOnClickListener + } + + if (buryDeepView.text.isNullOrBlank()) { + "请输入埋深".show(this) + return@setOnClickListener + } + + if (downPipeDiameterView.text.isNullOrBlank()) { + "请输入下层管管径".show(this) + return@setOnClickListener + } + + if (areaView.text.isNullOrBlank()) { + "请输入所属区域".show(this) + return@setOnClickListener + } + + if (lineView.text.isNullOrBlank()) { + "请输入所属线路".show(this) + return@setOnClickListener + } + + if (roadView.text.isNullOrBlank()) { + "请输入所属道路".show(this) + return@setOnClickListener + } + + if (constructDateView.text.isNullOrBlank()) { + "请选择建设年代".show(this) + return@setOnClickListener + } + + if (ownerView.text.isNullOrBlank()) { + "请输入权属单位".show(this) + return@setOnClickListener + } + + if (identifierIdView.text.isNullOrBlank()) { + "请先读取标识器获取ID".show(this) + return@setOnClickListener + } + + if (identifierDeepView.text.isNullOrBlank()) { + "请输入标识器埋深".show(this) + return@setOnClickListener + } + + if (personDeptView.text.isNullOrBlank()) { + "请输入标识器安装部门".show(this) + return@setOnClickListener + } + + taskViewModel.installLabel( + companyId, + objectTypeSelectedItem.toObjectType(), + markerObjectTypeView.text.toString(), + materialSelectedItem, + "${pipelineDiameterView.text}mm", + "${buryDeepView.text}mm", + downPipeSelectedItem, + downPipeMaterialSelectedItem, + "${downPipeDiameterView.text}mm", + "${downPointDeepView.text}mm", + buryMethodSelectedItem, + areaView.text.toString(), + lineView.text.toString(), + roadView.text.toString(), + constructDateView.text.toString(), + ownerView.text.toString(), + objectId, + identifierIdView.text.toString(), + identifierTypeSelectedItem, + "${identifierDeepView.text}mm", + personDeptView.text.toString(), + installTimeView.text.toString(), + lngView.text.toString(), + latView.text.toString(), + colorSelectedItem.toColor(), + remarkView.text.toString(), + realPaths + ) + + //保存默认值 + "markerObjectTypeView".setDefaultValue(markerObjectTypeView.text.toString()) + "pipelineDiameterView".setDefaultValue(pipelineDiameterView.text.toString()) + "buryDeepView".setDefaultValue(buryDeepView.text.toString()) + "downPipeDiameterView".setDefaultValue(downPipeDiameterView.text.toString()) + "downPointDeepView".setDefaultValue(downPointDeepView.text.toString()) + "areaView".setDefaultValue(areaView.text.toString()) + "lineView".setDefaultValue(lineView.text.toString()) + "roadView".setDefaultValue(roadView.text.toString()) + "ownerView".setDefaultValue(ownerView.text.toString()) + "identifierDeepView".setDefaultValue(identifierDeepView.text.toString()) + "personDeptView".setDefaultValue(personDeptView.text.toString()) + } else { + NoNetworkDialog.Builder() + .setContext(context) + .setOnDialogButtonClickListener(object : + NoNetworkDialog.OnDialogButtonClickListener { + override fun onButtonClick() { + val intent = Intent(Settings.ACTION_SETTINGS) + startActivity(intent) + } + }).build().show() + } + } + + //TODO 搜索标识器 + readLabelButton.setOnClickListener { + LoadingDialogHub.show(this, "正在搜索标识器,请稍后...") + identifierIdView.text = "123456789" + LoadingDialogHub.dismiss() + } } private fun takePicture() { @@ -191,11 +355,11 @@ } private fun analyticalSelectResults(result: LocalMedia) { - //压缩图片后上传 + //压缩图片 result.realPath.compressImage(this, object : OnImageCompressListener { override fun onSuccess(file: File) { - //上传图片 -// fileUploadViewModel.uploadFile(file) + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) } override fun onError(e: Throwable) { @@ -207,7 +371,51 @@ override fun initLayoutView(): Int = R.layout.activity_install_label override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...") + LoadState.Success -> { + saveLabelInLocal() + LoadingDialogHub.dismiss() + finish() + } + else -> LoadingDialogHub.dismiss() + } + } + } + //安装成功后将标识器保存在本地 + private fun saveLabelInLocal() { + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + + val labelBean = LabelBean() + labelBean.objectType = objectTypeSelectedItem + labelBean.pipelineType = markerObjectTypeView.text.toString() + labelBean.pipelineMaterial = materialSelectedItem + labelBean.pipelineDiameter = "${pipelineDiameterView.text}mm" + labelBean.buryDeep = "${buryDeepView.text}mm" + labelBean.lowerType = downPipeSelectedItem + labelBean.lowerMaterial = downPipeMaterialSelectedItem + labelBean.lowerDiameter = "${downPipeDiameterView.text}mm" + labelBean.lowerDeep = "${downPointDeepView.text}mm" + labelBean.buryMethod = buryMethodSelectedItem + labelBean.area = areaView.text.toString() + labelBean.line = lineView.text.toString() + labelBean.road = roadView.text.toString() + labelBean.constructTime = constructDateView.text.toString() + labelBean.owner = ownerView.text.toString() + labelBean.objectId = objectId + labelBean.identifierId = identifierIdView.text.toString() + labelBean.identifierType = identifierTypeSelectedItem + labelBean.identifierDeep = "${identifierDeepView.text}mm" + labelBean.person = personDeptView.text.toString() + labelBean.installTime = installTimeView.text.toString() + labelBean.lng = lngView.text.toString() + labelBean.lat = latView.text.toString() + labelBean.color = colorSelectedItem.toColor() + labelBean.remark = remarkView.text.toString() + + DataBaseManager.get.insertTaskLabel(labelBean) } override fun setupTopBarLayout() { diff --git a/app/src/main/java/com/casic/detector/view/MainActivity.kt b/app/src/main/java/com/casic/detector/view/MainActivity.kt index cd06e07..9b791e9 100644 --- a/app/src/main/java/com/casic/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/detector/view/MainActivity.kt @@ -571,7 +571,8 @@ labelBean.lng, labelBean.lat, labelBean.color, - labelBean.remark + labelBean.remark, + arrayListOf() ) } LoadingDialogHub.dismiss() diff --git a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt index 082ee39..82813ff 100644 --- a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt @@ -39,7 +39,7 @@ objectJson, object : TypeToken() {}.type ) - objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt()] + objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt() - 1] pipelineTypeView.text = labelBean.pipelineType pipelineDiameterView.text = labelBean.pipelineDiameter pipelineMaterialView.text = labelBean.pipelineMaterial diff --git a/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt index 845b2b8..2475f0d 100644 --- a/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt @@ -89,8 +89,10 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ) = launch({ + loadState.value = LoadState.Loading val response = RetrofitServiceManager.installLabel( companyId, recordType, @@ -117,16 +119,17 @@ longitude, latitude, colorType, - memo + memo, + realPaths ) if (response.separateResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + loadState.value = LoadState.Success } else { + loadState.value = LoadState.Fail response.toErrorMessage().show(BaseApplication.get()) } }, { + loadState.value = LoadState.Fail it.convertChinese().show(BaseApplication.get()) }) diff --git a/app/src/main/res/layout/activity_big_image.xml b/app/src/main/res/layout/activity_big_image.xml new file mode 100644 index 0000000..9d060f4 --- /dev/null +++ b/app/src/main/res/layout/activity_big_image.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_install_label.xml b/app/src/main/res/layout/activity_install_label.xml index 10dfdc2..e191ec8 100644 --- a/app/src/main/res/layout/activity_install_label.xml +++ b/app/src/main/res/layout/activity_install_label.xml @@ -64,9 +64,11 @@ android:textSize="@dimen/sp_18" /> + android:layout_height="@dimen/dp_100" + android:gravity="top" + android:paddingVertical="@dimen/dp_5" /> diff --git a/app/src/main/res/layout/include_install_label_identifier.xml b/app/src/main/res/layout/include_install_label_identifier.xml index 87f0070..d166fd0 100644 --- a/app/src/main/res/layout/include_install_label_identifier.xml +++ b/app/src/main/res/layout/include_install_label_identifier.xml @@ -37,7 +37,10 @@ style="@style/textViewStyle" android:text="ID号:" /> - + @@ -100,7 +104,9 @@ style="@style/textViewStyle" android:text="部门:" /> - + - + @@ -120,6 +123,7 @@ android:text="埋深:" /> @@ -184,6 +188,7 @@ android:text="下层管直径:" /> @@ -210,6 +215,7 @@ android:text="下层管埋深:" /> @@ -254,7 +260,9 @@ style="@style/textViewStyle" android:text="所属区域:" /> - + - + - + - + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Int.kt b/app/src/main/java/com/casic/detector/extensions/Int.kt index 10275bb..d67cac8 100644 --- a/app/src/main/java/com/casic/detector/extensions/Int.kt +++ b/app/src/main/java/com/casic/detector/extensions/Int.kt @@ -13,4 +13,12 @@ paint.color = color canvas.drawArc(rectF, 0f, 360f, true, paint) return bitmap +} + +fun Int.appendZero(): String { + return if (this < 10) { + "0$this" + } else { + this.toString() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index 7352dc1..aacd89d 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -45,6 +45,36 @@ } } +fun String.toObjectType(): String { + return if (this == LocaleConstant.POINT_TYPE_ARRAY[0]) { + "1" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[1]) { + "2" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[2]) { + "3" + } else { + "4" + } +} + +fun String.toColor(): String { + return if (this == LocaleConstant.COLOR_ARRAY[0]) { + "0" + } else if (this == LocaleConstant.COLOR_ARRAY[1]) { + "1" + } else if (this == LocaleConstant.COLOR_ARRAY[2]) { + "2" + } else if (this == LocaleConstant.COLOR_ARRAY[3]) { + "3" + } else if (this == LocaleConstant.COLOR_ARRAY[4]) { + "4" + } else if (this == LocaleConstant.COLOR_ARRAY[5]) { + "5" + } else { + "6" + } +} + fun String.compressImage(context: Context, listener: OnImageCompressListener) { Luban.with(context) .load(this) @@ -63,4 +93,14 @@ listener.onError(e) } }).launch() +} + +//根据控件名字存默认值 +fun String.setDefaultValue(value: String) { + SaveKeyValues.putValue(this, value) +} + +//根据控件名字取默认值 +fun String.getDefaultValue(): String { + return SaveKeyValues.getValue(this, "") as String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 6ee3191..9e862aa 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -1,10 +1,8 @@ package com.casic.detector.retrofit +import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query +import retrofit2.http.* interface RetrofitService { /** @@ -56,6 +54,12 @@ /** * 安装新标识器 */ + @Multipart @POST("/ems/marker/save-marker-photo.do") - suspend fun installLabel(@Body requestBody: RequestBody): String + suspend fun installLabel( + @PartMap jsonMarker: Map, + @Part fileBuffer1: MultipartBody.Part?, + @Part fileBuffer2: MultipartBody.Part?, + @Part fileBuffer3: MultipartBody.Part? + ): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 1549f93..6e6f1ae 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -7,7 +7,11 @@ import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody +import java.io.File object RetrofitServiceManager { private val api by lazy { @@ -68,6 +72,7 @@ /** * 安装新标识器 + * Multipart上传图片,文件,带多参数上传 */ suspend fun installLabel( companyId: String, @@ -95,7 +100,8 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ): String { val param = JsonObject() param.addProperty("companyId", companyId) @@ -127,6 +133,31 @@ val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return api.installLabel(requestBody) + val res = HashMap() + res["jsonMarker"] = requestBody + + val multiParts = ArrayList() + realPaths.forEachIndexed { index, s -> + val file = File(s) + val fileMultipart = MultipartBody.Part.createFormData( + "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) + ) + multiParts.add(fileMultipart) + } + + return when (multiParts.size) { + 3 -> { + api.installLabel(res, multiParts[0], multiParts[1], multiParts[2]) + } + 2 -> { + api.installLabel(res, multiParts[0], multiParts[1], null) + } + 1 -> { + api.installLabel(res, multiParts[0], null, null) + } + else -> { + api.installLabel(res, null, null, null) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt index 5bb7fbe..e34bbb8 100644 --- a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt @@ -22,16 +22,17 @@ const val USER_NAME = "USER_NAME" const val USER_ID = "USER_ID" const val USER_COMPANY_ID = "USER_COMPANY_ID" + const val OBJECT_ID = "OBJECT_ID" const val SERVER_IP = "SERVER_IP" const val SERVER_PORT = "SERVER_PORT" const val APP_AUTHORITY = "com.casic.detector.fileprovider" val POPUP_TITLES = arrayOf("更新数据", "下载工单", "关于软件", "事件上报", "标识器补全") - var POINT_TYPE_ARRAY = arrayOf("", "管线", "管线附属物", "管线特征管点", "交叉穿越点") + var POINT_TYPE_ARRAY = arrayOf("管线", "管线附属物", "管线特征管点", "交叉穿越点") var SPINNER_ARRAY = arrayOf("标识器ID", "所属区域", "所属线路", "所属道路", "权属单位", "安装部门", "安装时间", "备注") - var PIPE_MATERIAL_ARRAY = arrayOf("", "铸铁", "塑料") - var DOWN_PIPE_TYPE_ARRAY = arrayOf("", "热力", "燃气", "供水", "电力", "通信") - var BURY_METHOD_ARRAY = arrayOf("", "直埋", "圆管", "管块", "管沟", "架空") + var PIPE_MATERIAL_ARRAY = arrayOf("铸铁", "塑料") + var DOWN_PIPE_TYPE_ARRAY = arrayOf("热力", "燃气", "供水", "电力", "通信") + var BURY_METHOD_ARRAY = arrayOf("直埋", "圆管", "管块", "管沟", "架空") var IDENTIFIER_TYPE_ARRAY = arrayOf("EM30", "EM50", "EM14") var COLOR_ARRAY = arrayOf("蓝色", "橙色", "红色", "黑色", "紫色", "黄色", "绿色") } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/BigImageActivity.kt b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt new file mode 100644 index 0000000..ca6c7d7 --- /dev/null +++ b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt @@ -0,0 +1,87 @@ +package com.casic.detector.view + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant +import com.pengxh.kt.lite.utils.ImmerseStatusBarUtil +import kotlinx.android.synthetic.main.activity_big_image.* + +class BigImageActivity : KotlinBaseActivity() { + + override fun initLayoutView(): Int = R.layout.activity_big_image + + override fun setupTopBarLayout() { + ImmerseStatusBarUtil.setColor(this, Color.BLACK) + leftBackView.setOnClickListener { finish() } + } + + override fun initData() { + + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + val index: Int = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + imagePagerView.adapter = BigImageAdapter(this, urls) + imagePagerView.currentItem = index + imagePagerView.offscreenPageLimit = imageSize + imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + pageNumberView.text = String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt index d61bec9..02b455f 100644 --- a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt @@ -1,43 +1,50 @@ package com.casic.detector.view +import android.annotation.SuppressLint +import android.app.DatePickerDialog import android.content.Context +import android.content.Intent +import android.provider.Settings import android.view.View +import androidx.lifecycle.ViewModelProvider import com.amap.api.location.AMapLocation import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback +import com.casic.detector.adapter.EditableImageAdapter +import com.casic.detector.bean.LabelBean import com.casic.detector.callback.ILocationListener import com.casic.detector.callback.OnImageCompressListener import com.casic.detector.callback.OnItemSelectedListener -import com.casic.detector.extensions.compressImage -import com.casic.detector.extensions.initLayoutImmersionBar -import com.casic.detector.extensions.show -import com.casic.detector.extensions.showDatePicker +import com.casic.detector.extensions.* +import com.casic.detector.utils.DataBaseManager +import com.casic.detector.utils.LoadingDialogHub import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity +import com.casic.detector.vm.TaskViewModel import com.gyf.immersionbar.ImmersionBar import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType import com.luck.picture.lib.entity.LocalMedia import com.luck.picture.lib.interfaces.OnResultCallbackListener -import com.pengxh.kt.lite.adapter.EditableImageAdapter import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.extensions.timestampToCompleteDate +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.vm.LoadState +import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog import kotlinx.android.synthetic.main.activity_install_label.* import kotlinx.android.synthetic.main.include_base_title.* import kotlinx.android.synthetic.main.include_install_label_identifier.* import kotlinx.android.synthetic.main.include_install_label_object.* import kotlinx.android.synthetic.main.include_install_label_open_camera.* import java.io.File +import java.util.* +@SuppressLint("SetTextI18n") class InstallLabelActivity : KotlinBaseActivity() { private val kTag = "InstallLabelActivity" private val context: Context = this@InstallLabelActivity + private val calendar by lazy { Calendar.getInstance() } private lateinit var imageAdapter: EditableImageAdapter - private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 private val realPaths: ArrayList = ArrayList() //真实图片路径 private var objectTypeSelectedItem = "" private var materialSelectedItem = "" @@ -46,17 +53,33 @@ private var buryMethodSelectedItem = "" private var identifierTypeSelectedItem = "" private var colorSelectedItem = "" + private lateinit var taskViewModel: TaskViewModel override fun initData() { imageAdapter = EditableImageAdapter(this, 3, 3f) addImageRecyclerView.adapter = imageAdapter + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + //设置默认值 + markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue()) + pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue()) + buryDeepView.setText("buryDeepView".getDefaultValue()) + downPipeDiameterView.setText("downPipeDiameterView".getDefaultValue()) + downPointDeepView.setText("downPointDeepView".getDefaultValue()) + areaView.setText("areaView".getDefaultValue()) + lineView.setText("lineView".getDefaultValue()) + roadView.setText("roadView".getDefaultValue()) + ownerView.setText("ownerView".getDefaultValue()) + identifierDeepView.setText("identifierDeepView".getDefaultValue()) + personDeptView.setText("personDeptView".getDefaultValue()) } override fun initEvent() { leftBackView.setOnClickListener { finish() } /**************************************************************************************/ - objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 1, + objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { objectTypeSelectedItem = default @@ -67,7 +90,7 @@ } }) - materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { materialSelectedItem = default @@ -78,7 +101,7 @@ } }) - downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 1, + downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeSelectedItem = default @@ -89,7 +112,7 @@ } }) - downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeMaterialSelectedItem = default @@ -100,7 +123,7 @@ } }) - buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 1, + buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { buryMethodSelectedItem = default @@ -112,11 +135,15 @@ }) constructDateView.setOnClickListener { - showDatePicker(DateEntity.today(), object : DateSelectedCallback { - override fun onDateSelected(date: String) { - constructDateView.text = date - } - }) + val year = calendar.get(Calendar.YEAR) + val month = calendar.get(Calendar.MONTH) + val day = calendar.get(Calendar.DAY_OF_MONTH) + val datePicker = DatePickerDialog(this, { _, y, m, d -> + constructDateView.text = String.format( + "%s-%s-%s", y, m.appendZero(), d.appendZero() + ) + }, year, month, day) + datePicker.show() } identifierTypeSpinner.show(this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0, @@ -161,16 +188,153 @@ if (realPaths[position].isEmpty()) { "图片加载失败,无法查看大图".show(context) } else { -// context.navigatePageTo(position, realPaths) + context.navigatePageTo(position, realPaths) } } override fun onItemLongClick(view: View?, position: Int) { - imagePaths.removeAt(position) imageAdapter.deleteImage(position) } }) /**************************************************************************************/ + installButton.setOnClickListener { + if (isNetworkConnected()) { + val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + if (markerObjectTypeView.text.isNullOrBlank()) { + when (objectTypeSelectedItem) { + "管线" -> { + "请输入管线种类!".show(this) + } + "管线附属物" -> { + "请输入附属物名称!".show(this) + } + "管线特征管点" -> { + "请输入特征管点!".show(this) + } + "交叉穿越点" -> { + "请输入上层管种类!".show(this) + } + } + return@setOnClickListener + } + + if (pipelineDiameterView.text.isNullOrBlank()) { + "请输入管径".show(this) + return@setOnClickListener + } + + if (buryDeepView.text.isNullOrBlank()) { + "请输入埋深".show(this) + return@setOnClickListener + } + + if (downPipeDiameterView.text.isNullOrBlank()) { + "请输入下层管管径".show(this) + return@setOnClickListener + } + + if (areaView.text.isNullOrBlank()) { + "请输入所属区域".show(this) + return@setOnClickListener + } + + if (lineView.text.isNullOrBlank()) { + "请输入所属线路".show(this) + return@setOnClickListener + } + + if (roadView.text.isNullOrBlank()) { + "请输入所属道路".show(this) + return@setOnClickListener + } + + if (constructDateView.text.isNullOrBlank()) { + "请选择建设年代".show(this) + return@setOnClickListener + } + + if (ownerView.text.isNullOrBlank()) { + "请输入权属单位".show(this) + return@setOnClickListener + } + + if (identifierIdView.text.isNullOrBlank()) { + "请先读取标识器获取ID".show(this) + return@setOnClickListener + } + + if (identifierDeepView.text.isNullOrBlank()) { + "请输入标识器埋深".show(this) + return@setOnClickListener + } + + if (personDeptView.text.isNullOrBlank()) { + "请输入标识器安装部门".show(this) + return@setOnClickListener + } + + taskViewModel.installLabel( + companyId, + objectTypeSelectedItem.toObjectType(), + markerObjectTypeView.text.toString(), + materialSelectedItem, + "${pipelineDiameterView.text}mm", + "${buryDeepView.text}mm", + downPipeSelectedItem, + downPipeMaterialSelectedItem, + "${downPipeDiameterView.text}mm", + "${downPointDeepView.text}mm", + buryMethodSelectedItem, + areaView.text.toString(), + lineView.text.toString(), + roadView.text.toString(), + constructDateView.text.toString(), + ownerView.text.toString(), + objectId, + identifierIdView.text.toString(), + identifierTypeSelectedItem, + "${identifierDeepView.text}mm", + personDeptView.text.toString(), + installTimeView.text.toString(), + lngView.text.toString(), + latView.text.toString(), + colorSelectedItem.toColor(), + remarkView.text.toString(), + realPaths + ) + + //保存默认值 + "markerObjectTypeView".setDefaultValue(markerObjectTypeView.text.toString()) + "pipelineDiameterView".setDefaultValue(pipelineDiameterView.text.toString()) + "buryDeepView".setDefaultValue(buryDeepView.text.toString()) + "downPipeDiameterView".setDefaultValue(downPipeDiameterView.text.toString()) + "downPointDeepView".setDefaultValue(downPointDeepView.text.toString()) + "areaView".setDefaultValue(areaView.text.toString()) + "lineView".setDefaultValue(lineView.text.toString()) + "roadView".setDefaultValue(roadView.text.toString()) + "ownerView".setDefaultValue(ownerView.text.toString()) + "identifierDeepView".setDefaultValue(identifierDeepView.text.toString()) + "personDeptView".setDefaultValue(personDeptView.text.toString()) + } else { + NoNetworkDialog.Builder() + .setContext(context) + .setOnDialogButtonClickListener(object : + NoNetworkDialog.OnDialogButtonClickListener { + override fun onButtonClick() { + val intent = Intent(Settings.ACTION_SETTINGS) + startActivity(intent) + } + }).build().show() + } + } + + //TODO 搜索标识器 + readLabelButton.setOnClickListener { + LoadingDialogHub.show(this, "正在搜索标识器,请稍后...") + identifierIdView.text = "123456789" + LoadingDialogHub.dismiss() + } } private fun takePicture() { @@ -191,11 +355,11 @@ } private fun analyticalSelectResults(result: LocalMedia) { - //压缩图片后上传 + //压缩图片 result.realPath.compressImage(this, object : OnImageCompressListener { override fun onSuccess(file: File) { - //上传图片 -// fileUploadViewModel.uploadFile(file) + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) } override fun onError(e: Throwable) { @@ -207,7 +371,51 @@ override fun initLayoutView(): Int = R.layout.activity_install_label override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...") + LoadState.Success -> { + saveLabelInLocal() + LoadingDialogHub.dismiss() + finish() + } + else -> LoadingDialogHub.dismiss() + } + } + } + //安装成功后将标识器保存在本地 + private fun saveLabelInLocal() { + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + + val labelBean = LabelBean() + labelBean.objectType = objectTypeSelectedItem + labelBean.pipelineType = markerObjectTypeView.text.toString() + labelBean.pipelineMaterial = materialSelectedItem + labelBean.pipelineDiameter = "${pipelineDiameterView.text}mm" + labelBean.buryDeep = "${buryDeepView.text}mm" + labelBean.lowerType = downPipeSelectedItem + labelBean.lowerMaterial = downPipeMaterialSelectedItem + labelBean.lowerDiameter = "${downPipeDiameterView.text}mm" + labelBean.lowerDeep = "${downPointDeepView.text}mm" + labelBean.buryMethod = buryMethodSelectedItem + labelBean.area = areaView.text.toString() + labelBean.line = lineView.text.toString() + labelBean.road = roadView.text.toString() + labelBean.constructTime = constructDateView.text.toString() + labelBean.owner = ownerView.text.toString() + labelBean.objectId = objectId + labelBean.identifierId = identifierIdView.text.toString() + labelBean.identifierType = identifierTypeSelectedItem + labelBean.identifierDeep = "${identifierDeepView.text}mm" + labelBean.person = personDeptView.text.toString() + labelBean.installTime = installTimeView.text.toString() + labelBean.lng = lngView.text.toString() + labelBean.lat = latView.text.toString() + labelBean.color = colorSelectedItem.toColor() + labelBean.remark = remarkView.text.toString() + + DataBaseManager.get.insertTaskLabel(labelBean) } override fun setupTopBarLayout() { diff --git a/app/src/main/java/com/casic/detector/view/MainActivity.kt b/app/src/main/java/com/casic/detector/view/MainActivity.kt index cd06e07..9b791e9 100644 --- a/app/src/main/java/com/casic/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/detector/view/MainActivity.kt @@ -571,7 +571,8 @@ labelBean.lng, labelBean.lat, labelBean.color, - labelBean.remark + labelBean.remark, + arrayListOf() ) } LoadingDialogHub.dismiss() diff --git a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt index 082ee39..82813ff 100644 --- a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt @@ -39,7 +39,7 @@ objectJson, object : TypeToken() {}.type ) - objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt()] + objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt() - 1] pipelineTypeView.text = labelBean.pipelineType pipelineDiameterView.text = labelBean.pipelineDiameter pipelineMaterialView.text = labelBean.pipelineMaterial diff --git a/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt index 845b2b8..2475f0d 100644 --- a/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt @@ -89,8 +89,10 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ) = launch({ + loadState.value = LoadState.Loading val response = RetrofitServiceManager.installLabel( companyId, recordType, @@ -117,16 +119,17 @@ longitude, latitude, colorType, - memo + memo, + realPaths ) if (response.separateResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + loadState.value = LoadState.Success } else { + loadState.value = LoadState.Fail response.toErrorMessage().show(BaseApplication.get()) } }, { + loadState.value = LoadState.Fail it.convertChinese().show(BaseApplication.get()) }) diff --git a/app/src/main/res/layout/activity_big_image.xml b/app/src/main/res/layout/activity_big_image.xml new file mode 100644 index 0000000..9d060f4 --- /dev/null +++ b/app/src/main/res/layout/activity_big_image.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_install_label.xml b/app/src/main/res/layout/activity_install_label.xml index 10dfdc2..e191ec8 100644 --- a/app/src/main/res/layout/activity_install_label.xml +++ b/app/src/main/res/layout/activity_install_label.xml @@ -64,9 +64,11 @@ android:textSize="@dimen/sp_18" /> + android:layout_height="@dimen/dp_100" + android:gravity="top" + android:paddingVertical="@dimen/dp_5" /> diff --git a/app/src/main/res/layout/include_install_label_identifier.xml b/app/src/main/res/layout/include_install_label_identifier.xml index 87f0070..d166fd0 100644 --- a/app/src/main/res/layout/include_install_label_identifier.xml +++ b/app/src/main/res/layout/include_install_label_identifier.xml @@ -37,7 +37,10 @@ style="@style/textViewStyle" android:text="ID号:" /> - + @@ -100,7 +104,9 @@ style="@style/textViewStyle" android:text="部门:" /> - + - + @@ -120,6 +123,7 @@ android:text="埋深:" /> @@ -184,6 +188,7 @@ android:text="下层管直径:" /> @@ -210,6 +215,7 @@ android:text="下层管埋深:" /> @@ -254,7 +260,9 @@ style="@style/textViewStyle" android:text="所属区域:" /> - + - + - + - + \ No newline at end of file diff --git a/app/src/main/res/layout/include_install_label_open_camera.xml b/app/src/main/res/layout/include_install_label_open_camera.xml index 39f3242..2ebfeea 100644 --- a/app/src/main/res/layout/include_install_label_open_camera.xml +++ b/app/src/main/res/layout/include_install_label_open_camera.xml @@ -22,6 +22,15 @@ android:layout_marginHorizontal="@dimen/dp_10" android:text="拍照片" android:textSize="@dimen/sp_18" /> + + + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Int.kt b/app/src/main/java/com/casic/detector/extensions/Int.kt index 10275bb..d67cac8 100644 --- a/app/src/main/java/com/casic/detector/extensions/Int.kt +++ b/app/src/main/java/com/casic/detector/extensions/Int.kt @@ -13,4 +13,12 @@ paint.color = color canvas.drawArc(rectF, 0f, 360f, true, paint) return bitmap +} + +fun Int.appendZero(): String { + return if (this < 10) { + "0$this" + } else { + this.toString() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index 7352dc1..aacd89d 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -45,6 +45,36 @@ } } +fun String.toObjectType(): String { + return if (this == LocaleConstant.POINT_TYPE_ARRAY[0]) { + "1" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[1]) { + "2" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[2]) { + "3" + } else { + "4" + } +} + +fun String.toColor(): String { + return if (this == LocaleConstant.COLOR_ARRAY[0]) { + "0" + } else if (this == LocaleConstant.COLOR_ARRAY[1]) { + "1" + } else if (this == LocaleConstant.COLOR_ARRAY[2]) { + "2" + } else if (this == LocaleConstant.COLOR_ARRAY[3]) { + "3" + } else if (this == LocaleConstant.COLOR_ARRAY[4]) { + "4" + } else if (this == LocaleConstant.COLOR_ARRAY[5]) { + "5" + } else { + "6" + } +} + fun String.compressImage(context: Context, listener: OnImageCompressListener) { Luban.with(context) .load(this) @@ -63,4 +93,14 @@ listener.onError(e) } }).launch() +} + +//根据控件名字存默认值 +fun String.setDefaultValue(value: String) { + SaveKeyValues.putValue(this, value) +} + +//根据控件名字取默认值 +fun String.getDefaultValue(): String { + return SaveKeyValues.getValue(this, "") as String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 6ee3191..9e862aa 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -1,10 +1,8 @@ package com.casic.detector.retrofit +import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query +import retrofit2.http.* interface RetrofitService { /** @@ -56,6 +54,12 @@ /** * 安装新标识器 */ + @Multipart @POST("/ems/marker/save-marker-photo.do") - suspend fun installLabel(@Body requestBody: RequestBody): String + suspend fun installLabel( + @PartMap jsonMarker: Map, + @Part fileBuffer1: MultipartBody.Part?, + @Part fileBuffer2: MultipartBody.Part?, + @Part fileBuffer3: MultipartBody.Part? + ): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 1549f93..6e6f1ae 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -7,7 +7,11 @@ import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody +import java.io.File object RetrofitServiceManager { private val api by lazy { @@ -68,6 +72,7 @@ /** * 安装新标识器 + * Multipart上传图片,文件,带多参数上传 */ suspend fun installLabel( companyId: String, @@ -95,7 +100,8 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ): String { val param = JsonObject() param.addProperty("companyId", companyId) @@ -127,6 +133,31 @@ val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return api.installLabel(requestBody) + val res = HashMap() + res["jsonMarker"] = requestBody + + val multiParts = ArrayList() + realPaths.forEachIndexed { index, s -> + val file = File(s) + val fileMultipart = MultipartBody.Part.createFormData( + "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) + ) + multiParts.add(fileMultipart) + } + + return when (multiParts.size) { + 3 -> { + api.installLabel(res, multiParts[0], multiParts[1], multiParts[2]) + } + 2 -> { + api.installLabel(res, multiParts[0], multiParts[1], null) + } + 1 -> { + api.installLabel(res, multiParts[0], null, null) + } + else -> { + api.installLabel(res, null, null, null) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt index 5bb7fbe..e34bbb8 100644 --- a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt @@ -22,16 +22,17 @@ const val USER_NAME = "USER_NAME" const val USER_ID = "USER_ID" const val USER_COMPANY_ID = "USER_COMPANY_ID" + const val OBJECT_ID = "OBJECT_ID" const val SERVER_IP = "SERVER_IP" const val SERVER_PORT = "SERVER_PORT" const val APP_AUTHORITY = "com.casic.detector.fileprovider" val POPUP_TITLES = arrayOf("更新数据", "下载工单", "关于软件", "事件上报", "标识器补全") - var POINT_TYPE_ARRAY = arrayOf("", "管线", "管线附属物", "管线特征管点", "交叉穿越点") + var POINT_TYPE_ARRAY = arrayOf("管线", "管线附属物", "管线特征管点", "交叉穿越点") var SPINNER_ARRAY = arrayOf("标识器ID", "所属区域", "所属线路", "所属道路", "权属单位", "安装部门", "安装时间", "备注") - var PIPE_MATERIAL_ARRAY = arrayOf("", "铸铁", "塑料") - var DOWN_PIPE_TYPE_ARRAY = arrayOf("", "热力", "燃气", "供水", "电力", "通信") - var BURY_METHOD_ARRAY = arrayOf("", "直埋", "圆管", "管块", "管沟", "架空") + var PIPE_MATERIAL_ARRAY = arrayOf("铸铁", "塑料") + var DOWN_PIPE_TYPE_ARRAY = arrayOf("热力", "燃气", "供水", "电力", "通信") + var BURY_METHOD_ARRAY = arrayOf("直埋", "圆管", "管块", "管沟", "架空") var IDENTIFIER_TYPE_ARRAY = arrayOf("EM30", "EM50", "EM14") var COLOR_ARRAY = arrayOf("蓝色", "橙色", "红色", "黑色", "紫色", "黄色", "绿色") } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/BigImageActivity.kt b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt new file mode 100644 index 0000000..ca6c7d7 --- /dev/null +++ b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt @@ -0,0 +1,87 @@ +package com.casic.detector.view + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant +import com.pengxh.kt.lite.utils.ImmerseStatusBarUtil +import kotlinx.android.synthetic.main.activity_big_image.* + +class BigImageActivity : KotlinBaseActivity() { + + override fun initLayoutView(): Int = R.layout.activity_big_image + + override fun setupTopBarLayout() { + ImmerseStatusBarUtil.setColor(this, Color.BLACK) + leftBackView.setOnClickListener { finish() } + } + + override fun initData() { + + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + val index: Int = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + imagePagerView.adapter = BigImageAdapter(this, urls) + imagePagerView.currentItem = index + imagePagerView.offscreenPageLimit = imageSize + imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + pageNumberView.text = String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt index d61bec9..02b455f 100644 --- a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt @@ -1,43 +1,50 @@ package com.casic.detector.view +import android.annotation.SuppressLint +import android.app.DatePickerDialog import android.content.Context +import android.content.Intent +import android.provider.Settings import android.view.View +import androidx.lifecycle.ViewModelProvider import com.amap.api.location.AMapLocation import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback +import com.casic.detector.adapter.EditableImageAdapter +import com.casic.detector.bean.LabelBean import com.casic.detector.callback.ILocationListener import com.casic.detector.callback.OnImageCompressListener import com.casic.detector.callback.OnItemSelectedListener -import com.casic.detector.extensions.compressImage -import com.casic.detector.extensions.initLayoutImmersionBar -import com.casic.detector.extensions.show -import com.casic.detector.extensions.showDatePicker +import com.casic.detector.extensions.* +import com.casic.detector.utils.DataBaseManager +import com.casic.detector.utils.LoadingDialogHub import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity +import com.casic.detector.vm.TaskViewModel import com.gyf.immersionbar.ImmersionBar import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType import com.luck.picture.lib.entity.LocalMedia import com.luck.picture.lib.interfaces.OnResultCallbackListener -import com.pengxh.kt.lite.adapter.EditableImageAdapter import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.extensions.timestampToCompleteDate +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.vm.LoadState +import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog import kotlinx.android.synthetic.main.activity_install_label.* import kotlinx.android.synthetic.main.include_base_title.* import kotlinx.android.synthetic.main.include_install_label_identifier.* import kotlinx.android.synthetic.main.include_install_label_object.* import kotlinx.android.synthetic.main.include_install_label_open_camera.* import java.io.File +import java.util.* +@SuppressLint("SetTextI18n") class InstallLabelActivity : KotlinBaseActivity() { private val kTag = "InstallLabelActivity" private val context: Context = this@InstallLabelActivity + private val calendar by lazy { Calendar.getInstance() } private lateinit var imageAdapter: EditableImageAdapter - private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 private val realPaths: ArrayList = ArrayList() //真实图片路径 private var objectTypeSelectedItem = "" private var materialSelectedItem = "" @@ -46,17 +53,33 @@ private var buryMethodSelectedItem = "" private var identifierTypeSelectedItem = "" private var colorSelectedItem = "" + private lateinit var taskViewModel: TaskViewModel override fun initData() { imageAdapter = EditableImageAdapter(this, 3, 3f) addImageRecyclerView.adapter = imageAdapter + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + //设置默认值 + markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue()) + pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue()) + buryDeepView.setText("buryDeepView".getDefaultValue()) + downPipeDiameterView.setText("downPipeDiameterView".getDefaultValue()) + downPointDeepView.setText("downPointDeepView".getDefaultValue()) + areaView.setText("areaView".getDefaultValue()) + lineView.setText("lineView".getDefaultValue()) + roadView.setText("roadView".getDefaultValue()) + ownerView.setText("ownerView".getDefaultValue()) + identifierDeepView.setText("identifierDeepView".getDefaultValue()) + personDeptView.setText("personDeptView".getDefaultValue()) } override fun initEvent() { leftBackView.setOnClickListener { finish() } /**************************************************************************************/ - objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 1, + objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { objectTypeSelectedItem = default @@ -67,7 +90,7 @@ } }) - materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { materialSelectedItem = default @@ -78,7 +101,7 @@ } }) - downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 1, + downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeSelectedItem = default @@ -89,7 +112,7 @@ } }) - downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeMaterialSelectedItem = default @@ -100,7 +123,7 @@ } }) - buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 1, + buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { buryMethodSelectedItem = default @@ -112,11 +135,15 @@ }) constructDateView.setOnClickListener { - showDatePicker(DateEntity.today(), object : DateSelectedCallback { - override fun onDateSelected(date: String) { - constructDateView.text = date - } - }) + val year = calendar.get(Calendar.YEAR) + val month = calendar.get(Calendar.MONTH) + val day = calendar.get(Calendar.DAY_OF_MONTH) + val datePicker = DatePickerDialog(this, { _, y, m, d -> + constructDateView.text = String.format( + "%s-%s-%s", y, m.appendZero(), d.appendZero() + ) + }, year, month, day) + datePicker.show() } identifierTypeSpinner.show(this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0, @@ -161,16 +188,153 @@ if (realPaths[position].isEmpty()) { "图片加载失败,无法查看大图".show(context) } else { -// context.navigatePageTo(position, realPaths) + context.navigatePageTo(position, realPaths) } } override fun onItemLongClick(view: View?, position: Int) { - imagePaths.removeAt(position) imageAdapter.deleteImage(position) } }) /**************************************************************************************/ + installButton.setOnClickListener { + if (isNetworkConnected()) { + val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + if (markerObjectTypeView.text.isNullOrBlank()) { + when (objectTypeSelectedItem) { + "管线" -> { + "请输入管线种类!".show(this) + } + "管线附属物" -> { + "请输入附属物名称!".show(this) + } + "管线特征管点" -> { + "请输入特征管点!".show(this) + } + "交叉穿越点" -> { + "请输入上层管种类!".show(this) + } + } + return@setOnClickListener + } + + if (pipelineDiameterView.text.isNullOrBlank()) { + "请输入管径".show(this) + return@setOnClickListener + } + + if (buryDeepView.text.isNullOrBlank()) { + "请输入埋深".show(this) + return@setOnClickListener + } + + if (downPipeDiameterView.text.isNullOrBlank()) { + "请输入下层管管径".show(this) + return@setOnClickListener + } + + if (areaView.text.isNullOrBlank()) { + "请输入所属区域".show(this) + return@setOnClickListener + } + + if (lineView.text.isNullOrBlank()) { + "请输入所属线路".show(this) + return@setOnClickListener + } + + if (roadView.text.isNullOrBlank()) { + "请输入所属道路".show(this) + return@setOnClickListener + } + + if (constructDateView.text.isNullOrBlank()) { + "请选择建设年代".show(this) + return@setOnClickListener + } + + if (ownerView.text.isNullOrBlank()) { + "请输入权属单位".show(this) + return@setOnClickListener + } + + if (identifierIdView.text.isNullOrBlank()) { + "请先读取标识器获取ID".show(this) + return@setOnClickListener + } + + if (identifierDeepView.text.isNullOrBlank()) { + "请输入标识器埋深".show(this) + return@setOnClickListener + } + + if (personDeptView.text.isNullOrBlank()) { + "请输入标识器安装部门".show(this) + return@setOnClickListener + } + + taskViewModel.installLabel( + companyId, + objectTypeSelectedItem.toObjectType(), + markerObjectTypeView.text.toString(), + materialSelectedItem, + "${pipelineDiameterView.text}mm", + "${buryDeepView.text}mm", + downPipeSelectedItem, + downPipeMaterialSelectedItem, + "${downPipeDiameterView.text}mm", + "${downPointDeepView.text}mm", + buryMethodSelectedItem, + areaView.text.toString(), + lineView.text.toString(), + roadView.text.toString(), + constructDateView.text.toString(), + ownerView.text.toString(), + objectId, + identifierIdView.text.toString(), + identifierTypeSelectedItem, + "${identifierDeepView.text}mm", + personDeptView.text.toString(), + installTimeView.text.toString(), + lngView.text.toString(), + latView.text.toString(), + colorSelectedItem.toColor(), + remarkView.text.toString(), + realPaths + ) + + //保存默认值 + "markerObjectTypeView".setDefaultValue(markerObjectTypeView.text.toString()) + "pipelineDiameterView".setDefaultValue(pipelineDiameterView.text.toString()) + "buryDeepView".setDefaultValue(buryDeepView.text.toString()) + "downPipeDiameterView".setDefaultValue(downPipeDiameterView.text.toString()) + "downPointDeepView".setDefaultValue(downPointDeepView.text.toString()) + "areaView".setDefaultValue(areaView.text.toString()) + "lineView".setDefaultValue(lineView.text.toString()) + "roadView".setDefaultValue(roadView.text.toString()) + "ownerView".setDefaultValue(ownerView.text.toString()) + "identifierDeepView".setDefaultValue(identifierDeepView.text.toString()) + "personDeptView".setDefaultValue(personDeptView.text.toString()) + } else { + NoNetworkDialog.Builder() + .setContext(context) + .setOnDialogButtonClickListener(object : + NoNetworkDialog.OnDialogButtonClickListener { + override fun onButtonClick() { + val intent = Intent(Settings.ACTION_SETTINGS) + startActivity(intent) + } + }).build().show() + } + } + + //TODO 搜索标识器 + readLabelButton.setOnClickListener { + LoadingDialogHub.show(this, "正在搜索标识器,请稍后...") + identifierIdView.text = "123456789" + LoadingDialogHub.dismiss() + } } private fun takePicture() { @@ -191,11 +355,11 @@ } private fun analyticalSelectResults(result: LocalMedia) { - //压缩图片后上传 + //压缩图片 result.realPath.compressImage(this, object : OnImageCompressListener { override fun onSuccess(file: File) { - //上传图片 -// fileUploadViewModel.uploadFile(file) + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) } override fun onError(e: Throwable) { @@ -207,7 +371,51 @@ override fun initLayoutView(): Int = R.layout.activity_install_label override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...") + LoadState.Success -> { + saveLabelInLocal() + LoadingDialogHub.dismiss() + finish() + } + else -> LoadingDialogHub.dismiss() + } + } + } + //安装成功后将标识器保存在本地 + private fun saveLabelInLocal() { + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + + val labelBean = LabelBean() + labelBean.objectType = objectTypeSelectedItem + labelBean.pipelineType = markerObjectTypeView.text.toString() + labelBean.pipelineMaterial = materialSelectedItem + labelBean.pipelineDiameter = "${pipelineDiameterView.text}mm" + labelBean.buryDeep = "${buryDeepView.text}mm" + labelBean.lowerType = downPipeSelectedItem + labelBean.lowerMaterial = downPipeMaterialSelectedItem + labelBean.lowerDiameter = "${downPipeDiameterView.text}mm" + labelBean.lowerDeep = "${downPointDeepView.text}mm" + labelBean.buryMethod = buryMethodSelectedItem + labelBean.area = areaView.text.toString() + labelBean.line = lineView.text.toString() + labelBean.road = roadView.text.toString() + labelBean.constructTime = constructDateView.text.toString() + labelBean.owner = ownerView.text.toString() + labelBean.objectId = objectId + labelBean.identifierId = identifierIdView.text.toString() + labelBean.identifierType = identifierTypeSelectedItem + labelBean.identifierDeep = "${identifierDeepView.text}mm" + labelBean.person = personDeptView.text.toString() + labelBean.installTime = installTimeView.text.toString() + labelBean.lng = lngView.text.toString() + labelBean.lat = latView.text.toString() + labelBean.color = colorSelectedItem.toColor() + labelBean.remark = remarkView.text.toString() + + DataBaseManager.get.insertTaskLabel(labelBean) } override fun setupTopBarLayout() { diff --git a/app/src/main/java/com/casic/detector/view/MainActivity.kt b/app/src/main/java/com/casic/detector/view/MainActivity.kt index cd06e07..9b791e9 100644 --- a/app/src/main/java/com/casic/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/detector/view/MainActivity.kt @@ -571,7 +571,8 @@ labelBean.lng, labelBean.lat, labelBean.color, - labelBean.remark + labelBean.remark, + arrayListOf() ) } LoadingDialogHub.dismiss() diff --git a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt index 082ee39..82813ff 100644 --- a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt @@ -39,7 +39,7 @@ objectJson, object : TypeToken() {}.type ) - objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt()] + objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt() - 1] pipelineTypeView.text = labelBean.pipelineType pipelineDiameterView.text = labelBean.pipelineDiameter pipelineMaterialView.text = labelBean.pipelineMaterial diff --git a/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt index 845b2b8..2475f0d 100644 --- a/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt @@ -89,8 +89,10 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ) = launch({ + loadState.value = LoadState.Loading val response = RetrofitServiceManager.installLabel( companyId, recordType, @@ -117,16 +119,17 @@ longitude, latitude, colorType, - memo + memo, + realPaths ) if (response.separateResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + loadState.value = LoadState.Success } else { + loadState.value = LoadState.Fail response.toErrorMessage().show(BaseApplication.get()) } }, { + loadState.value = LoadState.Fail it.convertChinese().show(BaseApplication.get()) }) diff --git a/app/src/main/res/layout/activity_big_image.xml b/app/src/main/res/layout/activity_big_image.xml new file mode 100644 index 0000000..9d060f4 --- /dev/null +++ b/app/src/main/res/layout/activity_big_image.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_install_label.xml b/app/src/main/res/layout/activity_install_label.xml index 10dfdc2..e191ec8 100644 --- a/app/src/main/res/layout/activity_install_label.xml +++ b/app/src/main/res/layout/activity_install_label.xml @@ -64,9 +64,11 @@ android:textSize="@dimen/sp_18" /> + android:layout_height="@dimen/dp_100" + android:gravity="top" + android:paddingVertical="@dimen/dp_5" /> diff --git a/app/src/main/res/layout/include_install_label_identifier.xml b/app/src/main/res/layout/include_install_label_identifier.xml index 87f0070..d166fd0 100644 --- a/app/src/main/res/layout/include_install_label_identifier.xml +++ b/app/src/main/res/layout/include_install_label_identifier.xml @@ -37,7 +37,10 @@ style="@style/textViewStyle" android:text="ID号:" /> - + @@ -100,7 +104,9 @@ style="@style/textViewStyle" android:text="部门:" /> - + - + @@ -120,6 +123,7 @@ android:text="埋深:" /> @@ -184,6 +188,7 @@ android:text="下层管直径:" /> @@ -210,6 +215,7 @@ android:text="下层管埋深:" /> @@ -254,7 +260,9 @@ style="@style/textViewStyle" android:text="所属区域:" /> - + - + - + - + \ No newline at end of file diff --git a/app/src/main/res/layout/include_install_label_open_camera.xml b/app/src/main/res/layout/include_install_label_open_camera.xml index 39f3242..2ebfeea 100644 --- a/app/src/main/res/layout/include_install_label_open_camera.xml +++ b/app/src/main/res/layout/include_install_label_open_camera.xml @@ -22,6 +22,15 @@ android:layout_marginHorizontal="@dimen/dp_10" android:text="拍照片" android:textSize="@dimen/sp_18" /> + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Int.kt b/app/src/main/java/com/casic/detector/extensions/Int.kt index 10275bb..d67cac8 100644 --- a/app/src/main/java/com/casic/detector/extensions/Int.kt +++ b/app/src/main/java/com/casic/detector/extensions/Int.kt @@ -13,4 +13,12 @@ paint.color = color canvas.drawArc(rectF, 0f, 360f, true, paint) return bitmap +} + +fun Int.appendZero(): String { + return if (this < 10) { + "0$this" + } else { + this.toString() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index 7352dc1..aacd89d 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -45,6 +45,36 @@ } } +fun String.toObjectType(): String { + return if (this == LocaleConstant.POINT_TYPE_ARRAY[0]) { + "1" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[1]) { + "2" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[2]) { + "3" + } else { + "4" + } +} + +fun String.toColor(): String { + return if (this == LocaleConstant.COLOR_ARRAY[0]) { + "0" + } else if (this == LocaleConstant.COLOR_ARRAY[1]) { + "1" + } else if (this == LocaleConstant.COLOR_ARRAY[2]) { + "2" + } else if (this == LocaleConstant.COLOR_ARRAY[3]) { + "3" + } else if (this == LocaleConstant.COLOR_ARRAY[4]) { + "4" + } else if (this == LocaleConstant.COLOR_ARRAY[5]) { + "5" + } else { + "6" + } +} + fun String.compressImage(context: Context, listener: OnImageCompressListener) { Luban.with(context) .load(this) @@ -63,4 +93,14 @@ listener.onError(e) } }).launch() +} + +//根据控件名字存默认值 +fun String.setDefaultValue(value: String) { + SaveKeyValues.putValue(this, value) +} + +//根据控件名字取默认值 +fun String.getDefaultValue(): String { + return SaveKeyValues.getValue(this, "") as String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 6ee3191..9e862aa 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -1,10 +1,8 @@ package com.casic.detector.retrofit +import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query +import retrofit2.http.* interface RetrofitService { /** @@ -56,6 +54,12 @@ /** * 安装新标识器 */ + @Multipart @POST("/ems/marker/save-marker-photo.do") - suspend fun installLabel(@Body requestBody: RequestBody): String + suspend fun installLabel( + @PartMap jsonMarker: Map, + @Part fileBuffer1: MultipartBody.Part?, + @Part fileBuffer2: MultipartBody.Part?, + @Part fileBuffer3: MultipartBody.Part? + ): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 1549f93..6e6f1ae 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -7,7 +7,11 @@ import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody +import java.io.File object RetrofitServiceManager { private val api by lazy { @@ -68,6 +72,7 @@ /** * 安装新标识器 + * Multipart上传图片,文件,带多参数上传 */ suspend fun installLabel( companyId: String, @@ -95,7 +100,8 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ): String { val param = JsonObject() param.addProperty("companyId", companyId) @@ -127,6 +133,31 @@ val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return api.installLabel(requestBody) + val res = HashMap() + res["jsonMarker"] = requestBody + + val multiParts = ArrayList() + realPaths.forEachIndexed { index, s -> + val file = File(s) + val fileMultipart = MultipartBody.Part.createFormData( + "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) + ) + multiParts.add(fileMultipart) + } + + return when (multiParts.size) { + 3 -> { + api.installLabel(res, multiParts[0], multiParts[1], multiParts[2]) + } + 2 -> { + api.installLabel(res, multiParts[0], multiParts[1], null) + } + 1 -> { + api.installLabel(res, multiParts[0], null, null) + } + else -> { + api.installLabel(res, null, null, null) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt index 5bb7fbe..e34bbb8 100644 --- a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt @@ -22,16 +22,17 @@ const val USER_NAME = "USER_NAME" const val USER_ID = "USER_ID" const val USER_COMPANY_ID = "USER_COMPANY_ID" + const val OBJECT_ID = "OBJECT_ID" const val SERVER_IP = "SERVER_IP" const val SERVER_PORT = "SERVER_PORT" const val APP_AUTHORITY = "com.casic.detector.fileprovider" val POPUP_TITLES = arrayOf("更新数据", "下载工单", "关于软件", "事件上报", "标识器补全") - var POINT_TYPE_ARRAY = arrayOf("", "管线", "管线附属物", "管线特征管点", "交叉穿越点") + var POINT_TYPE_ARRAY = arrayOf("管线", "管线附属物", "管线特征管点", "交叉穿越点") var SPINNER_ARRAY = arrayOf("标识器ID", "所属区域", "所属线路", "所属道路", "权属单位", "安装部门", "安装时间", "备注") - var PIPE_MATERIAL_ARRAY = arrayOf("", "铸铁", "塑料") - var DOWN_PIPE_TYPE_ARRAY = arrayOf("", "热力", "燃气", "供水", "电力", "通信") - var BURY_METHOD_ARRAY = arrayOf("", "直埋", "圆管", "管块", "管沟", "架空") + var PIPE_MATERIAL_ARRAY = arrayOf("铸铁", "塑料") + var DOWN_PIPE_TYPE_ARRAY = arrayOf("热力", "燃气", "供水", "电力", "通信") + var BURY_METHOD_ARRAY = arrayOf("直埋", "圆管", "管块", "管沟", "架空") var IDENTIFIER_TYPE_ARRAY = arrayOf("EM30", "EM50", "EM14") var COLOR_ARRAY = arrayOf("蓝色", "橙色", "红色", "黑色", "紫色", "黄色", "绿色") } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/BigImageActivity.kt b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt new file mode 100644 index 0000000..ca6c7d7 --- /dev/null +++ b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt @@ -0,0 +1,87 @@ +package com.casic.detector.view + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant +import com.pengxh.kt.lite.utils.ImmerseStatusBarUtil +import kotlinx.android.synthetic.main.activity_big_image.* + +class BigImageActivity : KotlinBaseActivity() { + + override fun initLayoutView(): Int = R.layout.activity_big_image + + override fun setupTopBarLayout() { + ImmerseStatusBarUtil.setColor(this, Color.BLACK) + leftBackView.setOnClickListener { finish() } + } + + override fun initData() { + + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + val index: Int = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + imagePagerView.adapter = BigImageAdapter(this, urls) + imagePagerView.currentItem = index + imagePagerView.offscreenPageLimit = imageSize + imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + pageNumberView.text = String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt index d61bec9..02b455f 100644 --- a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt @@ -1,43 +1,50 @@ package com.casic.detector.view +import android.annotation.SuppressLint +import android.app.DatePickerDialog import android.content.Context +import android.content.Intent +import android.provider.Settings import android.view.View +import androidx.lifecycle.ViewModelProvider import com.amap.api.location.AMapLocation import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback +import com.casic.detector.adapter.EditableImageAdapter +import com.casic.detector.bean.LabelBean import com.casic.detector.callback.ILocationListener import com.casic.detector.callback.OnImageCompressListener import com.casic.detector.callback.OnItemSelectedListener -import com.casic.detector.extensions.compressImage -import com.casic.detector.extensions.initLayoutImmersionBar -import com.casic.detector.extensions.show -import com.casic.detector.extensions.showDatePicker +import com.casic.detector.extensions.* +import com.casic.detector.utils.DataBaseManager +import com.casic.detector.utils.LoadingDialogHub import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity +import com.casic.detector.vm.TaskViewModel import com.gyf.immersionbar.ImmersionBar import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType import com.luck.picture.lib.entity.LocalMedia import com.luck.picture.lib.interfaces.OnResultCallbackListener -import com.pengxh.kt.lite.adapter.EditableImageAdapter import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.extensions.timestampToCompleteDate +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.vm.LoadState +import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog import kotlinx.android.synthetic.main.activity_install_label.* import kotlinx.android.synthetic.main.include_base_title.* import kotlinx.android.synthetic.main.include_install_label_identifier.* import kotlinx.android.synthetic.main.include_install_label_object.* import kotlinx.android.synthetic.main.include_install_label_open_camera.* import java.io.File +import java.util.* +@SuppressLint("SetTextI18n") class InstallLabelActivity : KotlinBaseActivity() { private val kTag = "InstallLabelActivity" private val context: Context = this@InstallLabelActivity + private val calendar by lazy { Calendar.getInstance() } private lateinit var imageAdapter: EditableImageAdapter - private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 private val realPaths: ArrayList = ArrayList() //真实图片路径 private var objectTypeSelectedItem = "" private var materialSelectedItem = "" @@ -46,17 +53,33 @@ private var buryMethodSelectedItem = "" private var identifierTypeSelectedItem = "" private var colorSelectedItem = "" + private lateinit var taskViewModel: TaskViewModel override fun initData() { imageAdapter = EditableImageAdapter(this, 3, 3f) addImageRecyclerView.adapter = imageAdapter + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + //设置默认值 + markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue()) + pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue()) + buryDeepView.setText("buryDeepView".getDefaultValue()) + downPipeDiameterView.setText("downPipeDiameterView".getDefaultValue()) + downPointDeepView.setText("downPointDeepView".getDefaultValue()) + areaView.setText("areaView".getDefaultValue()) + lineView.setText("lineView".getDefaultValue()) + roadView.setText("roadView".getDefaultValue()) + ownerView.setText("ownerView".getDefaultValue()) + identifierDeepView.setText("identifierDeepView".getDefaultValue()) + personDeptView.setText("personDeptView".getDefaultValue()) } override fun initEvent() { leftBackView.setOnClickListener { finish() } /**************************************************************************************/ - objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 1, + objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { objectTypeSelectedItem = default @@ -67,7 +90,7 @@ } }) - materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { materialSelectedItem = default @@ -78,7 +101,7 @@ } }) - downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 1, + downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeSelectedItem = default @@ -89,7 +112,7 @@ } }) - downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeMaterialSelectedItem = default @@ -100,7 +123,7 @@ } }) - buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 1, + buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { buryMethodSelectedItem = default @@ -112,11 +135,15 @@ }) constructDateView.setOnClickListener { - showDatePicker(DateEntity.today(), object : DateSelectedCallback { - override fun onDateSelected(date: String) { - constructDateView.text = date - } - }) + val year = calendar.get(Calendar.YEAR) + val month = calendar.get(Calendar.MONTH) + val day = calendar.get(Calendar.DAY_OF_MONTH) + val datePicker = DatePickerDialog(this, { _, y, m, d -> + constructDateView.text = String.format( + "%s-%s-%s", y, m.appendZero(), d.appendZero() + ) + }, year, month, day) + datePicker.show() } identifierTypeSpinner.show(this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0, @@ -161,16 +188,153 @@ if (realPaths[position].isEmpty()) { "图片加载失败,无法查看大图".show(context) } else { -// context.navigatePageTo(position, realPaths) + context.navigatePageTo(position, realPaths) } } override fun onItemLongClick(view: View?, position: Int) { - imagePaths.removeAt(position) imageAdapter.deleteImage(position) } }) /**************************************************************************************/ + installButton.setOnClickListener { + if (isNetworkConnected()) { + val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + if (markerObjectTypeView.text.isNullOrBlank()) { + when (objectTypeSelectedItem) { + "管线" -> { + "请输入管线种类!".show(this) + } + "管线附属物" -> { + "请输入附属物名称!".show(this) + } + "管线特征管点" -> { + "请输入特征管点!".show(this) + } + "交叉穿越点" -> { + "请输入上层管种类!".show(this) + } + } + return@setOnClickListener + } + + if (pipelineDiameterView.text.isNullOrBlank()) { + "请输入管径".show(this) + return@setOnClickListener + } + + if (buryDeepView.text.isNullOrBlank()) { + "请输入埋深".show(this) + return@setOnClickListener + } + + if (downPipeDiameterView.text.isNullOrBlank()) { + "请输入下层管管径".show(this) + return@setOnClickListener + } + + if (areaView.text.isNullOrBlank()) { + "请输入所属区域".show(this) + return@setOnClickListener + } + + if (lineView.text.isNullOrBlank()) { + "请输入所属线路".show(this) + return@setOnClickListener + } + + if (roadView.text.isNullOrBlank()) { + "请输入所属道路".show(this) + return@setOnClickListener + } + + if (constructDateView.text.isNullOrBlank()) { + "请选择建设年代".show(this) + return@setOnClickListener + } + + if (ownerView.text.isNullOrBlank()) { + "请输入权属单位".show(this) + return@setOnClickListener + } + + if (identifierIdView.text.isNullOrBlank()) { + "请先读取标识器获取ID".show(this) + return@setOnClickListener + } + + if (identifierDeepView.text.isNullOrBlank()) { + "请输入标识器埋深".show(this) + return@setOnClickListener + } + + if (personDeptView.text.isNullOrBlank()) { + "请输入标识器安装部门".show(this) + return@setOnClickListener + } + + taskViewModel.installLabel( + companyId, + objectTypeSelectedItem.toObjectType(), + markerObjectTypeView.text.toString(), + materialSelectedItem, + "${pipelineDiameterView.text}mm", + "${buryDeepView.text}mm", + downPipeSelectedItem, + downPipeMaterialSelectedItem, + "${downPipeDiameterView.text}mm", + "${downPointDeepView.text}mm", + buryMethodSelectedItem, + areaView.text.toString(), + lineView.text.toString(), + roadView.text.toString(), + constructDateView.text.toString(), + ownerView.text.toString(), + objectId, + identifierIdView.text.toString(), + identifierTypeSelectedItem, + "${identifierDeepView.text}mm", + personDeptView.text.toString(), + installTimeView.text.toString(), + lngView.text.toString(), + latView.text.toString(), + colorSelectedItem.toColor(), + remarkView.text.toString(), + realPaths + ) + + //保存默认值 + "markerObjectTypeView".setDefaultValue(markerObjectTypeView.text.toString()) + "pipelineDiameterView".setDefaultValue(pipelineDiameterView.text.toString()) + "buryDeepView".setDefaultValue(buryDeepView.text.toString()) + "downPipeDiameterView".setDefaultValue(downPipeDiameterView.text.toString()) + "downPointDeepView".setDefaultValue(downPointDeepView.text.toString()) + "areaView".setDefaultValue(areaView.text.toString()) + "lineView".setDefaultValue(lineView.text.toString()) + "roadView".setDefaultValue(roadView.text.toString()) + "ownerView".setDefaultValue(ownerView.text.toString()) + "identifierDeepView".setDefaultValue(identifierDeepView.text.toString()) + "personDeptView".setDefaultValue(personDeptView.text.toString()) + } else { + NoNetworkDialog.Builder() + .setContext(context) + .setOnDialogButtonClickListener(object : + NoNetworkDialog.OnDialogButtonClickListener { + override fun onButtonClick() { + val intent = Intent(Settings.ACTION_SETTINGS) + startActivity(intent) + } + }).build().show() + } + } + + //TODO 搜索标识器 + readLabelButton.setOnClickListener { + LoadingDialogHub.show(this, "正在搜索标识器,请稍后...") + identifierIdView.text = "123456789" + LoadingDialogHub.dismiss() + } } private fun takePicture() { @@ -191,11 +355,11 @@ } private fun analyticalSelectResults(result: LocalMedia) { - //压缩图片后上传 + //压缩图片 result.realPath.compressImage(this, object : OnImageCompressListener { override fun onSuccess(file: File) { - //上传图片 -// fileUploadViewModel.uploadFile(file) + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) } override fun onError(e: Throwable) { @@ -207,7 +371,51 @@ override fun initLayoutView(): Int = R.layout.activity_install_label override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...") + LoadState.Success -> { + saveLabelInLocal() + LoadingDialogHub.dismiss() + finish() + } + else -> LoadingDialogHub.dismiss() + } + } + } + //安装成功后将标识器保存在本地 + private fun saveLabelInLocal() { + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + + val labelBean = LabelBean() + labelBean.objectType = objectTypeSelectedItem + labelBean.pipelineType = markerObjectTypeView.text.toString() + labelBean.pipelineMaterial = materialSelectedItem + labelBean.pipelineDiameter = "${pipelineDiameterView.text}mm" + labelBean.buryDeep = "${buryDeepView.text}mm" + labelBean.lowerType = downPipeSelectedItem + labelBean.lowerMaterial = downPipeMaterialSelectedItem + labelBean.lowerDiameter = "${downPipeDiameterView.text}mm" + labelBean.lowerDeep = "${downPointDeepView.text}mm" + labelBean.buryMethod = buryMethodSelectedItem + labelBean.area = areaView.text.toString() + labelBean.line = lineView.text.toString() + labelBean.road = roadView.text.toString() + labelBean.constructTime = constructDateView.text.toString() + labelBean.owner = ownerView.text.toString() + labelBean.objectId = objectId + labelBean.identifierId = identifierIdView.text.toString() + labelBean.identifierType = identifierTypeSelectedItem + labelBean.identifierDeep = "${identifierDeepView.text}mm" + labelBean.person = personDeptView.text.toString() + labelBean.installTime = installTimeView.text.toString() + labelBean.lng = lngView.text.toString() + labelBean.lat = latView.text.toString() + labelBean.color = colorSelectedItem.toColor() + labelBean.remark = remarkView.text.toString() + + DataBaseManager.get.insertTaskLabel(labelBean) } override fun setupTopBarLayout() { diff --git a/app/src/main/java/com/casic/detector/view/MainActivity.kt b/app/src/main/java/com/casic/detector/view/MainActivity.kt index cd06e07..9b791e9 100644 --- a/app/src/main/java/com/casic/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/detector/view/MainActivity.kt @@ -571,7 +571,8 @@ labelBean.lng, labelBean.lat, labelBean.color, - labelBean.remark + labelBean.remark, + arrayListOf() ) } LoadingDialogHub.dismiss() diff --git a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt index 082ee39..82813ff 100644 --- a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt @@ -39,7 +39,7 @@ objectJson, object : TypeToken() {}.type ) - objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt()] + objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt() - 1] pipelineTypeView.text = labelBean.pipelineType pipelineDiameterView.text = labelBean.pipelineDiameter pipelineMaterialView.text = labelBean.pipelineMaterial diff --git a/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt index 845b2b8..2475f0d 100644 --- a/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt @@ -89,8 +89,10 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ) = launch({ + loadState.value = LoadState.Loading val response = RetrofitServiceManager.installLabel( companyId, recordType, @@ -117,16 +119,17 @@ longitude, latitude, colorType, - memo + memo, + realPaths ) if (response.separateResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + loadState.value = LoadState.Success } else { + loadState.value = LoadState.Fail response.toErrorMessage().show(BaseApplication.get()) } }, { + loadState.value = LoadState.Fail it.convertChinese().show(BaseApplication.get()) }) diff --git a/app/src/main/res/layout/activity_big_image.xml b/app/src/main/res/layout/activity_big_image.xml new file mode 100644 index 0000000..9d060f4 --- /dev/null +++ b/app/src/main/res/layout/activity_big_image.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_install_label.xml b/app/src/main/res/layout/activity_install_label.xml index 10dfdc2..e191ec8 100644 --- a/app/src/main/res/layout/activity_install_label.xml +++ b/app/src/main/res/layout/activity_install_label.xml @@ -64,9 +64,11 @@ android:textSize="@dimen/sp_18" /> + android:layout_height="@dimen/dp_100" + android:gravity="top" + android:paddingVertical="@dimen/dp_5" /> diff --git a/app/src/main/res/layout/include_install_label_identifier.xml b/app/src/main/res/layout/include_install_label_identifier.xml index 87f0070..d166fd0 100644 --- a/app/src/main/res/layout/include_install_label_identifier.xml +++ b/app/src/main/res/layout/include_install_label_identifier.xml @@ -37,7 +37,10 @@ style="@style/textViewStyle" android:text="ID号:" /> - + @@ -100,7 +104,9 @@ style="@style/textViewStyle" android:text="部门:" /> - + - + @@ -120,6 +123,7 @@ android:text="埋深:" /> @@ -184,6 +188,7 @@ android:text="下层管直径:" /> @@ -210,6 +215,7 @@ android:text="下层管埋深:" /> @@ -254,7 +260,9 @@ style="@style/textViewStyle" android:text="所属区域:" /> - + - + - + - + \ No newline at end of file diff --git a/app/src/main/res/layout/include_install_label_open_camera.xml b/app/src/main/res/layout/include_install_label_open_camera.xml index 39f3242..2ebfeea 100644 --- a/app/src/main/res/layout/include_install_label_open_camera.xml +++ b/app/src/main/res/layout/include_install_label_open_camera.xml @@ -22,6 +22,15 @@ android:layout_marginHorizontal="@dimen/dp_10" android:text="拍照片" android:textSize="@dimen/sp_18" /> + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_editable_rv_g.xml b/app/src/main/res/layout/item_editable_rv_g.xml new file mode 100644 index 0000000..8d0fc20 --- /dev/null +++ b/app/src/main/res/layout/item_editable_rv_g.xml @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3ad10f9..ef50c2a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,4 @@ implementation 'io.github.lucksiege:pictureselector:v3.0.4' //图片压缩 implementation 'top.zibin:Luban:1.1.8' - //单项/数字、二三级联动、日期/时间等滚轮选择器 - implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:4.1.11' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 13af612..de6ab8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,7 @@ + diff --git a/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt new file mode 100644 index 0000000..6f694dd --- /dev/null +++ b/app/src/main/java/com/casic/detector/adapter/EditableImageAdapter.kt @@ -0,0 +1,111 @@ +package com.casic.detector.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.pengxh.kt.lite.adapter.ViewHolder +import com.pengxh.kt.lite.extensions.dp2px +import com.pengxh.kt.lite.extensions.getScreenWidth + + +/** + * 数量可编辑图片适配器 + * + * @param imageCountLimit 最多显示几张图片,每行3张图片 + * @param spacing 上下左右外边距,无需在 [androidx.recyclerview.widget.RecyclerView] 设置边距 + * */ +class EditableImageAdapter( + private val context: Context, private val imageCountLimit: Int, private val spacing: Float +) : RecyclerView.Adapter() { + + private val layoutInflater by lazy { LayoutInflater.from(context) } + private val screenWidth by lazy { context.getScreenWidth() } + private var images: MutableList = ArrayList() + + fun setupImage(images: MutableList) { + this.images = images + notifyItemRangeChanged(0, images.size) + } + + fun deleteImage(position: Int) { + if (images.isNotEmpty()) { + images.removeAt(position) + /** + * 发生变化的item数目 + * */ + notifyItemRangeRemoved(position, 1) + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return ViewHolder( + layoutInflater.inflate(R.layout.item_editable_rv_g, parent, false) + ) + } + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val imageView = holder.getView(R.id.imageView) + configImageParams(imageView, holder.bindingAdapterPosition) + if (position == itemCount - 1 && images.size < imageCountLimit) { + imageView.setImageResource(R.mipmap.photo6) + imageView.setOnClickListener { //添加图片 + itemClickListener?.onAddImageClick() + } + } else { + Glide.with(context).load(images[position]).into(imageView) + imageView.setOnClickListener { // 点击操作,查看大图 + itemClickListener?.onItemClick(holder.bindingAdapterPosition) + } + // 长按监听 + imageView.setOnLongClickListener { v -> //长按删除 + itemClickListener?.onItemLongClick(v, holder.bindingAdapterPosition) + true + } + } + } + + private fun configImageParams(imageView: ImageView, position: Int) { + val temp = spacing.dp2px(context) + val imageSize = (screenWidth - temp * 3) / 3 + + val params = LinearLayout.LayoutParams(imageSize, imageSize) + when (position) { + 0 -> params.setMargins(temp, temp, temp shr 1, temp shr 1) + 1 -> params.setMargins(temp shr 1, temp, temp shr 1, temp shr 1) + 2 -> params.setMargins(temp shr 1, temp, temp, temp shr 1) + 3 -> params.setMargins(temp, temp shr 1, temp shr 1, temp shr 1) + 4 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp shr 1) + 5 -> params.setMargins(temp shr 1, temp shr 1, temp, temp shr 1) + 6 -> params.setMargins(temp, temp shr 1, temp shr 1, temp) + 7 -> params.setMargins(temp shr 1, temp shr 1, temp shr 1, temp) + 8 -> params.setMargins(temp shr 1, temp shr 1, temp, temp) + } + imageView.layoutParams = params + } + + override fun getItemCount(): Int = if (images.size >= imageCountLimit) { + imageCountLimit + } else { + images.size + 1 + } + + private var itemClickListener: OnItemClickListener? = null + + fun setOnItemClickListener(itemClickListener: OnItemClickListener?) { + this.itemClickListener = itemClickListener + } + + interface OnItemClickListener { + fun onAddImageClick() + + fun onItemClick(position: Int) + + fun onItemLongClick(view: View?, position: Int) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt b/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt deleted file mode 100644 index 731c02b..0000000 --- a/app/src/main/java/com/casic/detector/callback/DateSelectedCallback.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.casic.detector.callback - -interface DateSelectedCallback { - fun onDateSelected(date: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Activity.kt b/app/src/main/java/com/casic/detector/extensions/Activity.kt deleted file mode 100644 index e2027d8..0000000 --- a/app/src/main/java/com/casic/detector/extensions/Activity.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.casic.detector.extensions - -import android.app.Activity -import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback -import com.github.gzuliyujiang.wheelpicker.DatePicker -import com.github.gzuliyujiang.wheelpicker.annotation.DateMode -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.sp2px - -fun Activity.showDatePicker(start: DateEntity, callback: DateSelectedCallback) { - val datePicker = DatePicker(this) - - val layout = datePicker.wheelLayout - layout.setDateMode(DateMode.YEAR_MONTH_DAY) - layout.setDateLabel("年", "月", "日") - layout.setTextSize(14f.sp2px(this).toFloat()) - layout.setSelectedTextSize(16f.sp2px(this).toFloat()) - layout.setSelectedTextColor(R.color.themeColor.convertColor(this)) - layout.setSelectedTextBold(true) - layout.setResetWhenLinkage(false) - layout.setRange( - start, - DateEntity.target(2050, 12, 31), - DateEntity.today() - ) - - datePicker.setOnDatePickedListener { year, month, day -> - val m = if (month < 10) { - "0${month}" - } else { - month - } - val d = if (day < 10) { - "0${day}" - } else { - day - } - callback.onDateSelected(String.format("%s-%s-%s", year, m, d)) - } - datePicker.show() -} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/Int.kt b/app/src/main/java/com/casic/detector/extensions/Int.kt index 10275bb..d67cac8 100644 --- a/app/src/main/java/com/casic/detector/extensions/Int.kt +++ b/app/src/main/java/com/casic/detector/extensions/Int.kt @@ -13,4 +13,12 @@ paint.color = color canvas.drawArc(rectF, 0f, 360f, true, paint) return bitmap +} + +fun Int.appendZero(): String { + return if (this < 10) { + "0$this" + } else { + this.toString() + } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/extensions/String.kt b/app/src/main/java/com/casic/detector/extensions/String.kt index 7352dc1..aacd89d 100644 --- a/app/src/main/java/com/casic/detector/extensions/String.kt +++ b/app/src/main/java/com/casic/detector/extensions/String.kt @@ -45,6 +45,36 @@ } } +fun String.toObjectType(): String { + return if (this == LocaleConstant.POINT_TYPE_ARRAY[0]) { + "1" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[1]) { + "2" + } else if (this == LocaleConstant.POINT_TYPE_ARRAY[2]) { + "3" + } else { + "4" + } +} + +fun String.toColor(): String { + return if (this == LocaleConstant.COLOR_ARRAY[0]) { + "0" + } else if (this == LocaleConstant.COLOR_ARRAY[1]) { + "1" + } else if (this == LocaleConstant.COLOR_ARRAY[2]) { + "2" + } else if (this == LocaleConstant.COLOR_ARRAY[3]) { + "3" + } else if (this == LocaleConstant.COLOR_ARRAY[4]) { + "4" + } else if (this == LocaleConstant.COLOR_ARRAY[5]) { + "5" + } else { + "6" + } +} + fun String.compressImage(context: Context, listener: OnImageCompressListener) { Luban.with(context) .load(this) @@ -63,4 +93,14 @@ listener.onError(e) } }).launch() +} + +//根据控件名字存默认值 +fun String.setDefaultValue(value: String) { + SaveKeyValues.putValue(this, value) +} + +//根据控件名字取默认值 +fun String.getDefaultValue(): String { + return SaveKeyValues.getValue(this, "") as String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt index 6ee3191..9e862aa 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitService.kt @@ -1,10 +1,8 @@ package com.casic.detector.retrofit +import okhttp3.MultipartBody import okhttp3.RequestBody -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query +import retrofit2.http.* interface RetrofitService { /** @@ -56,6 +54,12 @@ /** * 安装新标识器 */ + @Multipart @POST("/ems/marker/save-marker-photo.do") - suspend fun installLabel(@Body requestBody: RequestBody): String + suspend fun installLabel( + @PartMap jsonMarker: Map, + @Part fileBuffer1: MultipartBody.Part?, + @Part fileBuffer2: MultipartBody.Part?, + @Part fileBuffer3: MultipartBody.Part? + ): String } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt index 1549f93..6e6f1ae 100644 --- a/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/detector/retrofit/RetrofitServiceManager.kt @@ -7,7 +7,11 @@ import com.pengxh.kt.lite.utils.RetrofitFactory import com.pengxh.kt.lite.utils.SaveKeyValues import okhttp3.MediaType.Companion.toMediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody +import java.io.File object RetrofitServiceManager { private val api by lazy { @@ -68,6 +72,7 @@ /** * 安装新标识器 + * Multipart上传图片,文件,带多参数上传 */ suspend fun installLabel( companyId: String, @@ -95,7 +100,8 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ): String { val param = JsonObject() param.addProperty("companyId", companyId) @@ -127,6 +133,31 @@ val requestBody = param.toString().toRequestBody( "application/json;charset=UTF-8".toMediaType() ) - return api.installLabel(requestBody) + val res = HashMap() + res["jsonMarker"] = requestBody + + val multiParts = ArrayList() + realPaths.forEachIndexed { index, s -> + val file = File(s) + val fileMultipart = MultipartBody.Part.createFormData( + "fileBuffer${index + 1}", file.name, file.asRequestBody("image/png".toMediaType()) + ) + multiParts.add(fileMultipart) + } + + return when (multiParts.size) { + 3 -> { + api.installLabel(res, multiParts[0], multiParts[1], multiParts[2]) + } + 2 -> { + api.installLabel(res, multiParts[0], multiParts[1], null) + } + 1 -> { + api.installLabel(res, multiParts[0], null, null) + } + else -> { + api.installLabel(res, null, null, null) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt index 5bb7fbe..e34bbb8 100644 --- a/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt +++ b/app/src/main/java/com/casic/detector/utils/LocaleConstant.kt @@ -22,16 +22,17 @@ const val USER_NAME = "USER_NAME" const val USER_ID = "USER_ID" const val USER_COMPANY_ID = "USER_COMPANY_ID" + const val OBJECT_ID = "OBJECT_ID" const val SERVER_IP = "SERVER_IP" const val SERVER_PORT = "SERVER_PORT" const val APP_AUTHORITY = "com.casic.detector.fileprovider" val POPUP_TITLES = arrayOf("更新数据", "下载工单", "关于软件", "事件上报", "标识器补全") - var POINT_TYPE_ARRAY = arrayOf("", "管线", "管线附属物", "管线特征管点", "交叉穿越点") + var POINT_TYPE_ARRAY = arrayOf("管线", "管线附属物", "管线特征管点", "交叉穿越点") var SPINNER_ARRAY = arrayOf("标识器ID", "所属区域", "所属线路", "所属道路", "权属单位", "安装部门", "安装时间", "备注") - var PIPE_MATERIAL_ARRAY = arrayOf("", "铸铁", "塑料") - var DOWN_PIPE_TYPE_ARRAY = arrayOf("", "热力", "燃气", "供水", "电力", "通信") - var BURY_METHOD_ARRAY = arrayOf("", "直埋", "圆管", "管块", "管沟", "架空") + var PIPE_MATERIAL_ARRAY = arrayOf("铸铁", "塑料") + var DOWN_PIPE_TYPE_ARRAY = arrayOf("热力", "燃气", "供水", "电力", "通信") + var BURY_METHOD_ARRAY = arrayOf("直埋", "圆管", "管块", "管沟", "架空") var IDENTIFIER_TYPE_ARRAY = arrayOf("EM30", "EM50", "EM14") var COLOR_ARRAY = arrayOf("蓝色", "橙色", "红色", "黑色", "紫色", "黄色", "绿色") } \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/BigImageActivity.kt b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt new file mode 100644 index 0000000..ca6c7d7 --- /dev/null +++ b/app/src/main/java/com/casic/detector/view/BigImageActivity.kt @@ -0,0 +1,87 @@ +package com.casic.detector.view + +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.viewpager.widget.PagerAdapter +import androidx.viewpager.widget.ViewPager +import com.bumptech.glide.Glide +import com.casic.detector.R +import com.luck.picture.lib.photoview.PhotoView +import com.pengxh.kt.lite.base.KotlinBaseActivity +import com.pengxh.kt.lite.utils.Constant +import com.pengxh.kt.lite.utils.ImmerseStatusBarUtil +import kotlinx.android.synthetic.main.activity_big_image.* + +class BigImageActivity : KotlinBaseActivity() { + + override fun initLayoutView(): Int = R.layout.activity_big_image + + override fun setupTopBarLayout() { + ImmerseStatusBarUtil.setColor(this, Color.BLACK) + leftBackView.setOnClickListener { finish() } + } + + override fun initData() { + + } + + override fun observeRequestState() { + + } + + override fun initEvent() { + val index: Int = intent.getIntExtra(Constant.BIG_IMAGE_INTENT_INDEX_KEY, 0) + val urls = intent.getStringArrayListExtra(Constant.BIG_IMAGE_INTENT_DATA_KEY) + if (urls == null || urls.size == 0) { + return + } + val imageSize = urls.size + pageNumberView.text = String.format("(" + (index + 1) + "/" + imageSize + ")") + imagePagerView.adapter = BigImageAdapter(this, urls) + imagePagerView.currentItem = index + imagePagerView.offscreenPageLimit = imageSize + imagePagerView.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrolled( + position: Int, positionOffset: Float, positionOffsetPixels: Int + ) { + } + + override fun onPageSelected(position: Int) { + pageNumberView.text = String.format("(" + (position + 1) + "/" + imageSize + ")") + } + + override fun onPageScrollStateChanged(state: Int) {} + }) + } + + inner class BigImageAdapter( + private val context: Context, private val data: ArrayList + ) : PagerAdapter() { + + override fun getCount(): Int = data.size + + override fun isViewFromObject(view: View, any: Any): Boolean { + return view == any + } + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = + LayoutInflater.from(context).inflate(R.layout.item_big_picture, container, false) + val photoView: PhotoView = view.findViewById(R.id.photoView) + Glide.with(context).load(data[position]).into(photoView) + photoView.scaleType = ImageView.ScaleType.CENTER_INSIDE + container.addView(view) + //点击大图取消预览 + photoView.setOnClickListener { finish() } + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, any: Any) { + container.removeView(any as View) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt index d61bec9..02b455f 100644 --- a/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt +++ b/app/src/main/java/com/casic/detector/view/InstallLabelActivity.kt @@ -1,43 +1,50 @@ package com.casic.detector.view +import android.annotation.SuppressLint +import android.app.DatePickerDialog import android.content.Context +import android.content.Intent +import android.provider.Settings import android.view.View +import androidx.lifecycle.ViewModelProvider import com.amap.api.location.AMapLocation import com.casic.detector.R -import com.casic.detector.callback.DateSelectedCallback +import com.casic.detector.adapter.EditableImageAdapter +import com.casic.detector.bean.LabelBean import com.casic.detector.callback.ILocationListener import com.casic.detector.callback.OnImageCompressListener import com.casic.detector.callback.OnItemSelectedListener -import com.casic.detector.extensions.compressImage -import com.casic.detector.extensions.initLayoutImmersionBar -import com.casic.detector.extensions.show -import com.casic.detector.extensions.showDatePicker +import com.casic.detector.extensions.* +import com.casic.detector.utils.DataBaseManager +import com.casic.detector.utils.LoadingDialogHub import com.casic.detector.utils.LocaleConstant import com.casic.detector.utils.LocationHub -import com.github.gzuliyujiang.wheelpicker.entity.DateEntity +import com.casic.detector.vm.TaskViewModel import com.gyf.immersionbar.ImmersionBar import com.luck.picture.lib.basic.PictureSelector import com.luck.picture.lib.config.SelectMimeType import com.luck.picture.lib.entity.LocalMedia import com.luck.picture.lib.interfaces.OnResultCallbackListener -import com.pengxh.kt.lite.adapter.EditableImageAdapter import com.pengxh.kt.lite.base.KotlinBaseActivity -import com.pengxh.kt.lite.extensions.convertColor -import com.pengxh.kt.lite.extensions.show -import com.pengxh.kt.lite.extensions.timestampToCompleteDate +import com.pengxh.kt.lite.extensions.* +import com.pengxh.kt.lite.utils.SaveKeyValues +import com.pengxh.kt.lite.vm.LoadState +import com.pengxh.kt.lite.widget.dialog.NoNetworkDialog import kotlinx.android.synthetic.main.activity_install_label.* import kotlinx.android.synthetic.main.include_base_title.* import kotlinx.android.synthetic.main.include_install_label_identifier.* import kotlinx.android.synthetic.main.include_install_label_object.* import kotlinx.android.synthetic.main.include_install_label_open_camera.* import java.io.File +import java.util.* +@SuppressLint("SetTextI18n") class InstallLabelActivity : KotlinBaseActivity() { private val kTag = "InstallLabelActivity" private val context: Context = this@InstallLabelActivity + private val calendar by lazy { Calendar.getInstance() } private lateinit var imageAdapter: EditableImageAdapter - private val imagePaths: ArrayList = ArrayList() //服务器返回的拍照数据集 private val realPaths: ArrayList = ArrayList() //真实图片路径 private var objectTypeSelectedItem = "" private var materialSelectedItem = "" @@ -46,17 +53,33 @@ private var buryMethodSelectedItem = "" private var identifierTypeSelectedItem = "" private var colorSelectedItem = "" + private lateinit var taskViewModel: TaskViewModel override fun initData() { imageAdapter = EditableImageAdapter(this, 3, 3f) addImageRecyclerView.adapter = imageAdapter + + taskViewModel = ViewModelProvider(this)[TaskViewModel::class.java] + + //设置默认值 + markerObjectTypeView.setText("markerObjectTypeView".getDefaultValue()) + pipelineDiameterView.setText("pipelineDiameterView".getDefaultValue()) + buryDeepView.setText("buryDeepView".getDefaultValue()) + downPipeDiameterView.setText("downPipeDiameterView".getDefaultValue()) + downPointDeepView.setText("downPointDeepView".getDefaultValue()) + areaView.setText("areaView".getDefaultValue()) + lineView.setText("lineView".getDefaultValue()) + roadView.setText("roadView".getDefaultValue()) + ownerView.setText("ownerView".getDefaultValue()) + identifierDeepView.setText("identifierDeepView".getDefaultValue()) + personDeptView.setText("personDeptView".getDefaultValue()) } override fun initEvent() { leftBackView.setOnClickListener { finish() } /**************************************************************************************/ - objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 1, + objectTypeSpinner.show(this, LocaleConstant.POINT_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { objectTypeSelectedItem = default @@ -67,7 +90,7 @@ } }) - materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + materialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { materialSelectedItem = default @@ -78,7 +101,7 @@ } }) - downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 1, + downPipeTypeSpinner.show(this, LocaleConstant.DOWN_PIPE_TYPE_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeSelectedItem = default @@ -89,7 +112,7 @@ } }) - downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 1, + downPipeMaterialSpinner.show(this, LocaleConstant.PIPE_MATERIAL_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { downPipeMaterialSelectedItem = default @@ -100,7 +123,7 @@ } }) - buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 1, + buryMethodSpinner.show(this, LocaleConstant.BURY_METHOD_ARRAY, 0, object : OnItemSelectedListener { override fun defaultSelection(default: String) { buryMethodSelectedItem = default @@ -112,11 +135,15 @@ }) constructDateView.setOnClickListener { - showDatePicker(DateEntity.today(), object : DateSelectedCallback { - override fun onDateSelected(date: String) { - constructDateView.text = date - } - }) + val year = calendar.get(Calendar.YEAR) + val month = calendar.get(Calendar.MONTH) + val day = calendar.get(Calendar.DAY_OF_MONTH) + val datePicker = DatePickerDialog(this, { _, y, m, d -> + constructDateView.text = String.format( + "%s-%s-%s", y, m.appendZero(), d.appendZero() + ) + }, year, month, day) + datePicker.show() } identifierTypeSpinner.show(this, LocaleConstant.IDENTIFIER_TYPE_ARRAY, 0, @@ -161,16 +188,153 @@ if (realPaths[position].isEmpty()) { "图片加载失败,无法查看大图".show(context) } else { -// context.navigatePageTo(position, realPaths) + context.navigatePageTo(position, realPaths) } } override fun onItemLongClick(view: View?, position: Int) { - imagePaths.removeAt(position) imageAdapter.deleteImage(position) } }) /**************************************************************************************/ + installButton.setOnClickListener { + if (isNetworkConnected()) { + val companyId = SaveKeyValues.getValue(LocaleConstant.USER_COMPANY_ID, "") as String + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + if (markerObjectTypeView.text.isNullOrBlank()) { + when (objectTypeSelectedItem) { + "管线" -> { + "请输入管线种类!".show(this) + } + "管线附属物" -> { + "请输入附属物名称!".show(this) + } + "管线特征管点" -> { + "请输入特征管点!".show(this) + } + "交叉穿越点" -> { + "请输入上层管种类!".show(this) + } + } + return@setOnClickListener + } + + if (pipelineDiameterView.text.isNullOrBlank()) { + "请输入管径".show(this) + return@setOnClickListener + } + + if (buryDeepView.text.isNullOrBlank()) { + "请输入埋深".show(this) + return@setOnClickListener + } + + if (downPipeDiameterView.text.isNullOrBlank()) { + "请输入下层管管径".show(this) + return@setOnClickListener + } + + if (areaView.text.isNullOrBlank()) { + "请输入所属区域".show(this) + return@setOnClickListener + } + + if (lineView.text.isNullOrBlank()) { + "请输入所属线路".show(this) + return@setOnClickListener + } + + if (roadView.text.isNullOrBlank()) { + "请输入所属道路".show(this) + return@setOnClickListener + } + + if (constructDateView.text.isNullOrBlank()) { + "请选择建设年代".show(this) + return@setOnClickListener + } + + if (ownerView.text.isNullOrBlank()) { + "请输入权属单位".show(this) + return@setOnClickListener + } + + if (identifierIdView.text.isNullOrBlank()) { + "请先读取标识器获取ID".show(this) + return@setOnClickListener + } + + if (identifierDeepView.text.isNullOrBlank()) { + "请输入标识器埋深".show(this) + return@setOnClickListener + } + + if (personDeptView.text.isNullOrBlank()) { + "请输入标识器安装部门".show(this) + return@setOnClickListener + } + + taskViewModel.installLabel( + companyId, + objectTypeSelectedItem.toObjectType(), + markerObjectTypeView.text.toString(), + materialSelectedItem, + "${pipelineDiameterView.text}mm", + "${buryDeepView.text}mm", + downPipeSelectedItem, + downPipeMaterialSelectedItem, + "${downPipeDiameterView.text}mm", + "${downPointDeepView.text}mm", + buryMethodSelectedItem, + areaView.text.toString(), + lineView.text.toString(), + roadView.text.toString(), + constructDateView.text.toString(), + ownerView.text.toString(), + objectId, + identifierIdView.text.toString(), + identifierTypeSelectedItem, + "${identifierDeepView.text}mm", + personDeptView.text.toString(), + installTimeView.text.toString(), + lngView.text.toString(), + latView.text.toString(), + colorSelectedItem.toColor(), + remarkView.text.toString(), + realPaths + ) + + //保存默认值 + "markerObjectTypeView".setDefaultValue(markerObjectTypeView.text.toString()) + "pipelineDiameterView".setDefaultValue(pipelineDiameterView.text.toString()) + "buryDeepView".setDefaultValue(buryDeepView.text.toString()) + "downPipeDiameterView".setDefaultValue(downPipeDiameterView.text.toString()) + "downPointDeepView".setDefaultValue(downPointDeepView.text.toString()) + "areaView".setDefaultValue(areaView.text.toString()) + "lineView".setDefaultValue(lineView.text.toString()) + "roadView".setDefaultValue(roadView.text.toString()) + "ownerView".setDefaultValue(ownerView.text.toString()) + "identifierDeepView".setDefaultValue(identifierDeepView.text.toString()) + "personDeptView".setDefaultValue(personDeptView.text.toString()) + } else { + NoNetworkDialog.Builder() + .setContext(context) + .setOnDialogButtonClickListener(object : + NoNetworkDialog.OnDialogButtonClickListener { + override fun onButtonClick() { + val intent = Intent(Settings.ACTION_SETTINGS) + startActivity(intent) + } + }).build().show() + } + } + + //TODO 搜索标识器 + readLabelButton.setOnClickListener { + LoadingDialogHub.show(this, "正在搜索标识器,请稍后...") + identifierIdView.text = "123456789" + LoadingDialogHub.dismiss() + } } private fun takePicture() { @@ -191,11 +355,11 @@ } private fun analyticalSelectResults(result: LocalMedia) { - //压缩图片后上传 + //压缩图片 result.realPath.compressImage(this, object : OnImageCompressListener { override fun onSuccess(file: File) { - //上传图片 -// fileUploadViewModel.uploadFile(file) + realPaths.add(file.absolutePath) + imageAdapter.setupImage(realPaths) } override fun onError(e: Throwable) { @@ -207,7 +371,51 @@ override fun initLayoutView(): Int = R.layout.activity_install_label override fun observeRequestState() { + taskViewModel.loadState.observe(this) { + when (it) { + LoadState.Loading -> LoadingDialogHub.show(this, "标识器安装中,请稍后...") + LoadState.Success -> { + saveLabelInLocal() + LoadingDialogHub.dismiss() + finish() + } + else -> LoadingDialogHub.dismiss() + } + } + } + //安装成功后将标识器保存在本地 + private fun saveLabelInLocal() { + val objectId = SaveKeyValues.getValue(LocaleConstant.OBJECT_ID, "") as String + + val labelBean = LabelBean() + labelBean.objectType = objectTypeSelectedItem + labelBean.pipelineType = markerObjectTypeView.text.toString() + labelBean.pipelineMaterial = materialSelectedItem + labelBean.pipelineDiameter = "${pipelineDiameterView.text}mm" + labelBean.buryDeep = "${buryDeepView.text}mm" + labelBean.lowerType = downPipeSelectedItem + labelBean.lowerMaterial = downPipeMaterialSelectedItem + labelBean.lowerDiameter = "${downPipeDiameterView.text}mm" + labelBean.lowerDeep = "${downPointDeepView.text}mm" + labelBean.buryMethod = buryMethodSelectedItem + labelBean.area = areaView.text.toString() + labelBean.line = lineView.text.toString() + labelBean.road = roadView.text.toString() + labelBean.constructTime = constructDateView.text.toString() + labelBean.owner = ownerView.text.toString() + labelBean.objectId = objectId + labelBean.identifierId = identifierIdView.text.toString() + labelBean.identifierType = identifierTypeSelectedItem + labelBean.identifierDeep = "${identifierDeepView.text}mm" + labelBean.person = personDeptView.text.toString() + labelBean.installTime = installTimeView.text.toString() + labelBean.lng = lngView.text.toString() + labelBean.lat = latView.text.toString() + labelBean.color = colorSelectedItem.toColor() + labelBean.remark = remarkView.text.toString() + + DataBaseManager.get.insertTaskLabel(labelBean) } override fun setupTopBarLayout() { diff --git a/app/src/main/java/com/casic/detector/view/MainActivity.kt b/app/src/main/java/com/casic/detector/view/MainActivity.kt index cd06e07..9b791e9 100644 --- a/app/src/main/java/com/casic/detector/view/MainActivity.kt +++ b/app/src/main/java/com/casic/detector/view/MainActivity.kt @@ -571,7 +571,8 @@ labelBean.lng, labelBean.lat, labelBean.color, - labelBean.remark + labelBean.remark, + arrayListOf() ) } LoadingDialogHub.dismiss() diff --git a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt index 082ee39..82813ff 100644 --- a/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt +++ b/app/src/main/java/com/casic/detector/view/ObjectDetailActivity.kt @@ -39,7 +39,7 @@ objectJson, object : TypeToken() {}.type ) - objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt()] + objectTypeView.text = LocaleConstant.POINT_TYPE_ARRAY[labelBean.objectType.toInt() - 1] pipelineTypeView.text = labelBean.pipelineType pipelineDiameterView.text = labelBean.pipelineDiameter pipelineMaterialView.text = labelBean.pipelineMaterial diff --git a/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt b/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt index 845b2b8..2475f0d 100644 --- a/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt +++ b/app/src/main/java/com/casic/detector/vm/TaskViewModel.kt @@ -89,8 +89,10 @@ longitude: String, latitude: String, colorType: String, - memo: String + memo: String, + realPaths: ArrayList ) = launch({ + loadState.value = LoadState.Loading val response = RetrofitServiceManager.installLabel( companyId, recordType, @@ -117,16 +119,17 @@ longitude, latitude, colorType, - memo + memo, + realPaths ) if (response.separateResponseState()) { -// taskResult.value = gson.fromJson( -// response, object : TypeToken() {}.type -// ) + loadState.value = LoadState.Success } else { + loadState.value = LoadState.Fail response.toErrorMessage().show(BaseApplication.get()) } }, { + loadState.value = LoadState.Fail it.convertChinese().show(BaseApplication.get()) }) diff --git a/app/src/main/res/layout/activity_big_image.xml b/app/src/main/res/layout/activity_big_image.xml new file mode 100644 index 0000000..9d060f4 --- /dev/null +++ b/app/src/main/res/layout/activity_big_image.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_install_label.xml b/app/src/main/res/layout/activity_install_label.xml index 10dfdc2..e191ec8 100644 --- a/app/src/main/res/layout/activity_install_label.xml +++ b/app/src/main/res/layout/activity_install_label.xml @@ -64,9 +64,11 @@ android:textSize="@dimen/sp_18" /> + android:layout_height="@dimen/dp_100" + android:gravity="top" + android:paddingVertical="@dimen/dp_5" /> diff --git a/app/src/main/res/layout/include_install_label_identifier.xml b/app/src/main/res/layout/include_install_label_identifier.xml index 87f0070..d166fd0 100644 --- a/app/src/main/res/layout/include_install_label_identifier.xml +++ b/app/src/main/res/layout/include_install_label_identifier.xml @@ -37,7 +37,10 @@ style="@style/textViewStyle" android:text="ID号:" /> - + @@ -100,7 +104,9 @@ style="@style/textViewStyle" android:text="部门:" /> - + - + @@ -120,6 +123,7 @@ android:text="埋深:" /> @@ -184,6 +188,7 @@ android:text="下层管直径:" /> @@ -210,6 +215,7 @@ android:text="下层管埋深:" /> @@ -254,7 +260,9 @@ style="@style/textViewStyle" android:text="所属区域:" /> - + - + - + - + \ No newline at end of file diff --git a/app/src/main/res/layout/include_install_label_open_camera.xml b/app/src/main/res/layout/include_install_label_open_camera.xml index 39f3242..2ebfeea 100644 --- a/app/src/main/res/layout/include_install_label_open_camera.xml +++ b/app/src/main/res/layout/include_install_label_open_camera.xml @@ -22,6 +22,15 @@ android:layout_marginHorizontal="@dimen/dp_10" android:text="拍照片" android:textSize="@dimen/sp_18" /> + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_editable_rv_g.xml b/app/src/main/res/layout/item_editable_rv_g.xml new file mode 100644 index 0000000..8d0fc20 --- /dev/null +++ b/app/src/main/res/layout/item_editable_rv_g.xml @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-xxxhdpi/photo6.png b/app/src/main/res/mipmap-xxxhdpi/photo6.png new file mode 100644 index 0000000..dde3c6f --- /dev/null +++ b/app/src/main/res/mipmap-xxxhdpi/photo6.png Binary files differ