Implement QR code screen redesign

This commit is contained in:
Niels Andriesse 2020-01-06 16:05:57 +11:00
parent c76335150c
commit b56d19e865
9 changed files with 278 additions and 3 deletions

View File

@ -153,6 +153,9 @@
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.SettingsActivity"
android:launchMode="singleTask" />
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.QRCodeActivity"
android:launchMode="singleTask" />
<!-- Session -->
<activity android:name="org.thoughtcrime.securesms.loki.LinkedDevicesActivity" />
<activity

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.design.widget.TabLayout
style="@style/Session.DarkTabLayout"
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="@dimen/tab_bar_height" />
</android.support.v4.view.ViewPager>

View File

@ -115,6 +115,22 @@
android:layout_height="1px"
android:background="@color/separator" />
<TextView
android:id="@+id/chatsButton"
android:layout_width="match_parent"
android:layout_height="@dimen/setting_button_height"
android:background="@drawable/setting_button_background"
android:textColor="@color/text"
android:textSize="@dimen/medium_font_size"
android:textStyle="bold"
android:gravity="center"
android:text="Chats" />
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/separator" />
<TextView
android:id="@+id/linkedDevicesButton"
android:layout_width="match_parent"

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/default_session_background" >
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none">
<LinearLayout
android:id="@+id/contentView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/very_large_spacing"
android:layout_marginTop="@dimen/medium_spacing"
android:layout_marginRight="@dimen/very_large_spacing"
android:textSize="@dimen/massive_font_size"
android:textColor="@color/text"
android:textStyle="bold"
android:textAlignment="center"
android:text="Scan Me" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/very_large_spacing"
android:layout_marginTop="@dimen/small_spacing"
android:layout_marginRight="@dimen/very_large_spacing"
android:gravity="center">
<ImageView
android:id="@+id/qrCodeImageView"
android:layout_width="320dp"
android:layout_height="320dp" />
</RelativeLayout>
<TextView
android:id="@+id/explanationTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/very_large_spacing"
android:layout_marginTop="20dp"
android:layout_marginRight="@dimen/very_large_spacing"
android:textSize="@dimen/medium_font_size"
android:textColor="@color/text"
android:fontFamily="@font/space_mono_regular"
android:textAlignment="center"
android:text="This is your unique public QR code. Other users may scan this in order to begin a conversation with you." />
<Button
style="@style/MediumUnimportantOutlineButton"
android:id="@+id/shareButton"
android:layout_width="match_parent"
android:layout_height="@dimen/medium_button_height"
android:layout_marginLeft="90dp"
android:layout_marginTop="28dp"
android:layout_marginRight="90dp"
android:layout_marginBottom="@dimen/medium_spacing"
android:text="Share" />
</LinearLayout>
</ScrollView>
</RelativeLayout>

View File

