Hook up new private chat screen redesign logic

This commit is contained in:
Niels Andriesse 2019-12-18 14:31:12 +01:00
parent bb976a4bff
commit 6dbe9b0ca9
8 changed files with 289 additions and 5 deletions

View File

@ -193,6 +193,8 @@ dependencies {
implementation("com.crashlytics.sdk.android:crashlytics:$crashlytics_version@aar") { implementation("com.crashlytics.sdk.android:crashlytics:$crashlytics_version@aar") {
transitive = true transitive = true
} }
implementation "com.jakewharton.rxbinding3:rxbinding:3.1.0"
implementation "com.github.tbruyelle:rxpermissions:0.10.2"
} }
def canonicalVersionCode = 23 def canonicalVersionCode = 23

View File

@ -0,0 +1,34 @@
<?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">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_horizontal"
android:layout_centerInParent="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/text"
android:textSize="@dimen/small_font_size"
android:text="Session needs camera access to scan QR codes" />
<Button
style="@style/MediumProminentOutlineButton"
android:id="@+id/grantCameraAccessButton"
android:layout_width="wrap_content"
android:layout_height="@dimen/medium_button_height"
android:layout_marginTop="@dimen/medium_spacing"
android:paddingLeft="@dimen/medium_spacing"
android:paddingRight="@dimen/medium_spacing"
android:text="Grant Camera Access" />
</LinearLayout>
</RelativeLayout>

View File

@ -0,0 +1,40 @@
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.thoughtcrime.securesms.components.camera.CameraView
android:id="@+id/cameraView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:camera="0" />
<LinearLayout
android:id="@+id/overlayView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="2" >
<org.thoughtcrime.securesms.components.ShapeScrim
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="0dp"/>
<TextView
android:id="@+id/descriptionTextView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="@dimen/very_large_spacing"
android:gravity="center"
android:background="@color/navigation_bar_background"
android:text="Users can share their QR code by going into their account settings and tapping &quot;Share QR Code&quot;"
android:textSize="@dimen/small_font_size"
android:textColor="@color/text" />
</LinearLayout>
</FrameLayout>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" />

View File

@ -1,16 +1,36 @@
package org.thoughtcrime.securesms.loki.redesign.activities package org.thoughtcrime.securesms.loki.redesign.activities
import android.Manifest
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle import android.os.Bundle
import android.support.v4.app.Fragment import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager import android.support.v4.app.FragmentManager
import android.support.v4.app.FragmentPagerAdapter import android.support.v4.app.FragmentPagerAdapter
import android.support.v4.content.ContextCompat
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast
import com.tbruyelle.rxpermissions2.RxPermissions
import kotlinx.android.synthetic.main.activity_new_private_chat.* import kotlinx.android.synthetic.main.activity_new_private_chat.*
import kotlinx.android.synthetic.main.fragment_enter_public_key.* import kotlinx.android.synthetic.main.fragment_enter_public_key.*
import network.loki.messenger.R import network.loki.messenger.R
import org.thoughtcrime.securesms.BaseActionBarActivity import org.thoughtcrime.securesms.BaseActionBarActivity
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.ScanQRCodeFragmentV2
import org.thoughtcrime.securesms.loki.redesign.fragments.ScanQRCodePlaceholderFragment
import org.thoughtcrime.securesms.loki.redesign.fragments.ScanQRCodePlaceholderFragmentDelegate
import org.thoughtcrime.securesms.qr.ScanListener
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation
class NewPrivateChatActivity : BaseActionBarActivity() { class NewPrivateChatActivity : BaseActionBarActivity() {
private val adapter = Adapter(supportFragmentManager) private val adapter = Adapter(supportFragmentManager)
@ -27,6 +47,25 @@ class NewPrivateChatActivity : BaseActionBarActivity() {
tabLayout.setupWithViewPager(viewPager) tabLayout.setupWithViewPager(viewPager)
} }
// endregion // endregion
// region Interaction
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 // region Adapter
@ -37,7 +76,11 @@ private class Adapter(manager: FragmentManager) : FragmentPagerAdapter(manager)
} }
override fun getItem(index: Int): Fragment { override fun getItem(index: Int): Fragment {
return EnterPublicKeyFragment() return when (index) {
0 -> EnterPublicKeyFragment()
1 -> ScanQRCodeWrapperFragment()
else -> throw IllegalStateException()
}
} }
override fun getPageTitle(index: Int): CharSequence? { override fun getPageTitle(index: Int): CharSequence? {
@ -50,7 +93,14 @@ private class Adapter(manager: FragmentManager) : FragmentPagerAdapter(manager)
} }
// endregion // endregion
// region Enter Public Key Fragment
class EnterPublicKeyFragment : Fragment() { class EnterPublicKeyFragment : 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 { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.fragment_enter_public_key, container, false) return inflater.inflate(R.layout.fragment_enter_public_key, container, false)
@ -58,6 +108,74 @@ class EnterPublicKeyFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
separatorView.title = "Test" publicKeyTextView.text = hexEncodedPublicKey
copyButton.setOnClickListener { copyPublicKey() }
shareButton.setOnClickListener { sharePublicKey() }
createPrivateChatButton.setOnClickListener { createPrivateChatIfPossible() }
} }
}
private fun copyPublicKey() {
val clipboard = activity!!.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("Session ID", hexEncodedPublicKey)
clipboard.primaryClip = clip
Toast.makeText(context!!, R.string.activity_register_public_key_copied_message, Toast.LENGTH_SHORT).show()
}
private fun sharePublicKey() {
val intent = Intent()
intent.action = Intent.ACTION_SEND
intent.putExtra(Intent.EXTRA_TEXT, hexEncodedPublicKey)
intent.type = "text/plain"
startActivity(intent)
}
private fun createPrivateChatIfPossible() {
val hexEncodedPublicKey = publicKeyEditText.text.trim().toString()
(activity!! as NewPrivateChatActivity).createPrivateChatIfPossible(hexEncodedPublicKey)
}
}
// endregion
// region Scan QR Code Wrapper Fragment
class ScanQRCodeWrapperFragment : Fragment(), ScanQRCodePlaceholderFragmentDelegate, ScanListener {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_scan_qr_code_wrapper, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
update()
}
private fun update() {
val fragment: Fragment
if (ContextCompat.checkSelfPermission(activity!!, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
val scanQRCodeFragment = ScanQRCodeFragmentV2()
scanQRCodeFragment.scanListener = this
fragment = scanQRCodeFragment
} else {
val scanQRCodePlaceholderFragment = ScanQRCodePlaceholderFragment()
scanQRCodePlaceholderFragment.delegate = this
fragment = scanQRCodePlaceholderFragment
}
val transaction = childFragmentManager.beginTransaction()
transaction.replace(R.id.fragmentContainer, fragment)
transaction.commit()
}
override fun requestCameraAccess() {
@SuppressWarnings("unused")
val unused = RxPermissions(this).request(Manifest.permission.CAMERA).subscribe { isGranted ->
if (isGranted) {
update()
}
}
}
override fun onQrDataFound(hexEncodedPublicKey: String) {
val activity = activity!! as NewPrivateChatActivity
activity.createPrivateChatIfPossible(hexEncodedPublicKey)
}
}
// endregion

