Improve profile item
This commit is contained in:
@@ -91,10 +91,11 @@ dependencies {
|
|||||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||||
implementation 'com.google.android.material:material:1.11.0'
|
implementation 'com.google.android.material:material:1.11.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||||
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2'
|
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.7.0'
|
||||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'
|
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0'
|
||||||
implementation 'androidx.navigation:navigation-fragment-ktx:2.7.6'
|
implementation 'androidx.navigation:navigation-fragment-ktx:2.7.6'
|
||||||
implementation 'androidx.navigation:navigation-ui-ktx:2.7.6'
|
implementation 'androidx.navigation:navigation-ui-ktx:2.7.6'
|
||||||
|
implementation 'com.google.zxing:core:3.4.1'
|
||||||
implementation 'androidx.room:room-runtime:2.6.1'
|
implementation 'androidx.room:room-runtime:2.6.1'
|
||||||
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0'
|
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0'
|
||||||
implementation 'androidx.preference:preference-ktx:1.2.1'
|
implementation 'androidx.preference:preference-ktx:1.2.1'
|
||||||
|
|||||||
14
app/src/main/java/io/nekohasekai/sfa/ktx/Dimens.kt
Normal file
14
app/src/main/java/io/nekohasekai/sfa/ktx/Dimens.kt
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package io.nekohasekai.sfa.ktx
|
||||||
|
|
||||||
|
import android.content.res.Resources
|
||||||
|
import kotlin.math.ceil
|
||||||
|
|
||||||
|
private val density = Resources.getSystem().displayMetrics.density
|
||||||
|
|
||||||
|
fun dp2pxf(dpValue: Int): Float {
|
||||||
|
return density * dpValue
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dp2px(dpValue: Int): Int {
|
||||||
|
return ceil(dp2pxf(dpValue)).toInt()
|
||||||
|
}
|
||||||
@@ -2,11 +2,18 @@ package io.nekohasekai.sfa.ktx
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.Color
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
import com.google.android.material.R
|
import com.google.android.material.R
|
||||||
|
import com.google.zxing.BarcodeFormat
|
||||||
|
import com.google.zxing.qrcode.QRCodeWriter
|
||||||
|
import io.nekohasekai.libbox.Libbox
|
||||||
import io.nekohasekai.libbox.ProfileContent
|
import io.nekohasekai.libbox.ProfileContent
|
||||||
import io.nekohasekai.sfa.database.Profile
|
import io.nekohasekai.sfa.database.Profile
|
||||||
import io.nekohasekai.sfa.database.TypedProfile
|
import io.nekohasekai.sfa.database.TypedProfile
|
||||||
|
import io.nekohasekai.sfa.ui.shared.QRCodeDialog
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -43,4 +50,28 @@ suspend fun Context.shareProfile(profile: Profile) {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun FragmentActivity.shareProfileURL(profile: Profile) {
|
||||||
|
val link = Libbox.generateRemoteProfileImportLink(
|
||||||
|
profile.name,
|
||||||
|
profile.typed.remoteURL
|
||||||
|
)
|
||||||
|
val imageSize = dp2px(256)
|
||||||
|
val color = getAttrColor(com.google.android.material.R.attr.colorPrimary)
|
||||||
|
val image = QRCodeWriter().encode(link, BarcodeFormat.QR_CODE, imageSize, imageSize, null)
|
||||||
|
val imageWidth = image.width
|
||||||
|
val imageHeight = image.height
|
||||||
|
val imageArray = IntArray(imageWidth * imageHeight)
|
||||||
|
for (y in 0 until imageHeight) {
|
||||||
|
val offset = y * imageWidth
|
||||||
|
for (x in 0 until imageWidth) {
|
||||||
|
imageArray[offset + x] = if (image.get(x, y)) color else Color.TRANSPARENT
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val bitmap = Bitmap.createBitmap(imageWidth, imageHeight, Bitmap.Config.ARGB_8888)
|
||||||
|
bitmap.setPixels(imageArray, 0, imageSize, 0, 0, imageWidth, imageHeight)
|
||||||
|
val dialog = QRCodeDialog(bitmap)
|
||||||
|
dialog.show(supportFragmentManager, "share-profile-url")
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@ import android.view.ViewGroup
|
|||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
@@ -15,13 +16,14 @@ import androidx.recyclerview.widget.RecyclerView
|
|||||||
import io.nekohasekai.sfa.R
|
import io.nekohasekai.sfa.R
|
||||||
import io.nekohasekai.sfa.database.Profile
|
import io.nekohasekai.sfa.database.Profile
|
||||||
import io.nekohasekai.sfa.database.ProfileManager
|
import io.nekohasekai.sfa.database.ProfileManager
|
||||||
|
import io.nekohasekai.sfa.database.TypedProfile
|
||||||
import io.nekohasekai.sfa.databinding.FragmentConfigurationBinding
|
import io.nekohasekai.sfa.databinding.FragmentConfigurationBinding
|
||||||
import io.nekohasekai.sfa.databinding.ViewConfigutationItemBinding
|
import io.nekohasekai.sfa.databinding.ViewConfigutationItemBinding
|
||||||
import io.nekohasekai.sfa.ktx.errorDialogBuilder
|
import io.nekohasekai.sfa.ktx.errorDialogBuilder
|
||||||
import io.nekohasekai.sfa.ktx.shareProfile
|
import io.nekohasekai.sfa.ktx.shareProfile
|
||||||
|
import io.nekohasekai.sfa.ktx.shareProfileURL
|
||||||
import io.nekohasekai.sfa.ui.profile.EditProfileActivity
|
import io.nekohasekai.sfa.ui.profile.EditProfileActivity
|
||||||
import io.nekohasekai.sfa.ui.profile.NewProfileActivity
|
import io.nekohasekai.sfa.ui.profile.NewProfileActivity
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -36,7 +38,7 @@ class ConfigurationFragment : Fragment() {
|
|||||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
val binding = FragmentConfigurationBinding.inflate(inflater, container, false)
|
val binding = FragmentConfigurationBinding.inflate(inflater, container, false)
|
||||||
val adapter = Adapter(lifecycleScope, binding)
|
val adapter = Adapter(binding)
|
||||||
this.adapter = adapter
|
this.adapter = adapter
|
||||||
binding.profileList.also {
|
binding.profileList.also {
|
||||||
it.layoutManager = LinearLayoutManager(requireContext())
|
it.layoutManager = LinearLayoutManager(requireContext())
|
||||||
@@ -89,16 +91,17 @@ class ConfigurationFragment : Fragment() {
|
|||||||
adapter?.reload()
|
adapter?.reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
class Adapter(
|
inner class Adapter(
|
||||||
internal val scope: CoroutineScope,
|
private val parent: FragmentConfigurationBinding
|
||||||
internal val parent: FragmentConfigurationBinding
|
|
||||||
) :
|
) :
|
||||||
RecyclerView.Adapter<Holder>() {
|
RecyclerView.Adapter<Holder>() {
|
||||||
|
|
||||||
internal var items: MutableList<Profile> = mutableListOf()
|
internal var items: MutableList<Profile> = mutableListOf()
|
||||||
|
internal val scope = lifecycleScope
|
||||||
|
internal val fragmentActivity = requireActivity() as FragmentActivity
|
||||||
|
|
||||||
internal fun reload() {
|
internal fun reload() {
|
||||||
scope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
val newItems = ProfileManager.list().toMutableList()
|
val newItems = ProfileManager.list().toMutableList()
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
items = newItems
|
items = newItems
|
||||||
@@ -163,6 +166,15 @@ class ConfigurationFragment : Fragment() {
|
|||||||
|
|
||||||
internal fun bind(profile: Profile) {
|
internal fun bind(profile: Profile) {
|
||||||
binding.profileName.text = profile.name
|
binding.profileName.text = profile.name
|
||||||
|
if (profile.typed.type == TypedProfile.Type.Remote) {
|
||||||
|
binding.profileLastUpdated.isVisible = true
|
||||||
|
binding.profileLastUpdated.text = binding.root.context.getString(
|
||||||
|
R.string.profile_item_last_updated,
|
||||||
|
profile.typed.lastUpdated.toLocaleString()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
binding.profileLastUpdated.isVisible = false
|
||||||
|
}
|
||||||
binding.root.setOnClickListener {
|
binding.root.setOnClickListener {
|
||||||
val intent = Intent(binding.root.context, EditProfileActivity::class.java)
|
val intent = Intent(binding.root.context, EditProfileActivity::class.java)
|
||||||
intent.putExtra("profile_id", profile.id)
|
intent.putExtra("profile_id", profile.id)
|
||||||
@@ -172,6 +184,9 @@ class ConfigurationFragment : Fragment() {
|
|||||||
val popup = PopupMenu(button.context, button)
|
val popup = PopupMenu(button.context, button)
|
||||||
popup.setForceShowIcon(true)
|
popup.setForceShowIcon(true)
|
||||||
popup.menuInflater.inflate(R.menu.profile_menu, popup.menu)
|
popup.menuInflater.inflate(R.menu.profile_menu, popup.menu)
|
||||||
|
if (profile.typed.type != TypedProfile.Type.Remote) {
|
||||||
|
popup.menu.removeItem(R.id.action_share_url)
|
||||||
|
}
|
||||||
popup.setOnMenuItemClickListener {
|
popup.setOnMenuItemClickListener {
|
||||||
when (it.itemId) {
|
when (it.itemId) {
|
||||||
R.id.action_share -> {
|
R.id.action_share -> {
|
||||||
@@ -187,6 +202,19 @@ class ConfigurationFragment : Fragment() {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
R.id.action_share_url -> {
|
||||||
|
adapter.scope.launch(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
adapter.fragmentActivity.shareProfileURL(profile)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
button.context.errorDialogBuilder(e).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
R.id.action_delete -> {
|
R.id.action_delete -> {
|
||||||
adapter.items.remove(profile)
|
adapter.items.remove(profile)
|
||||||
adapter.notifyItemRemoved(adapterPosition)
|
adapter.notifyItemRemoved(adapterPosition)
|
||||||
|
|||||||
@@ -95,13 +95,11 @@ class EditProfileActivity : AbstractActivity() {
|
|||||||
TypedProfile.Type.Local -> {
|
TypedProfile.Type.Local -> {
|
||||||
binding.editButton.isVisible = true
|
binding.editButton.isVisible = true
|
||||||
binding.remoteFields.isVisible = false
|
binding.remoteFields.isVisible = false
|
||||||
binding.shareURLButton.isVisible = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TypedProfile.Type.Remote -> {
|
TypedProfile.Type.Remote -> {
|
||||||
binding.editButton.isVisible = false
|
binding.editButton.isVisible = false
|
||||||
binding.remoteFields.isVisible = true
|
binding.remoteFields.isVisible = true
|
||||||
binding.shareURLButton.isVisible = true
|
|
||||||
binding.remoteURL.text = profile.typed.remoteURL
|
binding.remoteURL.text = profile.typed.remoteURL
|
||||||
binding.lastUpdated.text =
|
binding.lastUpdated.text =
|
||||||
DateFormat.getDateTimeInstance().format(profile.typed.lastUpdated)
|
DateFormat.getDateTimeInstance().format(profile.typed.lastUpdated)
|
||||||
@@ -115,9 +113,6 @@ class EditProfileActivity : AbstractActivity() {
|
|||||||
binding.autoUpdate.addTextChangedListener(this@EditProfileActivity::updateAutoUpdate)
|
binding.autoUpdate.addTextChangedListener(this@EditProfileActivity::updateAutoUpdate)
|
||||||
binding.autoUpdateInterval.addTextChangedListener(this@EditProfileActivity::updateAutoUpdateInterval)
|
binding.autoUpdateInterval.addTextChangedListener(this@EditProfileActivity::updateAutoUpdateInterval)
|
||||||
binding.updateButton.setOnClickListener(this@EditProfileActivity::updateProfile)
|
binding.updateButton.setOnClickListener(this@EditProfileActivity::updateProfile)
|
||||||
binding.checkButton.setOnClickListener(this@EditProfileActivity::checkProfile)
|
|
||||||
binding.shareButton.setOnClickListener(this@EditProfileActivity::shareProfile)
|
|
||||||
binding.shareURLButton.setOnClickListener(this@EditProfileActivity::shareProfileURL)
|
|
||||||
binding.profileLayout.isVisible = true
|
binding.profileLayout.isVisible = true
|
||||||
binding.progressView.isVisible = false
|
binding.progressView.isVisible = false
|
||||||
}
|
}
|
||||||
@@ -208,24 +203,6 @@ class EditProfileActivity : AbstractActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkProfile(button: View) {
|
|
||||||
val binding = binding ?: return
|
|
||||||
binding.progressView.isVisible = true
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
|
||||||
delay(200L)
|
|
||||||
try {
|
|
||||||
Libbox.checkConfig(File(profile.typed.path).readText())
|
|
||||||
} catch (e: Exception) {
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
errorDialogBuilder(e).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
binding.progressView.isVisible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun shareProfile(button: View) {
|
private fun shareProfile(button: View) {
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
@@ -238,25 +215,4 @@ class EditProfileActivity : AbstractActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun shareProfileURL(button: View) {
|
|
||||||
try {
|
|
||||||
startActivity(
|
|
||||||
Intent.createChooser(
|
|
||||||
Intent(Intent.ACTION_SEND).setType("application/octet-stream")
|
|
||||||
.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
|
||||||
.putExtra(
|
|
||||||
Intent.EXTRA_STREAM,
|
|
||||||
Libbox.generateRemoteProfileImportLink(
|
|
||||||
profile.name,
|
|
||||||
profile.typed.remoteURL
|
|
||||||
)
|
|
||||||
),
|
|
||||||
getString(com.google.android.material.R.string.abc_shareactionprovider_share_with)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
errorDialogBuilder(e).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package io.nekohasekai.sfa.ui.shared
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import io.nekohasekai.sfa.databinding.FragmentQrcodeDialogBinding
|
||||||
|
|
||||||
|
class QRCodeDialog(private val bitmap: Bitmap) :
|
||||||
|
BottomSheetDialogFragment() {
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
val binding = FragmentQrcodeDialogBinding.inflate(inflater, container, false)
|
||||||
|
val behavior = BottomSheetBehavior.from(binding.qrcodeLayout)
|
||||||
|
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
binding.qrCode.setImageBitmap(bitmap)
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
12
app/src/main/res/drawable/ic_qr_code_2_24.xml
Normal file
12
app/src/main/res/drawable/ic_qr_code_2_24.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="#000000"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:width="24dp">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M15,21h-2v-2h2V21zM13,14h-2v5h2V14zM21,12h-2v4h2V12zM19,10h-2v2h2V10zM7,12H5v2h2V12zM5,10H3v2h2V10zM12,5h2V3h-2V5zM4.5,4.5v3h3v-3H4.5zM9,9H3V3h6V9zM4.5,16.5v3h3v-3H4.5zM9,21H3v-6h6V21zM16.5,4.5v3h3v-3H16.5zM21,9h-6V3h6V9zM19,19v-3l-4,0v2h2v3h4v-2H19zM17,12l-4,0v2h4V12zM13,10H7v2h2v2h2v-2h2V10zM14,9V7h-2V5h-2v4L14,9zM6.75,5.25h-1.5v1.5h1.5V5.25zM6.75,17.25h-1.5v1.5h1.5V17.25zM18.75,5.25h-1.5v1.5h1.5V5.25z" />
|
||||||
|
|
||||||
|
</vector>
|
||||||
12
app/src/main/res/drawable/ic_update_24.xml
Normal file
12
app/src/main/res/drawable/ic_update_24.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="#000000"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:width="24dp">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M21,10.12h-6.78l2.74,-2.82c-2.73,-2.7 -7.15,-2.8 -9.88,-0.1c-2.73,2.71 -2.73,7.08 0,9.79s7.15,2.71 9.88,0C18.32,15.65 19,14.08 19,12.1h2c0,1.98 -0.88,4.55 -2.64,6.29c-3.51,3.48 -9.21,3.48 -12.72,0c-3.5,-3.47 -3.53,-9.11 -0.02,-12.58s9.14,-3.47 12.65,0L21,3V10.12zM12.5,8v4.25l3.5,2.08l-0.72,1.21L11,13V8H12.5z" />
|
||||||
|
|
||||||
|
</vector>
|
||||||
@@ -140,29 +140,6 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/shareButton"
|
|
||||||
style="@style/Widget.Material3.Button.ElevatedButton"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:text="@string/profile_share" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/shareURLButton"
|
|
||||||
style="@style/Widget.Material3.Button.ElevatedButton"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:text="@string/profile_share_url" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/checkButton"
|
|
||||||
style="@style/Widget.Material3.Button.ElevatedButton"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:text="@string/profile_check" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
31
app/src/main/res/layout/fragment_qrcode_dialog.xml
Normal file
31
app/src/main/res/layout/fragment_qrcode_dialog.xml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout 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="match_parent">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/qrcode_layout"
|
||||||
|
style="@style/Widget.Material3.BottomSheet"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
|
||||||
|
|
||||||
|
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
|
||||||
|
android:id="@+id/drag_handle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:id="@+id/qr_code"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
@@ -14,21 +14,38 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingStart="16dp"
|
|
||||||
android:paddingEnd="4dp">
|
android:paddingEnd="4dp">
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/profile_name"
|
android:layout_weight="1"
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
android:layout_width="0dp"
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
android:orientation="vertical"
|
||||||
tools:text="Profile name" />
|
android:padding="10dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/profile_name"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?textAppearanceTitleMedium"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
tools:text="Profile name" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
tools:visibility="gone"
|
||||||
|
android:id="@+id/profile_last_updated"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:textAppearance="?textAppearanceBodySmall"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
tools:text="Last updated at now" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center_vertical|end"
|
android:gravity="top|end"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -9,6 +9,13 @@
|
|||||||
app:iconTintMode="src_in"
|
app:iconTintMode="src_in"
|
||||||
app:iconTint="?colorPrimary" />
|
app:iconTint="?colorPrimary" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_share_url"
|
||||||
|
android:icon="@drawable/ic_qr_code_2_24"
|
||||||
|
android:title="@string/profile_share_url"
|
||||||
|
app:iconTint="?colorPrimary"
|
||||||
|
app:iconTintMode="src_in" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_delete"
|
android:id="@+id/action_delete"
|
||||||
android:title="@string/menu_delete"
|
android:title="@string/menu_delete"
|
||||||
|
|||||||
@@ -26,9 +26,10 @@
|
|||||||
<string name="profile_edit_content">Edit Content</string>
|
<string name="profile_edit_content">Edit Content</string>
|
||||||
<string name="profile_check">Check</string>
|
<string name="profile_check">Check</string>
|
||||||
<string name="profile_share">Share</string>
|
<string name="profile_share">Share</string>
|
||||||
<string name="profile_share_url">Share URL</string>
|
<string name="profile_share_url">Share URL as QR Code</string>
|
||||||
<string name="profile_input_required">Required</string>
|
<string name="profile_input_required">Required</string>
|
||||||
<string name="profile_empty">Empty profiles</string>
|
<string name="profile_empty">Empty profiles</string>
|
||||||
|
<string name="profile_item_last_updated">Last Updated: %s</string>
|
||||||
<string name="profile_last_updated">Last Updated</string>
|
<string name="profile_last_updated">Last Updated</string>
|
||||||
<string name="profile_update">Update</string>
|
<string name="profile_update">Update</string>
|
||||||
<string name="profile_auto_update">Auto Update</string>
|
<string name="profile_auto_update">Auto Update</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user