@ -0,0 +1,131 @@
package org.thoughtcrime.securesms.loki.redesign.activities
import android.content.Intent
import android.graphics.Typeface
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentPagerAdapter
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.style.StyleSpan
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_qr_code.*
import kotlinx.android.synthetic.main.fragment_view_my_qr_code.*
import network.loki.messenger.R
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.conversation.ConversationActivity
import org.thoughtcrime.securesms.database.Address
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.ThreadDatabase
import org.thoughtcrime.securesms.loki.redesign.fragments.ScanQRCodeWrapperFragment
import org.thoughtcrime.securesms.loki.redesign.fragments.ScanQRCodeWrapperFragmentDelegate
import org.thoughtcrime.securesms.loki.redesign.utilities.QRCodeUtilities
import org.thoughtcrime.securesms.loki.toPx
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation
class QRCodeActivity : PassphraseRequiredActionBarActivity(), ScanQRCodeWrapperFragmentDelegate {
private val adapter = QRCodeActivityAdapter(this)
// region Lifecycle
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
super.onCreate(savedInstanceState, isReady)
// Set content view
setContentView(R.layout.activity_qr_code)
// Set title
supportActionBar!!.title = "QR Code"
// Set up view pager
viewPager.adapter = adapter
tabLayout.setupWithViewPager(viewPager)
}
// endregion
// region Interaction
override fun handleQRCodeScanned(hexEncodedPublicKey: String) {
createPrivateChatIfPossible(hexEncodedPublicKey)
}
fun createPrivateChatIfPossible(hexEncodedPublicKey: String) {
if (!PublicKeyValidation.isValid(hexEncodedPublicKey)) { return Toast.makeText(this, "Invalid Session ID", Toast.LENGTH_SHORT).show() }
val masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(this)
val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(this)
val targetHexEncodedPublicKey = if (hexEncodedPublicKey == masterHexEncodedPublicKey) userHexEncodedPublicKey else hexEncodedPublicKey
val recipient = Recipient.from(this, Address.fromSerialized(targetHexEncodedPublicKey), true)
val intent = Intent(this, ConversationActivity::class.java)
intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.address)
intent.putExtra(ConversationActivity.TEXT_EXTRA, getIntent().getStringExtra(ConversationActivity.TEXT_EXTRA))
intent.setDataAndType(getIntent().data, getIntent().type)
val existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient)
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, existingThread)
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT)
startActivity(intent)
finish()
}
// endregion
}
// region Adapter
private class QRCodeActivityAdapter(val activity: QRCodeActivity) : FragmentPagerAdapter(activity.supportFragmentManager) {
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 = "Scan someone\'s QR code to start a conversation with them"
result
}
else -> throw IllegalStateException()
}
}
override fun getPageTitle(index: Int): CharSequence? {
return when (index) {
0 -> "View My QR Code"
1 -> "Scan QR Code"
else -> throw IllegalStateException()
}
}
}
// endregion
// region View My QR Code Fragment
class ViewMyQRCodeFragment : Fragment() {
private val hexEncodedPublicKey: String
get() {
val masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context!!)
val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context!!)
return masterHexEncodedPublicKey ?: userHexEncodedPublicKey
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.fragment_view_my_qr_code, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val size = toPx(240, resources)
val qrCode = QRCodeUtilities.encode(hexEncodedPublicKey, size)
qrCodeImageView.setImageBitmap(qrCode)
val explanation = SpannableStringBuilder("This is your unique public QR code. Other users may scan this in order to begin a conversation with you.")
explanation.setSpan(StyleSpan(Typeface.BOLD), 8, 34, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
explanationTextView.text = explanation
shareButton.setOnClickListener { shareQRCode() }
}
private fun shareQRCode() {
// TODO: Implement
}
}
// endregion

View File

@ -12,6 +12,7 @@ import kotlinx.android.synthetic.main.activity_settings.*
import network.loki.messenger.R
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.loki.redesign.utilities.push
import org.thoughtcrime.securesms.mms.GlideApp
import org.thoughtcrime.securesms.mms.GlideRequests
import org.thoughtcrime.securesms.util.TextSecurePreferences
@ -67,7 +68,8 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
}
private fun showQRCode() {
// TODO: Implement
val intent = Intent(this, QRCodeActivity::class.java)
push(intent)
}
private fun copyPublicKey() {

View File

@ -35,7 +35,11 @@ class ScanQRCodeFragmentV2 : Fragment() {
super.onResume()
cameraView.onResume()
cameraView.setPreviewCallback(scanningThread)
scanningThread.start()
try {
scanningThread.start()
} catch (exception: Exception) {
// Do nothing
}
scanningThread.setScanListener(scanListener)
}

View File

@ -0,0 +1,31 @@
package org.thoughtcrime.securesms.loki.redesign.utilities
import android.graphics.Bitmap
import android.graphics.Color
import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.WriterException
import com.google.zxing.qrcode.QRCodeWriter
object QRCodeUtilities {
fun encode(data: String, size: Int, hasTransparentBackground: Boolean = true): Bitmap {
try {
val hints = hashMapOf( EncodeHintType.MARGIN to 1 )
val result = QRCodeWriter().encode(data, BarcodeFormat.QR_CODE, size, size, hints)
val bitmap = Bitmap.createBitmap(result.width, result.height, Bitmap.Config.ARGB_8888)
for (y in 0 until result.height) {
for (x in 0 until result.width) {
if (result.get(x, y)) {
bitmap.setPixel(x, y, Color.WHITE)
} else if (!hasTransparentBackground) {
bitmap.setPixel(x, y, Color.BLACK)
}
}
}
return bitmap
} catch (e: WriterException) {
return Bitmap.createBitmap(512, 512, Bitmap.Config.ARGB_8888)
}
}
}

View File

@ -15,7 +15,7 @@ import org.thoughtcrime.securesms.loki.JazzIdenticonDrawable
import org.thoughtcrime.securesms.mms.GlideRequests
import org.thoughtcrime.securesms.recipients.Recipient
// TODO: Look into a better way of handling different sizes
// TODO: Look into a better way of handling different sizes. Maybe an enum (with associated values) encapsulating the different modes?
class ProfilePictureView : RelativeLayout {
lateinit var glide: GlideRequests