Implement multi device UI

This commit is contained in:
Niels Andriesse 2021-02-26 11:10:45 +11:00
parent 2a741049cc
commit 1f8b9bfe58
8 changed files with 275 additions and 45 deletions

View File

@ -23,20 +23,15 @@ class LandingActivity : BaseActionBarActivity() {
setContentView(R.layout.activity_landing)
setUpActionBarSessionLogo(true)
findViewById<FakeChatView>(R.id.fakeChatView).startAnimating()
findViewById<View>(R.id.registerButton).setOnClickListener { register() }
findViewById<View>(R.id.restoreButton).setOnClickListener { restoreFromRecoveryPhrase() }
findViewById<View>(R.id.restoreBackupButton).setOnClickListener { restoreFromBackup() }
// Setup essentials for a new user.
findViewById<View>(R.id.restoreButton).setOnClickListener { restore() }
findViewById<View>(R.id.linkButton).setOnClickListener { link() }
IdentityKeyUtil.generateIdentityKeyPair(this)
TextSecurePreferences.setLastExperienceVersionCode(this, Util.getCanonicalVersionCode())
TextSecurePreferences.setPasswordDisabled(this, true)
TextSecurePreferences.setReadReceiptsEnabled(this, true)
TextSecurePreferences.setTypingIndicatorsEnabled(this, true)
//AC: This is a temporary workaround to trick the old code that the screen is unlocked.
// AC: This is a temporary workaround to trick the old code that the screen is unlocked.
KeyCachingService.setMasterSecret(applicationContext, Object())
}
@ -45,21 +40,13 @@ class LandingActivity : BaseActionBarActivity() {
push(intent)
}
private fun restoreFromRecoveryPhrase() {
private fun restore() {
val intent = Intent(this, RecoveryPhraseRestoreActivity::class.java)
push(intent)
}
private fun restoreFromBackup() {
val intent = Intent(this, BackupRestoreActivity::class.java)
private fun link() {
val intent = Intent(this, LinkDeviceActivity::class.java)
push(intent)
}
private fun reset() {
IdentityKeyUtil.delete(this, IdentityKeyUtil.LOKI_SEED)
TextSecurePreferences.removeLocalNumber(this)
TextSecurePreferences.setHasSeenWelcomeScreen(this, false)
val application = ApplicationContext.getInstance(this)
application.stopPolling()
}
}

View File

@ -0,0 +1,125 @@
package org.thoughtcrime.securesms.loki.activities
import android.content.Context
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentPagerAdapter
import android.text.InputType
import android.view.*
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_create_private_chat.*
import kotlinx.android.synthetic.main.fragment_recovery_phrase.*
import network.loki.messenger.R
import org.session.libsignal.service.loki.crypto.MnemonicCodec
import org.session.libsignal.utilities.Hex
import org.thoughtcrime.securesms.BaseActionBarActivity
import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragment
import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragmentDelegate
import org.thoughtcrime.securesms.loki.utilities.MnemonicUtilities
import org.thoughtcrime.securesms.loki.utilities.setUpActionBarSessionLogo
class LinkDeviceActivity : BaseActionBarActivity(), ScanQRCodeWrapperFragmentDelegate {
private val adapter = LinkDeviceActivityAdapter(this)
// region Lifecycle
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setUpActionBarSessionLogo()
setContentView(R.layout.activity_link_device)
viewPager.adapter = adapter
tabLayout.setupWithViewPager(viewPager)
}
// endregion
// region Interaction
override fun handleQRCodeScanned(mnemonic: String) {
continueWithMnemonic(mnemonic)
}
fun continueWithMnemonic(mnemonic: String) {
val loadFileContents: (String) -> String = { fileName ->
MnemonicUtilities.loadFileContents(this, fileName)
}
try {
val hexEncodedSeed = MnemonicCodec(loadFileContents).decode(mnemonic)
val seed = Hex.fromStringCondensed(hexEncodedSeed)
continueWithSeed(seed)
} catch (error: Exception) {
val message = if (error is MnemonicCodec.DecodingError) {
error.description
} else {
"An error occurred."
}
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
}
}
private fun continueWithSeed(seed: ByteArray) {
// TODO: Implement
}
// endregion
}
// region Adapter
private class LinkDeviceActivityAdapter(private val activity: LinkDeviceActivity) : FragmentPagerAdapter(activity.supportFragmentManager) {
val recoveryPhraseFragment = RecoveryPhraseFragment()
override fun getCount(): Int {
return 2
}
override fun getItem(index: Int): Fragment {
return when (index) {
0 -> recoveryPhraseFragment
1 -> {
val result = ScanQRCodeWrapperFragment()
result.delegate = activity
result.message = "Navigate to Settings → Recovery Phrase on your other device to show your QR code."
result
}
else -> throw IllegalStateException()
}
}
override fun getPageTitle(index: Int): CharSequence? {
return when (index) {
0 -> "Recovery Phrase"
1 -> "Scan QR Code"
else -> throw IllegalStateException()
}
}
}
// endregion
// region Recovery Phrase Fragment
class RecoveryPhraseFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.fragment_recovery_phrase, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mnemonicEditText.imeOptions = EditorInfo.IME_ACTION_DONE or 16777216 // Always use incognito keyboard
mnemonicEditText.setRawInputType(InputType.TYPE_CLASS_TEXT)
mnemonicEditText.setOnEditorActionListener { v, actionID, _ ->
if (actionID == EditorInfo.IME_ACTION_DONE) {
val imm = v.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(v.windowToken, 0)
handleContinueButtonTapped()
true
} else {
false
}
}
continueButton.setOnClickListener { handleContinueButtonTapped() }
}
private fun handleContinueButtonTapped() {
val mnemonic = mnemonicEditText.text?.trim().toString()
(requireActivity() as LinkDeviceActivity).continueWithMnemonic(mnemonic)
}
}
// endregion