View File

@ -0,0 +1,58 @@
package org.thoughtcrime.securesms.loki.redesign.fragments
import android.content.res.Configuration
import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import kotlinx.android.synthetic.main.fragment_scan_qr_code.*
import network.loki.messenger.R
import org.thoughtcrime.securesms.qr.ScanListener
import org.thoughtcrime.securesms.qr.ScanningThread
class ScanQRCodeFragmentV2 : Fragment() {
private val scanningThread = ScanningThread()
private var viewCreated = false
var scanListener: ScanListener? = null
set(value) { field = value; scanningThread.setScanListener(scanListener) }
override fun onCreateView(layoutInflater: LayoutInflater, viewGroup: ViewGroup?, bundle: Bundle?): View? {
return layoutInflater.inflate(R.layout.fragment_scan_qr_code_v2, viewGroup, false)
}
override fun onViewCreated(view: View, bundle: Bundle?) {
super.onViewCreated(view, bundle)
viewCreated = true
when (resources.configuration.orientation) {
Configuration.ORIENTATION_LANDSCAPE -> overlayView.orientation = LinearLayout.HORIZONTAL
else -> overlayView.orientation = LinearLayout.VERTICAL
}
}
override fun onResume() {
super.onResume()
scanningThread.setScanListener(scanListener)
cameraView.onResume()
cameraView.setPreviewCallback(scanningThread)
scanningThread.start()
}
override fun onPause() {
super.onPause()
this.cameraView.onPause()
this.scanningThread.stopScanning()
}
override fun onConfigurationChanged(newConfiguration: Configuration) {
super.onConfigurationChanged(newConfiguration)
this.cameraView.onPause()
when (newConfiguration.orientation) {
Configuration.ORIENTATION_LANDSCAPE -> overlayView.orientation = LinearLayout.HORIZONTAL
else -> overlayView.orientation = LinearLayout.VERTICAL
}
cameraView.onResume()
cameraView.setPreviewCallback(scanningThread)
}
}

View File

@ -0,0 +1,27 @@
package org.thoughtcrime.securesms.loki.redesign.fragments
import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import kotlinx.android.synthetic.main.fragment_scan_qr_code_placeholder.*
import network.loki.messenger.R
class ScanQRCodePlaceholderFragment: Fragment() {
var delegate: ScanQRCodePlaceholderFragmentDelegate? = null
override fun onCreateView(layoutInflater: LayoutInflater, viewGroup: ViewGroup?, bundle: Bundle?): View? {
return layoutInflater.inflate(R.layout.fragment_scan_qr_code_placeholder, viewGroup, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
grantCameraAccessButton.setOnClickListener { delegate?.requestCameraAccess() }
}
}
interface ScanQRCodePlaceholderFragmentDelegate {
fun requestCameraAccess()
}

View File

@ -13,7 +13,6 @@ import org.thoughtcrime.securesms.loki.getColorWithID
import org.thoughtcrime.securesms.loki.toPx import org.thoughtcrime.securesms.loki.toPx
class SeparatorView : RelativeLayout { class SeparatorView : RelativeLayout {
lateinit var title: CharSequence
private val path = Path() private val path = Path()
@ -21,7 +20,7 @@ class SeparatorView : RelativeLayout {
val result = Paint() val result = Paint()
result.style = Paint.Style.STROKE result.style = Paint.Style.STROKE
result.color = resources.getColorWithID(R.color.separator, context.theme) result.color = resources.getColorWithID(R.color.separator, context.theme)
result.strokeWidth = 2.0f result.strokeWidth = toPx(1, resources).toFloat()
result.isAntiAlias = true result.isAntiAlias = true
result result
}() }()