Commit c697848a authored by wanglei's avatar wanglei

...

parent fd6e6cb5
......@@ -11,6 +11,7 @@ import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.core.content.ContextCompat
import androidx.lifecycle.LiveData
import com.base.scanqr.utils.LogEx
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import kotlin.math.abs
......@@ -21,6 +22,7 @@ import kotlin.math.min
class CameraUtils(
val activity: AppCompatActivity,
) {
private val TAG = "CameraUtils"
private var cameraExecutor: ExecutorService? = null
......@@ -76,7 +78,11 @@ class CameraUtils(
previewView.width,
previewView.height
)
val rotation = previewView.display.rotation
val display = previewView.display
LogEx.logDebug(TAG, "display=${display == null}")
val rotation = display.rotation
// 选择相机
val cameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()
......
package com.base.scanqr.ui.main
import android.content.Context
import android.text.format.DateUtils
import android.view.View
import android.view.ViewGroup
import com.base.scanqr.R
import com.base.scanqr.bean.FunctionUIBean.Companion.KEY_CONTACT
......@@ -16,17 +18,22 @@ import com.base.scanqr.bean.ScanBean
import com.base.scanqr.bean.WifiUIBean
import com.base.scanqr.databinding.ItemHistoryBinding
import com.base.scanqr.ui.adapter.CommonViewHolder
import com.base.scanqr.utils.DateUtils.formatTimeAgo
import com.base.scanqr.utils.XmlEx.inflate
import com.chad.library.adapter4.BaseQuickAdapter
class HistoryAdapter : BaseQuickAdapter<ScanBean, CommonViewHolder>() {
var moreAction: ((view: View, item: ScanBean) -> Unit)? = null
var itemClick: ((item: ScanBean) -> Unit)? = null
override fun onBindViewHolder(holder: CommonViewHolder, position: Int, item: ScanBean?) {
item ?: return
val binding = ItemHistoryBinding.bind(holder.itemView)
when (item.scanType) {
KEY_WIFI -> {
if (item is WifiUIBean) {
binding.ivIcon.setImageResource(R.mipmap.h_wifi)
binding.tvDesc.text = item.ssid
}
}
......@@ -63,6 +70,13 @@ class HistoryAdapter : BaseQuickAdapter<ScanBean, CommonViewHolder>() {
}
binding.tvTime.text = formatTimeAgo(item.createTime)
binding.flMore.setOnClickListener {
moreAction?.invoke(it, item)
}
binding.root.setOnClickListener {
itemClick?.invoke(item)
}
}
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): CommonViewHolder {
......
......@@ -3,24 +3,46 @@ package com.base.scanqr.ui.main
import android.graphics.Color
import androidx.core.content.ContextCompat
import androidx.core.view.updatePadding
import androidx.lifecycle.ViewModelProvider
import com.base.scanqr.R
import com.base.scanqr.base.BaseFragment
import com.base.scanqr.bean.EmailUIBean
import com.base.scanqr.bean.FunctionUIBean
import com.base.scanqr.bean.TextUIBean
import com.base.scanqr.bean.WifiUIBean
import com.base.scanqr.databinding.FragmentHistoryBinding
import com.base.scanqr.ui.widget.DeleteQRDialog.showDeleteQRDialog
import com.base.scanqr.ui.widget.HistoryMoreDialog.showHistoryMoreDialog
import com.base.scanqr.utils.BarUtils
import com.base.scanqr.utils.LogEx
import com.base.scanqr.utils.SpJsonUtils
class HistoryFragment : BaseFragment<FragmentHistoryBinding>(FragmentHistoryBinding::inflate) {
private var adapter: HistoryAdapter? = null
private val viewModel by lazy(LazyThreadSafetyMode.NONE) {
ViewModelProvider(this)[HistoryViewModel::class.java]
}
override fun initView() {
super.initView()
binding.flTop.updatePadding(top = BarUtils.getStatusBarHeight())
initAdapter()
viewModel.initData()
}
private fun initAdapter() {
adapter = HistoryAdapter()
binding.rv.adapter = adapter
adapter?.moreAction = { view, bean ->
requireContext().showHistoryMoreDialog(view, detailAction = {}, removeAction = {
viewModel.removeBean(bean)
if (tab == 0) {
scanUI()
} else {
createUI()
}
})
}
adapter?.itemClick = {}
}
override fun initListener() {
......@@ -31,35 +53,69 @@ class HistoryFragment : BaseFragment<FragmentHistoryBinding>(FragmentHistoryBind
binding.tvCreate.setOnClickListener {
createUI()
}
binding.llRemove.setOnClickListener {
requireContext().showDeleteQRDialog {
val wifiList = SpJsonUtils.getSpJsonList<WifiUIBean>(FunctionUIBean.KEY_WIFI)
wifiList.forEach {
LogEx.logDebug(TAG, "${it.scanType} ${it.ssid} ${it.password} ${it.createTime}")
}
val textList = SpJsonUtils.getSpJsonList<TextUIBean>(FunctionUIBean.KEY_TEXT)
textList.forEach {
LogEx.logDebug(TAG, "${it.scanType} ${it.content} ${it.createTime}")
viewModel.removeList(tab)
if (tab == 0) {
scanUI()
} else {
createUI()
}
}
}
val emailList = SpJsonUtils.getSpJsonList<EmailUIBean>(FunctionUIBean.KEY_EMAIL)
emailList.forEach {
LogEx.logDebug(TAG, "${it.scanType} ${it.address} ${it.createTime}")
if (tab == 0) {
scanUI()
} else {
createUI()
}
}
private fun scanUI() {
tab = 0
binding.tvScan.background = ContextCompat.getDrawable(requireContext(), R.drawable.bg_6473f8_10)
binding.tvScan.setTextColor(Color.parseColor("#FFFFFF"))
binding.tvCreate.background = ContextCompat.getDrawable(requireContext(), R.drawable.bg_transparent)
binding.tvCreate.setTextColor(Color.parseColor("#666666"))
changeRvData(false)
}
private fun createUI() {
tab = 1
binding.tvCreate.background = ContextCompat.getDrawable(requireContext(), R.drawable.bg_6473f8_10)
binding.tvCreate.setTextColor(Color.parseColor("#FFFFFF"))
binding.tvScan.background = ContextCompat.getDrawable(requireContext(), R.drawable.bg_transparent)
binding.tvScan.setTextColor(Color.parseColor("#666666"))
changeRvData(true)
}
private fun changeRvData(isCreateOrScan: Boolean) {
val uiRefresh = {
val createList = viewModel.historyList.filter { it.isCreateOrScan == isCreateOrScan }
adapter?.submitList(createList)
}
if (viewModel.dataRefreshFinish.get()) {
uiRefresh.invoke()
} else {
viewModel.dataRefreshBack = {
requireActivity().runOnUiThread {
uiRefresh.invoke()
}
}
}
}
companion object {
var tab: Int = 0 //scan=0 create=1
var sort: Int = 0
}
}
\ No newline at end of file
package com.base.scanqr.ui.main
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.base.scanqr.bean.EmailUIBean
import com.base.scanqr.bean.FunctionUIBean
import com.base.scanqr.bean.ScanBean
import com.base.scanqr.bean.TextUIBean
import com.base.scanqr.bean.WifiUIBean
import com.base.scanqr.utils.SpJsonUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.concurrent.atomic.AtomicBoolean
class HistoryViewModel() : ViewModel() {
var historyList = arrayListOf<ScanBean>()
var dataRefreshFinish = AtomicBoolean(false)
var dataRefreshBack: (() -> Unit)? = null
fun initData() = viewModelScope.launch(Dispatchers.IO) {
historyList.clear()
val wifiList = SpJsonUtils.getSpJsonList<WifiUIBean>(FunctionUIBean.KEY_WIFI)
val textList = SpJsonUtils.getSpJsonList<TextUIBean>(FunctionUIBean.KEY_TEXT)
val emailList = SpJsonUtils.getSpJsonList<EmailUIBean>(FunctionUIBean.KEY_EMAIL)
historyList.addAll(wifiList)
historyList.addAll(textList)
historyList.addAll(emailList)
dataRefreshBack?.invoke()
dataRefreshFinish.set(true)
}
fun removeList(tab: Int) {
val removeList = historyList.filter { if (tab == 0) !it.isCreateOrScan else it.isCreateOrScan }
removeList.forEach { removeBean(it) }
}
fun removeBean(bean: ScanBean) {
val scanBean = when (bean.scanType) {
FunctionUIBean.KEY_WIFI -> bean as WifiUIBean
FunctionUIBean.KEY_TEXT -> bean as TextUIBean
FunctionUIBean.KEY_EMAIL -> bean as EmailUIBean
else -> bean
}
SpJsonUtils.removeJsonBean(bean.scanType, scanBean, removeIf = { it1, it2 ->
it1.createTime == it2.createTime
})
historyList.removeIf { it.createTime == bean.createTime }
}
}
\ No newline at end of file
package com.base.scanqr.ui.widget
import android.app.AlertDialog
import android.content.Context
import android.view.Gravity
import android.view.LayoutInflater
import com.base.scanqr.databinding.DialogDeleteQrBinding
object DeleteQRDialog {
fun Context.showDeleteQRDialog(
removeAction: (() -> Unit)? = null,
) {
val dialog = AlertDialog.Builder(this).create()
val binding = DialogDeleteQrBinding.inflate(LayoutInflater.from(this))
dialog.setView(binding.root)
dialog.setCanceledOnTouchOutside(false)
dialog.show()
val params = dialog.window?.attributes
// params?.width = resources.getDimensionPixelOffset(R.dimen.dp_320)
// params?.height = resources.getDimensionPixelOffset(R.dimen.dp_400)
params?.gravity = Gravity.CENTER
// params?.y = 50
dialog.window?.attributes = params
dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
binding.tvCancel.setOnClickListener {
dialog.dismiss()
}
binding.tvRemove.setOnClickListener {
dialog.dismiss()
removeAction?.invoke()
}
}
}
\ No newline at end of file
package com.base.scanqr.ui.widget
import android.app.AlertDialog
import android.content.Context
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
import com.base.scanqr.R
import com.base.scanqr.databinding.DialogHistoryMoreBinding
import com.base.scanqr.ui.widget.DeleteQRDialog.showDeleteQRDialog
import com.base.scanqr.utils.DialogUtils.viewIsTopHalf
import com.base.scanqr.utils.LogEx
object HistoryMoreDialog {
private val TAG = "HistoryMoreDialog"
fun Context.showHistoryMoreDialog(
anchorView: View,
detailAction: (() -> Unit)? = null,
removeAction: (() -> Unit)? = null,
) {
val dialog = AlertDialog.Builder(this).create()
val binding = DialogHistoryMoreBinding.inflate(LayoutInflater.from(this))
dialog.setView(binding.root)
dialog.setCanceledOnTouchOutside(true)
dialog.show()
dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
val params = dialog.window?.attributes
params?.dimAmount = 0f
params?.width = resources.getDimensionPixelOffset(R.dimen.dp_200)
// params?.width = FrameLayout.LayoutParams.WRAP_CONTENT
params?.height = FrameLayout.LayoutParams.WRAP_CONTENT
params?.gravity = Gravity.TOP
val location = IntArray(2)
val isTopHalf = viewIsTopHalf(anchorView)
LogEx.logDebug(TAG, "isTopHalf=$isTopHalf")
anchorView.getLocationOnScreen(location)
//减少宽度附近的值
val x = location[0] - resources.getDimensionPixelOffset(R.dimen.dp_256)
val y = if (isTopHalf) {
location[1] - resources.getDimensionPixelOffset(R.dimen.dp_15)
} else {
//减少高度附近的值
location[1] - resources.getDimensionPixelOffset(R.dimen.dp_114) - anchorView.height
}
params?.x = x
params?.y = y
dialog.window?.attributes = params
binding.tvDetail.setOnClickListener {
dialog.dismiss()
detailAction?.invoke()
}
binding.tvRemove.setOnClickListener {
dialog.dismiss()
showDeleteQRDialog(removeAction)
}
}
}
\ No newline at end of file
package com.base.scanqr.utils
import android.annotation.SuppressLint
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import kotlin.random.Random
object DateUtils {
fun getDayOfWeek(timestamp: Long): String {
val days = arrayOf("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
val calendar = Calendar.getInstance().apply { timeInMillis = timestamp }
return days[calendar.get(Calendar.DAY_OF_WEEK) - 1]
}
fun getYearFromTimestamp(timestamp: Long): Int {
val calendar: Calendar = Calendar.getInstance()
calendar.setTimeInMillis(timestamp)
return calendar.get(Calendar.YEAR) // 返回年份
}
fun getMonthFromTimestamp(timestamp: Long): Int {
val calendar = Calendar.getInstance()
calendar.timeInMillis = timestamp
return calendar[Calendar.MONTH] + 1 // 返回月份,需要加1因为Calendar.MONTH是从0开始的
}
fun getDayOfMonthFromTimestamp(timestamp: Long): Int {
val calendar = Calendar.getInstance()
calendar.timeInMillis = timestamp
return calendar[Calendar.DAY_OF_MONTH] // 返回当前是月份的第几天
}
fun getDaySuffix(day: Int): String {
return when (day) {
1, 21, 31 -> "st"
2, 22 -> "nd"
3, 23 -> "rd"
else -> "th"
}
}
fun getHourOfDayFromTimestamp(timestamp: Long): Int {
val calendar = Calendar.getInstance()
calendar.timeInMillis = timestamp
return calendar[Calendar.HOUR_OF_DAY] // 返回当前小时(24小时制)
}
fun getMinuteFromTimestamp(timestamp: Long): Int {
val calendar = Calendar.getInstance()
calendar.timeInMillis = timestamp
return calendar[Calendar.MINUTE] // 返回当前分钟
}
/**
* month是从1开的
*/
fun getTimestampFromDateTime(year: Int, month: Int, day: Int, hour: Int, minute: Int): Long {
val calendar = Calendar.getInstance()
calendar[year, month - 1, day, hour] = minute
return calendar.timeInMillis // 返回对应的时间戳
}
fun daysInMonth(year: Int, month: Int): Int {
// 每个月的天数,二月默认为28天
val monthDays = arrayOf(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
// 检查是否是闰年
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
monthDays[1] = 29 // 如果是闰年,二月有29天
}
// 返回给定月份的天数
return monthDays[month - 1]
}
@SuppressLint("SimpleDateFormat")
fun generateRandomBirthdayTimestamp(age: Int): Long {
val currentTimeMillis = System.currentTimeMillis()
// 计算出生年份
val birthYear = 2024 - age
// 随机选择一个月份
val randomMonth = Random.nextInt(12) + 1
// 随机选择一个日期,确保是该月的有效日期
val randomDay = Random.nextInt(28) + 1 // 简单起见,我们假设日期不会超过28
// 构建出生日期字符串,包括时间部分
val birthDate = "$birthYear-${randomMonth.toString().padStart(2, '0')}-${randomDay.toString().padStart(2, '0')} 00:00:00"
// 将字符串转换为时间戳
return try {
// 尝试解析日期字符串
val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
dateFormat.parse(birthDate)?.time ?: currentTimeMillis
} catch (e: ParseException) {
// 如果解析失败,返回当前时间戳
currentTimeMillis
}
}
fun calculateAge(birthTimestamp: Long): Int {
// 创建一个 Calendar 实例
val birthCalendar = Calendar.getInstance()
// 设置时间戳对应的日期
birthCalendar.timeInMillis = birthTimestamp
// 创建一个 Calendar 实例用于获取当前日期
val currentCalendar = Calendar.getInstance()
// 计算年龄
var age = currentCalendar.get(Calendar.YEAR) - birthCalendar.get(Calendar.YEAR)
// 如果当前日期还没有到生日,则年龄减一
if (currentCalendar.get(Calendar.DAY_OF_YEAR) < birthCalendar.get(Calendar.DAY_OF_YEAR)) {
age--
}
return age
}
// fun formatTimeAgo(timestamp: Long): String {
// val instant = Instant.ofEpochMilli(timestamp)
// val now = LocalDateTime.now(ZoneId.systemDefault())
// val then = LocalDateTime.ofInstant(instant, ZoneId.systemDefault())
//
// val seconds = ChronoUnit.SECONDS.between(then, now)
// val minutes = ChronoUnit.MINUTES.between(then, now)
// val hours = ChronoUnit.HOURS.between(then, now)
// val days = ChronoUnit.DAYS.between(then, now)
//
// return when {
// days > 0 -> days.toString() + "day ago"
// hours > 0 -> hours.toString() + "H ago"
// minutes > 0 -> minutes.toString() + "Min ago"
// else -> seconds.toString() + "s ago"
// }
// }
fun formatTimeAgo(timestamp: Long): String {
val then = Date(timestamp)
val now = Date()
val diff = now.time - then.time
if (diff < 1000 * 60) {
// less than a minute
return (diff / 1000).toString() + " s ago"
} else if (diff < 1000 * 60 * 60) {
// less than an hour
return (diff / (1000 * 60)).toString() + " minute ago"
} else if (diff < 1000 * 60 * 60 * 24) {
// less than a day
return (diff / (1000 * 60 * 60)).toString() + " hour ago"
} else {
// more than a day
return (diff / (1000 * 60 * 60 * 24)).toString() + " day ago"
}
}
}
\ No newline at end of file
package com.base.scanqr.utils
import android.content.Context
import android.content.Context.WINDOW_SERVICE
import android.util.DisplayMetrics
import android.view.View
import android.view.WindowManager
object DialogUtils {
/**
* 判断视图在上半边还是下半边屏幕
*/
fun Context.viewIsTopHalf(view: View): Boolean {
val location = IntArray(2)
view.getLocationOnScreen(location)
val windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
val dm = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(dm)
val screenHeight = dm.heightPixels
// 判断视图的顶部是否在屏幕的上半部分
val isTopHalf = location[1] < screenHeight / 2
// 判断视图的底部是否在屏幕的上半部分
val isBottomHalf = location[1] + view.height < screenHeight / 2
return if (isTopHalf) {
// 视图的顶部在屏幕的上半部分
true
} else if (isBottomHalf) {
// 视图的底部在屏幕的上半部分
true
} else {
// 视图在屏幕的下半部分
false
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:cardBackgroundColor="@color/white"
app:cardCornerRadius="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="28dp"
android:text="@string/delete_qrcode"
android:textColor="@color/black"
android:textSize="19sp"
android:textStyle="bold" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="8dp"
android:gravity="center"
android:text="@string/do_you_want_delete_item"
android:textColor="#666666"
android:textSize="16sp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="24dp"
android:layout_marginBottom="24dp">
<TextView
android:id="@+id/tv_cancel"
android:layout_width="142dp"
android:layout_height="44dp"
android:layout_gravity="center_vertical"
android:background="@drawable/bg_f8f8fa_90"
android:gravity="center"
android:text="@string/cancel"
android:textColor="#333333"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_remove"
android:layout_width="142dp"
android:layout_height="44dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="16dp"
android:background="@drawable/bg_6473f8_90"
android:gravity="center"
android:text="@string/remove"
android:textColor="@color/white"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:layout_width="180dp"
android:layout_height="wrap_content"
android:layout_margin="10dp"
app:cardBackgroundColor="@color/white"
app:cardCornerRadius="10dp"
app:cardElevation="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_detail"
android:layout_width="match_parent"
android:layout_height="54dp"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:paddingStart="18dp"
android:text="@string/detail"
android:textColor="@color/black"
android:textSize="16sp"
tools:ignore="RtlSymmetry" />
<TextView
android:id="@+id/tv_remove"
android:layout_width="match_parent"
android:layout_height="54dp"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:paddingStart="18dp"
android:text="@string/remove"
android:textColor="@color/black"
android:textSize="16sp"
tools:ignore="RtlSymmetry" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</FrameLayout>
\ No newline at end of file
......@@ -51,6 +51,7 @@
</LinearLayout>
<FrameLayout
android:id="@+id/fl_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
......
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="dp_400">400dp</dimen>
<dimen name="dp_106">106dp</dimen>
<dimen name="dp_2">2dp</dimen>
<dimen name="dp_180">180dp</dimen>
<dimen name="dp_20">20dp</dimen>
<dimen name="dp_108">108dp</dimen>
<dimen name="dp_10">10dp</dimen>
<dimen name="dp_190">190dp</dimen>
<dimen name="dp_118">118dp</dimen>
<dimen name="dp_200">200dp</dimen>
<dimen name="dp_210">210dp</dimen>
<dimen name="dp_220">220dp</dimen>
<dimen name="dp_250">250dp</dimen>
<dimen name="dp_240">240dp</dimen>
<dimen name="dp_230">230dp</dimen>
<dimen name="dp_235">235dp</dimen>
<dimen name="dp_256">256dp</dimen>
<dimen name="dp_30">30dp</dimen>
<dimen name="dp_50">50dp</dimen>
<dimen name="dp_25">25dp</dimen>
<dimen name="dp_15">15dp</dimen>
<dimen name="dp_128">128dp</dimen>
<dimen name="dp_138">138dp</dimen>
<dimen name="dp_102">102dp</dimen>
<dimen name="dp_95">95dp</dimen>
<dimen name="dp_110">110dp</dimen>
<dimen name="dp_112">112dp</dimen>
<dimen name="dp_114">114dp</dimen>
</resources>
\ No newline at end of file
......@@ -45,4 +45,7 @@
<string name="sort">Sort</string>
<string name="export">Export</string>
<string name="remove">Remove</string>
<string name="detail">Detail</string>
<string name="delete_qrcode">Delete QRCode</string>
<string name="do_you_want_delete_item">Do you want delete item?</string>
</resources>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment