Implement join public chat screen redesign

This commit is contained in:
Niels Andriesse 2019-12-18 15:25:23 +01:00
parent 6dbe9b0ca9
commit 95dc4e6590
12 changed files with 281 additions and 66 deletions

View File

@ -143,8 +143,12 @@
android:name="org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity" android:name="org.thoughtcrime.securesms.loki.redesign.activities.HomeActivity"
android:launchMode="singleTask" /> android:launchMode="singleTask" />
<activity <activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.NewPrivateChatActivity" android:name="org.thoughtcrime.securesms.loki.redesign.activities.CreatePrivateChatActivity"
android:launchMode="singleTask" /> android:launchMode="singleTask" />
<activity
android:name="org.thoughtcrime.securesms.loki.redesign.activities.JoinPublicChatActivity"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize" />
<!-- Session --> <!-- Session -->
<activity android:name="org.thoughtcrime.securesms.loki.LinkedDevicesActivity" /> <activity android:name="org.thoughtcrime.securesms.loki.LinkedDevicesActivity" />
<activity <activity

View File

@ -0,0 +1,4 @@
<vector android:height="24dp" android:viewportHeight="25"
android:viewportWidth="25" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FFFFFF" android:pathData="M12.5,0.61C5.94,0.61 0.61,5.94 0.61,12.5S5.94,24.39 12.5,24.39s11.89,-5.34 11.89,-11.89S19.06,0.61 12.5,0.61zM2.35,13.35h3.41c0.05,1.35 0.22,2.64 0.5,3.82H3.45C2.85,16.01 2.46,14.72 2.35,13.35zM13.35,6.13V2.47c1.22,0.44 2.3,1.78 3.07,3.66H13.35zM16.98,7.83c0.31,1.17 0.51,2.46 0.57,3.82h-4.19V7.83H16.98zM11.65,2.47v3.66H8.58C9.35,4.24 10.43,2.9 11.65,2.47zM11.65,7.83v3.82H7.46C7.52,10.29 7.72,9 8.02,7.83H11.65zM5.76,11.65H2.35c0.11,-1.37 0.5,-2.66 1.1,-3.82h2.81C5.98,9.01 5.81,10.3 5.76,11.65zM7.46,13.35h4.19v3.82H8.02C7.72,16 7.52,14.71 7.46,13.35zM11.65,18.87v3.66c-1.22,-0.44 -2.3,-1.78 -3.07,-3.66H11.65zM13.35,22.53v-3.66h3.07C15.65,20.76 14.57,22.1 13.35,22.53zM13.35,17.17v-3.82h4.19c-0.06,1.36 -0.26,2.65 -0.57,3.82H13.35zM19.24,13.35h3.41c-0.11,1.37 -0.5,2.66 -1.1,3.82h-2.81C19.02,15.99 19.19,14.7 19.24,13.35zM19.24,11.65c-0.05,-1.35 -0.22,-2.64 -0.5,-3.82h2.81c0.6,1.16 0.99,2.45 1.1,3.82H19.24zM20.45,6.13h-2.21c-0.38,-1.08 -0.86,-2.05 -1.42,-2.85C18.23,3.94 19.47,4.92 20.45,6.13zM8.18,3.28c-0.56,0.8 -1.03,1.77 -1.42,2.85H4.56C5.53,4.92 6.77,3.94 8.18,3.28zM4.55,18.87h2.21c0.38,1.08 0.86,2.05 1.42,2.85C6.77,21.06 5.53,20.08 4.55,18.87zM16.82,21.72c0.56,-0.8 1.03,-1.77 1.42,-2.85h2.21C19.47,20.08 18.23,21.06 16.82,21.72z"/>
</vector>

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

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/contentView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/default_session_background"
android:orientation="vertical">
<EditText
style="@style/SessionEditText"
android:id="@+id/chatURLEditText"
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:hint="https://chat.lokinet.org" />
<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/small_font_size"
android:textColor="@color/text"
android:alpha="0.6"
android:textAlignment="center"
android:text="Enter the URL of the public chat you'd like to join" />
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
<Button
style="@style/MediumProminentOutlineButton"
android:id="@+id/joinPublicChatButton"
android:layout_width="match_parent"
android:layout_height="@dimen/medium_button_height"
android:layout_marginLeft="90dp"
android:layout_marginRight="90dp"
android:layout_marginBottom="@dimen/medium_spacing"
android:text="Next" />
</LinearLayout>

View File

@ -24,7 +24,7 @@
android:layout_height="0dp"/> android:layout_height="0dp"/>
<TextView <TextView
android:id="@+id/descriptionTextView" android:id="@+id/messageTextView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" android:layout_weight="1"

12
res/menu/menu_home.xml Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/joinPublicChatItem"
android:title="Join Public Chat"
android:icon="@drawable/ic_globe"
app:showAsAction="always" />
</menu>

View File

@ -1,22 +1,17 @@
package org.thoughtcrime.securesms.loki.redesign.activities package org.thoughtcrime.securesms.loki.redesign.activities
import android.Manifest
import android.content.ClipData import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
import android.content.Context import android.content.Context
import android.content.Intent 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.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 android.widget.Toast
import com.tbruyelle.rxpermissions2.RxPermissions import kotlinx.android.synthetic.main.activity_create_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
@ -24,22 +19,20 @@ import org.thoughtcrime.securesms.conversation.ConversationActivity
import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.Address
import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.ThreadDatabase import org.thoughtcrime.securesms.database.ThreadDatabase
import org.thoughtcrime.securesms.loki.redesign.fragments.ScanQRCodeFragmentV2 import org.thoughtcrime.securesms.loki.redesign.fragments.ScanQRCodeWrapperFragment
import org.thoughtcrime.securesms.loki.redesign.fragments.ScanQRCodePlaceholderFragment import org.thoughtcrime.securesms.loki.redesign.fragments.ScanQRCodeWrapperFragmentDelegate
import org.thoughtcrime.securesms.loki.redesign.fragments.ScanQRCodePlaceholderFragmentDelegate
import org.thoughtcrime.securesms.qr.ScanListener
import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation
class NewPrivateChatActivity : BaseActionBarActivity() { class CreatePrivateChatActivity : BaseActionBarActivity(), ScanQRCodeWrapperFragmentDelegate {
private val adapter = Adapter(supportFragmentManager) private val adapter = CreatePrivateChatActivityAdapter(this)
// region Lifecycle // region Lifecycle
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
// Set content view // Set content view
setContentView(R.layout.activity_new_private_chat) setContentView(R.layout.activity_create_private_chat)
// Set title // Set title
supportActionBar!!.title = "New Conversation" supportActionBar!!.title = "New Conversation"
// Set up view pager // Set up view pager
@ -49,6 +42,10 @@ class NewPrivateChatActivity : BaseActionBarActivity() {
// endregion // endregion
// region Interaction // region Interaction
override fun handleQRCodeScanned(hexEncodedPublicKey: String) {
createPrivateChatIfPossible(hexEncodedPublicKey)
}
fun createPrivateChatIfPossible(hexEncodedPublicKey: String) { fun createPrivateChatIfPossible(hexEncodedPublicKey: String) {
if (!PublicKeyValidation.isValid(hexEncodedPublicKey)) { return Toast.makeText(this, "Invalid Session ID", Toast.LENGTH_SHORT).show() } if (!PublicKeyValidation.isValid(hexEncodedPublicKey)) { return Toast.makeText(this, "Invalid Session ID", Toast.LENGTH_SHORT).show() }
val masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(this) val masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(this)
@ -69,7 +66,7 @@ class NewPrivateChatActivity : BaseActionBarActivity() {
} }
// region Adapter // region Adapter
private class Adapter(manager: FragmentManager) : FragmentPagerAdapter(manager) { private class CreatePrivateChatActivityAdapter(val activity: CreatePrivateChatActivity) : FragmentPagerAdapter(activity.supportFragmentManager) {
override fun getCount(): Int { override fun getCount(): Int {
return 2 return 2
@ -78,7 +75,12 @@ private class Adapter(manager: FragmentManager) : FragmentPagerAdapter(manager)
override fun getItem(index: Int): Fragment { override fun getItem(index: Int): Fragment {
return when (index) { return when (index) {
0 -> EnterPublicKeyFragment() 0 -> EnterPublicKeyFragment()
1 -> ScanQRCodeWrapperFragment() 1 -> {
val result = ScanQRCodeWrapperFragment()
result.delegate = activity
result.message = "Users can share their QR code by going into their account settings and tapping &quot;Share QR Code&quot;"
result
}
else -> throw IllegalStateException() else -> throw IllegalStateException()
} }
} }
@ -95,6 +97,7 @@ private class Adapter(manager: FragmentManager) : FragmentPagerAdapter(manager)
// region Enter Public Key Fragment // region Enter Public Key Fragment
class EnterPublicKeyFragment : Fragment() { class EnterPublicKeyFragment : Fragment() {
private val hexEncodedPublicKey: String private val hexEncodedPublicKey: String
get() { get() {
val masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context!!) val masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context!!)
@ -131,51 +134,7 @@ class EnterPublicKeyFragment : Fragment() {
private fun createPrivateChatIfPossible() { private fun createPrivateChatIfPossible() {
val hexEncodedPublicKey = publicKeyEditText.text.trim().toString() val hexEncodedPublicKey = publicKeyEditText.text.trim().toString()
(activity!! as NewPrivateChatActivity).createPrivateChatIfPossible(hexEncodedPublicKey) (activity!! as CreatePrivateChatActivity).createPrivateChatIfPossible(hexEncodedPublicKey)
} }
} }
// endregion // 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

@ -3,6 +3,8 @@ package org.thoughtcrime.securesms.loki.redesign.activities
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.LinearLayoutManager
import android.view.Menu
import android.view.MenuItem
import kotlinx.android.synthetic.main.activity_home.* import kotlinx.android.synthetic.main.activity_home.*
import network.loki.messenger.R import network.loki.messenger.R
import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.ApplicationContext
@ -42,8 +44,23 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
application.startRSSFeedPollersIfNeeded() application.startRSSFeedPollersIfNeeded()
} }
} }
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_home, menu)
return true
}
// endregion // endregion
// region Interaction
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.getItemId()
when (id) {
R.id.joinPublicChatItem -> joinPublicChat()
else -> { /* Do nothing */ }
}
return super.onOptionsItemSelected(item)
}
override fun onConversationClick(view: ConversationView) { override fun onConversationClick(view: ConversationView) {
val thread = view.thread ?: return val thread = view.thread ?: return
openConversation(thread) openConversation(thread)
@ -65,7 +82,13 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
} }
private fun createPrivateChat() { private fun createPrivateChat() {
val intent = Intent(this, NewPrivateChatActivity::class.java) val intent = Intent(this, CreatePrivateChatActivity::class.java)
startActivity(intent) startActivity(intent)
} }
private fun joinPublicChat() {
val intent = Intent(this, JoinPublicChatActivity::class.java)
startActivity(intent)
}
// endregion
} }

View File

@ -0,0 +1,90 @@
package org.thoughtcrime.securesms.loki.redesign.activities
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentPagerAdapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import kotlinx.android.synthetic.main.activity_join_public_chat.*
import kotlinx.android.synthetic.main.fragment_enter_chat_url.*
import network.loki.messenger.R
import org.thoughtcrime.securesms.BaseActionBarActivity
import org.thoughtcrime.securesms.loki.redesign.fragments.ScanQRCodeWrapperFragment
import org.thoughtcrime.securesms.loki.redesign.fragments.ScanQRCodeWrapperFragmentDelegate
class JoinPublicChatActivity : BaseActionBarActivity(), ScanQRCodeWrapperFragmentDelegate {
private val adapter = JoinPublicChatActivityAdapter(this)
// region Lifecycle
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Set content view
setContentView(R.layout.activity_join_public_chat)
// Set title
supportActionBar!!.title = "Join Public Chat"
// Set up view pager
viewPager.adapter = adapter
tabLayout.setupWithViewPager(viewPager)
}
// endregion
// region Interaction
override fun handleQRCodeScanned(url: String) {
joinPublicChatIfPossible(url)
}
fun joinPublicChatIfPossible(url: String) {
// TODO: Implement
}
// endregion
}
// region Adapter
private class JoinPublicChatActivityAdapter(val activity: JoinPublicChatActivity) : FragmentPagerAdapter(activity.supportFragmentManager) {
override fun getCount(): Int {
return 2
}
override fun getItem(index: Int): Fragment {
return when (index) {
0 -> EnterChatURLFragment()
1 -> {
val result = ScanQRCodeWrapperFragment()
result.delegate = activity
result.message = "Scan the QR code of the public chat you'd like to join"
result
}
else -> throw IllegalStateException()
}
}
override fun getPageTitle(index: Int): CharSequence? {
return when (index) {
0 -> "Enter Chat URL"
1 -> "Scan QR Code"
else -> throw IllegalStateException()
}
}
}
// endregion
// region Enter Public Key Fragment
class EnterChatURLFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.fragment_enter_chat_url, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
joinPublicChatButton.setOnClickListener { joinPublicChatIfPossible() }
}
private fun joinPublicChatIfPossible() {
val chatURL = chatURLEditText.text.trim().toString()
(activity!! as JoinPublicChatActivity).joinPublicChatIfPossible(chatURL)
}
}
// endregion