View File

@ -49,27 +49,16 @@
android:layout_marginRight="@dimen/massive_spacing"
android:text="@string/activity_landing_restore_button_title" />
<Button
style="@style/Widget.Session.Button.Common.ProminentOutline"
android:id="@+id/restoreBackupButton"
android:layout_width="match_parent"
android:layout_height="@dimen/medium_button_height"
android:layout_marginLeft="@dimen/massive_spacing"
android:layout_marginTop="@dimen/medium_spacing"
android:layout_marginRight="@dimen/massive_spacing"
android:text="@string/activity_landing_restore_backup_button_title" />
<Button
android:id="@+id/linkButton"
android:layout_width="match_parent"
android:layout_height="@dimen/onboarding_button_bottom_offset"
android:layout_marginLeft="@dimen/massive_spacing"
android:layout_marginRight="@dimen/massive_spacing"
android:visibility="invisible"
android:gravity="center"
android:background="@color/transparent"
android:textAllCaps="false"
android:textSize="@dimen/medium_font_size"
android:text="@string/activity_landing_link_button_title" />
android:text="Link a Device" />
</LinearLayout>

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/very_large_spacing"
android:layout_marginRight="@dimen/very_large_spacing"
android:textSize="@dimen/very_large_font_size"
android:textStyle="bold"
android:textColor="@color/text"
android:text="Recovery Phrase" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/very_large_spacing"
android:layout_marginTop="7dp"
android:layout_marginRight="@dimen/very_large_spacing"
android:textSize="@dimen/medium_font_size"
android:textColor="@color/text"
android:text="To link your device, enter the recovery phrase that was given to you when you signed up." />
<EditText
style="@style/SessionEditText"
android:id="@+id/mnemonicEditText"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_marginLeft="@dimen/very_large_spacing"
android:layout_marginTop="12dp"
android:layout_marginRight="@dimen/very_large_spacing"
android:paddingTop="0dp"
android:paddingBottom="0dp"
android:gravity="center_vertical"
android:inputType="textMultiLine"
android:maxLines="2"
android:hint="@string/activity_restore_seed_edit_text_hint" />
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<Button
style="@style/Widget.Session.Button.Common.ProminentFilled"
android:id="@+id/continueButton"
android:layout_width="match_parent"
android:layout_height="@dimen/medium_button_height"
android:layout_marginLeft="@dimen/massive_spacing"
android:layout_marginRight="@dimen/massive_spacing"
android:layout_marginBottom="@dimen/medium_spacing"
android:text="@string/continue_2" />
</LinearLayout>

