mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-11 18:54:21 +00:00
Update QrCodeActivity
This commit is contained in:
parent
ff64a8bc13
commit
18a4bcdbd9
@ -0,0 +1,6 @@
|
||||
package org.thoughtcrime.securesms.database
|
||||
|
||||
import android.content.Context
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
||||
|
||||
fun Context.threadDatabase() = DatabaseComponent.get(this).threadDatabase()
|
@ -43,6 +43,7 @@ import org.thoughtcrime.securesms.ui.components.OutlineButton
|
||||
import org.thoughtcrime.securesms.ui.contentDescription
|
||||
import org.thoughtcrime.securesms.ui.session_accent
|
||||
import org.thoughtcrime.securesms.util.setUpActionBarSessionLogo
|
||||
import org.thoughtcrime.securesms.util.start
|
||||
|
||||
class LandingActivity : BaseActionBarActivity() {
|
||||
|
||||
@ -105,7 +106,7 @@ class LandingActivity : BaseActionBarActivity() {
|
||||
.width(262.dp)
|
||||
.align(Alignment.CenterHorizontally)
|
||||
.contentDescription(R.string.AccessibilityId_restore_account_button)
|
||||
) { startLinkDeviceActivity() }
|
||||
) { start<LinkDeviceActivity>() }
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
BorderlessButton(
|
||||
text = stringResource(R.string.onboardingTosPrivacy),
|
||||
|
@ -1,8 +1,6 @@
|
||||
package org.thoughtcrime.securesms.onboarding
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.viewModels
|
||||
import androidx.camera.core.ExperimentalGetImage
|
||||
@ -160,10 +158,6 @@ fun RecoveryPassword(state: LinkDeviceState, onChange: (String) -> Unit = {}, on
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.startLinkDeviceActivity() {
|
||||
Intent(this, LinkDeviceActivity::class.java).let(::startActivity)
|
||||
}
|
||||
|
||||
class Analyzer(
|
||||
private val scanner: BarcodeScanner,
|
||||
private val onBarcodeScanned: (String) -> Unit
|
||||
|
@ -43,7 +43,7 @@ import org.thoughtcrime.securesms.ui.ThemeResPreviewParameterProvider
|
||||
import org.thoughtcrime.securesms.ui.classicDarkColors
|
||||
import org.thoughtcrime.securesms.ui.colorDestructive
|
||||
import org.thoughtcrime.securesms.ui.components.OutlineButton
|
||||
import org.thoughtcrime.securesms.ui.components.QrImageCard
|
||||
import org.thoughtcrime.securesms.ui.components.QrImage
|
||||
import org.thoughtcrime.securesms.ui.components.SmallButtons
|
||||
import org.thoughtcrime.securesms.ui.components.TemporaryStateButton
|
||||
import org.thoughtcrime.securesms.ui.contentDescription
|
||||
@ -161,7 +161,7 @@ fun RecoveryPasswordCell(seed: String, copySeed:() -> Unit = {}) {
|
||||
showQr,
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||
) {
|
||||
QrImageCard(
|
||||
QrImage(
|
||||
seed,
|
||||
modifier = Modifier.padding(vertical = 24.dp),
|
||||
contentDescription = "QR code of your recovery password",
|
||||
|
@ -1,141 +1,96 @@
|
||||
package org.thoughtcrime.securesms.preferences
|
||||
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentPagerAdapter
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import network.loki.messenger.R
|
||||
import network.loki.messenger.databinding.ActivityQrCodeBinding
|
||||
import network.loki.messenger.databinding.FragmentViewMyQrCodeBinding
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsignal.utilities.PublicKeyValidation
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
||||
import org.thoughtcrime.securesms.util.FileProviderUtil
|
||||
import org.thoughtcrime.securesms.util.QRCodeUtilities
|
||||
import org.thoughtcrime.securesms.util.ScanQRCodeWrapperFragment
|
||||
import org.thoughtcrime.securesms.database.threadDatabase
|
||||
import org.thoughtcrime.securesms.ui.components.MaybeScanQrCode
|
||||
import org.thoughtcrime.securesms.ui.components.QrImage
|
||||
import org.thoughtcrime.securesms.ui.components.SessionTabRow
|
||||
import org.thoughtcrime.securesms.ui.setComposeContent
|
||||
import org.thoughtcrime.securesms.ui.small
|
||||
import org.thoughtcrime.securesms.util.ScanQRCodeWrapperFragmentDelegate
|
||||
import org.thoughtcrime.securesms.util.toPx
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import org.thoughtcrime.securesms.util.start
|
||||
|
||||
private val TITLES = listOf(R.string.view, R.string.scan)
|
||||
|
||||
class QRCodeActivity : PassphraseRequiredActionBarActivity(), ScanQRCodeWrapperFragmentDelegate {
|
||||
private lateinit var binding: ActivityQrCodeBinding
|
||||
private val adapter = QRCodeActivityAdapter(this)
|
||||
|
||||
// region Lifecycle
|
||||
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
|
||||
super.onCreate(savedInstanceState, isReady)
|
||||
binding = ActivityQrCodeBinding.inflate(layoutInflater)
|
||||
// Set content view
|
||||
setContentView(binding.root)
|
||||
// Set title
|
||||
supportActionBar!!.title = resources.getString(R.string.activity_qr_code_title)
|
||||
// Set up view pager
|
||||
binding.viewPager.adapter = adapter
|
||||
binding.tabLayout.setupWithViewPager(binding.viewPager)
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Interaction
|
||||
override fun handleQRCodeScanned(hexEncodedPublicKey: String) {
|
||||
createPrivateChatIfPossible(hexEncodedPublicKey)
|
||||
setComposeContent {
|
||||
Tabs(TextSecurePreferences.getLocalNumber(this)!!)
|
||||
}
|
||||
}
|
||||
|
||||
fun createPrivateChatIfPossible(hexEncodedPublicKey: String) {
|
||||
if (!PublicKeyValidation.isValid(hexEncodedPublicKey)) { return Toast.makeText(this, R.string.invalid_session_id, Toast.LENGTH_SHORT).show() }
|
||||
val recipient = Recipient.from(this, Address.fromSerialized(hexEncodedPublicKey), false)
|
||||
val intent = Intent(this, ConversationActivityV2::class.java)
|
||||
intent.putExtra(ConversationActivityV2.ADDRESS, recipient.address)
|
||||
intent.setDataAndType(getIntent().data, getIntent().type)
|
||||
val existingThread = DatabaseComponent.get(this).threadDatabase().getThreadIdIfExistsFor(recipient)
|
||||
intent.putExtra(ConversationActivityV2.THREAD_ID, existingThread)
|
||||
startActivity(intent)
|
||||
override fun handleQRCodeScanned(string: String) {
|
||||
if (!PublicKeyValidation.isValid(string)) {
|
||||
return Toast.makeText(this, R.string.invalid_session_id, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
val recipient = Recipient.from(this, Address.fromSerialized(string), false)
|
||||
start<ConversationActivityV2> {
|
||||
putExtra(ConversationActivityV2.ADDRESS, recipient.address)
|
||||
setDataAndType(intent.data, intent.type)
|
||||
val existingThread = threadDatabase().getThreadIdIfExistsFor(recipient)
|
||||
putExtra(ConversationActivityV2.THREAD_ID, existingThread)
|
||||
}
|
||||
finish()
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
|
||||
// region Adapter
|
||||
private class QRCodeActivityAdapter(val activity: QRCodeActivity) : FragmentPagerAdapter(activity.supportFragmentManager) {
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun Tabs(sessionId: String) {
|
||||
val pagerState = rememberPagerState { TITLES.size }
|
||||
|
||||
override fun getCount(): Int {
|
||||
return 2
|
||||
}
|
||||
|
||||
override fun getItem(index: Int): Fragment {
|
||||
return when (index) {
|
||||
0 -> ViewMyQRCodeFragment()
|
||||
1 -> {
|
||||
val result = ScanQRCodeWrapperFragment()
|
||||
result.delegate = activity
|
||||
result.message = activity.resources.getString(R.string.activity_qr_code_view_scan_qr_code_explanation)
|
||||
result
|
||||
Column {
|
||||
SessionTabRow(pagerState, TITLES)
|
||||
HorizontalPager(
|
||||
state = pagerState,
|
||||
modifier = Modifier.weight(1f)
|
||||
) { page ->
|
||||
when (TITLES[page]) {
|
||||
R.string.view -> QrPage(sessionId)
|
||||
R.string.scan -> MaybeScanQrCode()
|
||||
}
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPageTitle(index: Int): CharSequence? {
|
||||
return when (index) {
|
||||
0 -> activity.resources.getString(R.string.activity_qr_code_view_my_qr_code_tab_title)
|
||||
1 -> activity.resources.getString(R.string.activity_qr_code_view_scan_qr_code_tab_title)
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region View My QR Code Fragment
|
||||
class ViewMyQRCodeFragment : Fragment() {
|
||||
private lateinit var binding: FragmentViewMyQrCodeBinding
|
||||
@Composable
|
||||
fun QrPage(string: String) {
|
||||
Column(modifier = Modifier.padding(horizontal = 32.dp).fillMaxSize()) {
|
||||
QrImage(
|
||||
string = string,
|
||||
contentDescription = "Your session id",
|
||||
modifier = Modifier.padding(top = 32.dp, bottom = 12.dp),
|
||||
icon = R.drawable.session
|
||||
)
|
||||
|
||||
private val hexEncodedPublicKey: String
|
||||
get() {
|
||||
return TextSecurePreferences.getLocalNumber(requireContext())!!
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
binding = FragmentViewMyQrCodeBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val size = toPx(280, resources)
|
||||
val qrCode = QRCodeUtilities.encode(hexEncodedPublicKey, size, false, false)
|
||||
binding.qrCodeImageView.setImageBitmap(qrCode)
|
||||
// val explanation = SpannableStringBuilder("This is your unique public QR code. Other users can scan this to start a conversation with you.")
|
||||
// explanation.setSpan(StyleSpan(Typeface.BOLD), 8, 34, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
binding.explanationTextView.text = resources.getString(R.string.fragment_view_my_qr_code_explanation)
|
||||
binding.shareButton.setOnClickListener { shareQRCode() }
|
||||
}
|
||||
|
||||
private fun shareQRCode() {
|
||||
val directory = requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES)
|
||||
val fileName = "$hexEncodedPublicKey.png"
|
||||
val file = File(directory, fileName)
|
||||
file.createNewFile()
|
||||
val fos = FileOutputStream(file)
|
||||
val size = toPx(280, resources)
|
||||
val qrCode = QRCodeUtilities.encode(hexEncodedPublicKey, size, false, false)
|
||||
qrCode.compress(Bitmap.CompressFormat.PNG, 100, fos)
|
||||
fos.flush()
|
||||
fos.close()
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
intent.putExtra(Intent.EXTRA_STREAM, FileProviderUtil.getUriFor(requireActivity(), file))
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
intent.type = "image/png"
|
||||
startActivity(Intent.createChooser(intent, resources.getString(R.string.fragment_view_my_qr_code_share_title)))
|
||||
Text(
|
||||
text = "This is your Account ID. Other users can scan it to start a conversation with you.",
|
||||
textAlign = TextAlign.Center,
|
||||
style = MaterialTheme.typography.small
|
||||
)
|
||||
}
|
||||
}
|
||||
// endregion
|
@ -20,16 +20,12 @@ import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Toast
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.interaction.InteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.material.Card
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
@ -40,18 +36,13 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import network.loki.messenger.BuildConfig
|
||||
@ -184,7 +175,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_qr_code -> {
|
||||
showQRCode()
|
||||
push<QRCodeActivity>()
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
@ -325,11 +316,6 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
return true
|
||||
}
|
||||
|
||||
private fun showQRCode() {
|
||||
val intent = Intent(this, QRCodeActivity::class.java)
|
||||
push(intent)
|
||||
}
|
||||
|
||||
private fun showEditProfilePictureUI() {
|
||||
showSessionDialog {
|
||||
title(R.string.activity_settings_set_display_picture)
|
||||
|
11
app/src/main/java/org/thoughtcrime/securesms/ui/Util.kt
Normal file
11
app/src/main/java/org/thoughtcrime/securesms/ui/Util.kt
Normal file
@ -0,0 +1,11 @@
|
||||
package org.thoughtcrime.securesms.ui
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
|
||||
fun Activity.setComposeContent(content: @Composable () -> Unit) {
|
||||
ComposeView(this)
|
||||
.apply { setContent { AppTheme { content() } } }
|
||||
.let(::setContentView)
|
||||
}
|
@ -58,13 +58,6 @@ typealias CameraPreview = androidx.camera.core.Preview
|
||||
|
||||
private const val TAG = "NewMessageFragment"
|
||||
|
||||
@Composable
|
||||
fun MaybeScanQrCode(errors: Flow<String> = emptyFlow()) {
|
||||
LocalContext.current.run {
|
||||
MaybeScanQrCode(onScan = {})
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Composable
|
||||
fun MaybeScanQrCode(
|
||||
|
@ -2,17 +2,15 @@ package org.thoughtcrime.securesms.ui.components
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.Card
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
@ -34,21 +32,12 @@ import org.thoughtcrime.securesms.ui.LocalOnLightCell
|
||||
import org.thoughtcrime.securesms.util.QRCodeUtilities
|
||||
|
||||
@Composable
|
||||
fun QrImageCard(
|
||||
fun QrImage(
|
||||
string: String,
|
||||
contentDescription: String,
|
||||
modifier: Modifier = Modifier,
|
||||
icon: Int = R.drawable.session_shield
|
||||
) {
|
||||
Card(
|
||||
backgroundColor = LocalLightCell.current,
|
||||
elevation = 0.dp,
|
||||
modifier = modifier
|
||||
) { QrImage(string, contentDescription, icon) }
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun QrImage(string: String, contentDescription: String, icon: Int = R.drawable.session_shield) {
|
||||
var bitmap: Bitmap? by remember {
|
||||
mutableStateOf(null)
|
||||
}
|
||||
@ -56,42 +45,57 @@ fun QrImage(string: String, contentDescription: String, icon: Int = R.drawable.s
|
||||
val scope = rememberCoroutineScope()
|
||||
LaunchedEffect(string) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
bitmap = QRCodeUtilities.encode(string, 400)
|
||||
bitmap = QRCodeUtilities.encode(string, 400).also {
|
||||
for (y in 150 until 250) {
|
||||
for (x in 150 until 250) {
|
||||
it.setPixel(x, y, 0x00000000)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1f)
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
visible = bitmap != null,
|
||||
enter = scaleIn()
|
||||
@Composable
|
||||
fun content(modifier: Modifier = Modifier) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1f)
|
||||
) {
|
||||
bitmap?.let {
|
||||
Image(
|
||||
bitmap = it.asImageBitmap(),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1f),
|
||||
contentDescription = contentDescription,
|
||||
colorFilter = ColorFilter.tint(LocalOnLightCell.current)
|
||||
)
|
||||
AnimatedVisibility(
|
||||
visible = bitmap != null,
|
||||
enter = fadeIn(),
|
||||
) {
|
||||
bitmap?.let {
|
||||
Image(
|
||||
bitmap = it.asImageBitmap(),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1f),
|
||||
contentDescription = contentDescription,
|
||||
colorFilter = ColorFilter.tint(LocalOnLightCell.current)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Icon(
|
||||
painter = painterResource(id = icon),
|
||||
contentDescription = "",
|
||||
tint = LocalOnLightCell.current,
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(60.dp)
|
||||
)
|
||||
}
|
||||
|
||||
Icon(
|
||||
painter = painterResource(id = icon),
|
||||
contentDescription = "",
|
||||
tint = LocalOnLightCell.current,
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.width(46.dp)
|
||||
.height(56.dp)
|
||||
.background(color = LocalLightCell.current)
|
||||
.padding(horizontal = 3.dp, vertical = 1.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (MaterialTheme.colors.isLight) {
|
||||
content(modifier)
|
||||
} else {
|
||||
Card(
|
||||
backgroundColor = LocalLightCell.current,
|
||||
elevation = 0.dp,
|
||||
modifier = modifier
|
||||
) { content() }
|
||||
}
|
||||
}
|
||||
|
@ -102,6 +102,7 @@ data class ThemeState (
|
||||
val followSystem: Boolean
|
||||
)
|
||||
|
||||
inline fun <reified T: Activity> Context.start() = Intent(this, T::class.java).also(::startActivity)
|
||||
inline fun <reified T: Activity> Activity.show() = Intent(this, T::class.java).also(::startActivity).also { overridePendingTransition(R.anim.slide_from_bottom, R.anim.fade_scale_out) }
|
||||
inline fun <reified T: Activity> Activity.push() = Intent(this, T::class.java).also(::startActivity).also { overridePendingTransition(R.anim.slide_from_right, R.anim.fade_scale_out) }
|
||||
inline fun <reified T: Activity> Context.start() = Intent(this, T::class.java).also(::startActivity)
|
||||
inline fun <reified T: Activity> Context.start(modify: Intent.() -> Unit) = Intent(this, T::class.java).also(modify).also(::startActivity)
|
||||
|
11
app/src/main/res/drawable/session.xml
Normal file
11
app/src/main/res/drawable/session.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="52dp"
|
||||
android:height="63dp"
|
||||
android:viewportWidth="52"
|
||||
android:viewportHeight="63">
|
||||
<path
|
||||
android:pathData="M43.22,31.788L32.683,25.284H39.825C42.812,25.284 45.676,23.961 47.789,21.608C49.901,19.254 51.087,16.062 51.087,12.734C51.087,9.405 49.901,6.213 47.789,3.86C45.676,1.506 42.812,0.184 39.825,0.184L14.888,0.184C11.148,0.189 7.562,1.847 4.917,4.794C2.272,7.742 0.784,11.738 0.779,15.906C0.781,18.943 1.512,21.925 2.897,24.542C4.282,27.159 6.27,29.315 8.654,30.787L19.193,37.293H12.042C10.552,37.274 9.073,37.584 7.692,38.206C6.31,38.828 5.053,39.75 3.994,40.917C2.934,42.084 2.093,43.474 1.518,45.006C0.944,46.538 0.648,48.182 0.648,49.842C0.648,51.503 0.944,53.146 1.518,54.679C2.093,56.211 2.934,57.6 3.994,58.768C5.053,59.935 6.31,60.856 7.692,61.478C9.073,62.1 10.552,62.41 12.042,62.391H36.979C40.719,62.387 44.305,60.729 46.951,57.781C49.596,54.834 51.083,50.838 51.087,46.67C51.087,43.633 50.357,40.651 48.973,38.034C47.59,35.418 45.604,33.261 43.22,31.788ZM10.338,27.386C8.541,26.275 7.035,24.659 5.971,22.7C4.907,20.74 4.322,18.504 4.273,16.215C4.132,9.538 9.163,4.072 15.156,4.072H39.599C43.781,4.072 47.381,7.638 47.589,12.297C47.64,13.47 47.478,14.642 47.111,15.742C46.745,16.842 46.181,17.848 45.455,18.699C44.729,19.549 43.856,20.226 42.888,20.69C41.92,21.153 40.878,21.392 39.825,21.393H25.748C25.336,21.396 24.941,21.58 24.65,21.906C24.359,22.233 24.196,22.674 24.197,23.134V35.937L10.338,27.386ZM36.71,58.503H12.267C8.088,58.503 4.485,54.937 4.28,50.279C4.228,49.107 4.39,47.935 4.756,46.835C5.123,45.735 5.686,44.729 6.412,43.878C7.138,43.027 8.011,42.35 8.979,41.886C9.946,41.423 10.988,41.183 12.042,41.182H26.12C26.325,41.182 26.528,41.137 26.717,41.049C26.906,40.962 27.078,40.834 27.223,40.672C27.368,40.511 27.482,40.319 27.561,40.108C27.639,39.897 27.679,39.671 27.679,39.443V26.639L41.528,35.19C43.327,36.301 44.834,37.917 45.898,39.879C46.962,41.84 47.547,44.078 47.595,46.369C47.736,53.037 42.705,58.503 36.71,58.503Z"
|
||||
android:strokeWidth="0.3"
|
||||
android:fillColor="#000000"
|
||||
android:strokeColor="#000000"/>
|
||||
</vector>
|
@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/viewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tabLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/tab_bar_height" />
|
||||
|
||||
</androidx.viewpager.widget.ViewPager>
|
@ -1094,6 +1094,8 @@
|
||||
<string name="hide">Hide</string>
|
||||
<string name="recoveryPasswordHideRecoveryPassword">Hide Recovery Password</string>
|
||||
<string name="qrView">View QR</string>
|
||||
<string name="view">View</string>
|
||||
<string name="scan">Scan</string>
|
||||
<string name="recoveryPasswordView">View Password</string>
|
||||
<string name="recoveryPasswordHideRecoveryPasswordDescription">Permanently hide your recovery password on this device.</string>
|
||||
<string name="conversationsNone">You don\'t have any conversations yet</string>
|
||||
|
Loading…
Reference in New Issue
Block a user