View File

@ -7,16 +7,16 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.LinearLayout import android.widget.LinearLayout
import kotlinx.android.synthetic.main.fragment_scan_qr_code.* import kotlinx.android.synthetic.main.fragment_scan_qr_code_v2.*
import network.loki.messenger.R import network.loki.messenger.R
import org.thoughtcrime.securesms.qr.ScanListener import org.thoughtcrime.securesms.qr.ScanListener
import org.thoughtcrime.securesms.qr.ScanningThread import org.thoughtcrime.securesms.qr.ScanningThread
class ScanQRCodeFragmentV2 : Fragment() { class ScanQRCodeFragmentV2 : Fragment() {
private val scanningThread = ScanningThread() private val scanningThread = ScanningThread()
private var viewCreated = false
var scanListener: ScanListener? = null var scanListener: ScanListener? = null
set(value) { field = value; scanningThread.setScanListener(scanListener) } set(value) { field = value; scanningThread.setScanListener(scanListener) }
var message: CharSequence = ""
override fun onCreateView(layoutInflater: LayoutInflater, viewGroup: ViewGroup?, bundle: Bundle?): View? { override fun onCreateView(layoutInflater: LayoutInflater, viewGroup: ViewGroup?, bundle: Bundle?): View? {
return layoutInflater.inflate(R.layout.fragment_scan_qr_code_v2, viewGroup, false) return layoutInflater.inflate(R.layout.fragment_scan_qr_code_v2, viewGroup, false)
@ -24,11 +24,11 @@ class ScanQRCodeFragmentV2 : Fragment() {
override fun onViewCreated(view: View, bundle: Bundle?) { override fun onViewCreated(view: View, bundle: Bundle?) {
super.onViewCreated(view, bundle) super.onViewCreated(view, bundle)
viewCreated = true
when (resources.configuration.orientation) { when (resources.configuration.orientation) {
Configuration.ORIENTATION_LANDSCAPE -> overlayView.orientation = LinearLayout.HORIZONTAL Configuration.ORIENTATION_LANDSCAPE -> overlayView.orientation = LinearLayout.HORIZONTAL
else -> overlayView.orientation = LinearLayout.VERTICAL else -> overlayView.orientation = LinearLayout.VERTICAL
} }
messageTextView.text = message
} }
override fun onResume() { override fun onResume() {

View File

@ -0,0 +1,62 @@
package org.thoughtcrime.securesms.loki.redesign.fragments
import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.content.ContextCompat
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.tbruyelle.rxpermissions2.RxPermissions
import network.loki.messenger.R
import org.thoughtcrime.securesms.qr.ScanListener
class ScanQRCodeWrapperFragment : Fragment(), ScanQRCodePlaceholderFragmentDelegate, ScanListener {
var delegate: ScanQRCodeWrapperFragmentDelegate? = null
var message: CharSequence = ""
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
scanQRCodeFragment.message = message
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(string: String) {
delegate?.handleQRCodeScanned(string)
}
}
interface ScanQRCodeWrapperFragmentDelegate {
fun handleQRCodeScanned(string: String)
}