View File

@ -49,27 +49,16 @@
android:layout_marginRight="@dimen/massive_spacing"
android:text="@string/activity_landing_restore_button_title" />
<Button
style="@style/Widget.Session.Button.Common.ProminentOutline"
android:id="@+id/restoreBackupButton"
android:layout_width="match_parent"
android:layout_height="@dimen/medium_button_height"
android:layout_marginLeft="@dimen/massive_spacing"
android:layout_marginTop="@dimen/small_spacing"
android:layout_marginRight="@dimen/massive_spacing"
android:text="@string/activity_landing_restore_backup_button_title" />
<Button
android:id="@+id/linkButton"
android:layout_width="match_parent"
android:layout_height="@dimen/onboarding_button_bottom_offset"
android:layout_marginLeft="@dimen/massive_spacing"
android:layout_marginRight="@dimen/massive_spacing"
android:visibility="invisible"
android:gravity="center"
android:background="@color/transparent"
android:textAllCaps="false"
android:textSize="@dimen/medium_font_size"
android:text="@string/activity_landing_link_button_title" />
android:text="Link a Device" />
</LinearLayout>

View File

@ -0,0 +1,14 @@
<?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
style="@style/Widget.Session.TabLayout"
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="@dimen/tab_bar_height" />
</androidx.viewpager.widget.ViewPager>

View File

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/very_large_spacing"
android:layout_marginRight="@dimen/very_large_spacing"
android:textSize="@dimen/large_font_size"
android:textStyle="bold"
android:textColor="@color/text"
android:text="Recovery Phrase" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/very_large_spacing"
android:layout_marginTop="4dp"
android:layout_marginRight="@dimen/very_large_spacing"
android:textSize="@dimen/small_font_size"
android:textColor="@color/text"
android:text="@string/activity_restore_explanation" />
<EditText
style="@style/SmallSessionEditText"
android:id="@+id/mnemonicEditText"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_marginLeft="@dimen/very_large_spacing"
android:layout_marginTop="10dp"
android:layout_marginRight="@dimen/very_large_spacing"
android:paddingTop="0dp"
android:paddingBottom="0dp"
android:gravity="center_vertical"
android:inputType="textMultiLine"
android:maxLines="2"
android:hint="@string/activity_restore_seed_edit_text_hint" />
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<Button
style="@style/Widget.Session.Button.Common.ProminentFilled"
android:id="@+id/continueButton"
android:layout_width="match_parent"
android:layout_height="@dimen/medium_button_height"
android:layout_marginLeft="@dimen/massive_spacing"
android:layout_marginRight="@dimen/massive_spacing"
android:layout_marginBottom="@dimen/medium_spacing"
android:text="@string/continue_2" />
</LinearLayout>

View File

@ -88,7 +88,7 @@
</PreferenceCategory>
<PreferenceCategory android:layout="@layout/preference_divider" />
<!-- <PreferenceCategory android:layout="@layout/preference_divider" />
<PreferenceCategory android:key="backup_category" android:title="@string/preferences_chats__backups">
@ -105,6 +105,6 @@
android:dependency="pref_backup_enabled_v3"
tools:summary="Last backup: 3 days ago" />
</PreferenceCategory>
</PreferenceCategory> -->
</PreferenceScreen>