Implement remaining onion request UI

pull/206/head
nielsandriesse 5 years ago
parent 326b5a9475
commit 3a646476ff

@ -5,4 +5,4 @@
<solid android:color="@color/accent" /> <solid android:color="@color/accent" />
</shape> </shape>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/paths_building" />
</shape>

@ -40,13 +40,21 @@
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginLeft="64dp" /> android:layout_marginLeft="64dp" />
<org.thoughtcrime.securesms.loki.views.ProfilePictureView <RelativeLayout
android:id="@+id/pathStatusView" android:id="@+id/pathStatusViewContainer"
android:layout_width="@dimen/small_profile_picture_size" android:layout_width="@dimen/small_profile_picture_size"
android:layout_height="@dimen/small_profile_picture_size" android:layout_height="@dimen/small_profile_picture_size"
android:background="@color/red"
android:layout_alignParentRight="true" android:layout_alignParentRight="true"
android:layout_centerVertical="true" /> android:layout_centerVertical="true" >
<org.thoughtcrime.securesms.loki.views.PathStatusView
android:layout_width="@dimen/path_status_view_size"
android:layout_height="@dimen/path_status_view_size"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_marginRight="8dp" />
</RelativeLayout>
</RelativeLayout> </RelativeLayout>

@ -3,6 +3,7 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@drawable/default_session_background" android:background="@drawable/default_session_background"
android:orientation="vertical" android:orientation="vertical"
android:gravity="center"> android:gravity="center">
@ -32,6 +33,14 @@
android:orientation="vertical" android:orientation="vertical"
android:layout_centerInParent="true" /> android:layout_centerInParent="true" />
<com.github.ybq.android.spinkit.SpinKitView
style="@style/SpinKitView.Large.ThreeBounce"
android:id="@+id/spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
app:SpinKit_Color="@color/text" />
</RelativeLayout> </RelativeLayout>
<Button <Button

@ -28,6 +28,7 @@
<color name="new_conversation_button_collapsed_background">#1F1F1F</color> <color name="new_conversation_button_collapsed_background">#1F1F1F</color>
<color name="pn_option_background">#1B1B1B</color> <color name="pn_option_background">#1B1B1B</color>
<color name="pn_option_border">#212121</color> <color name="pn_option_border">#212121</color>
<color name="paths_building">#FFCE3A</color>
<!-- Session --> <!-- Session -->
<!-- Loki --> <!-- Loki -->

@ -33,6 +33,7 @@
<dimen name="dialog_corner_radius">8dp</dimen> <dimen name="dialog_corner_radius">8dp</dimen>
<dimen name="dialog_button_corner_radius">4dp</dimen> <dimen name="dialog_button_corner_radius">4dp</dimen>
<dimen name="pn_option_corner_radius">8dp</dimen> <dimen name="pn_option_corner_radius">8dp</dimen>
<dimen name="path_status_view_size">8dp</dimen>
<dimen name="path_row_height">56dp</dimen> <dimen name="path_row_height">56dp</dimen>
<dimen name="path_row_dot_size">8dp</dimen> <dimen name="path_row_dot_size">8dp</dimen>
<dimen name="path_row_expanded_dot_size">16dp</dimen> <dimen name="path_row_expanded_dot_size">16dp</dimen>

@ -101,7 +101,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
profileButton.hexEncodedPublicKey = hexEncodedPublicKey profileButton.hexEncodedPublicKey = hexEncodedPublicKey
profileButton.update() profileButton.update()
profileButton.setOnClickListener { openSettings() } profileButton.setOnClickListener { openSettings() }
pathStatusView.setOnClickListener { showPath() } pathStatusViewContainer.setOnClickListener { showPath() }
// Set up seed reminder view // Set up seed reminder view
val isMasterDevice = (TextSecurePreferences.getMasterHexEncodedPublicKey(this) == null) val isMasterDevice = (TextSecurePreferences.getMasterHexEncodedPublicKey(this) == null)
val hasViewedSeed = TextSecurePreferences.getHasViewedSeed(this) val hasViewedSeed = TextSecurePreferences.getHasViewedSeed(this)

@ -1,10 +1,13 @@
package org.thoughtcrime.securesms.loki.activities package org.thoughtcrime.securesms.loki.activities
import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.support.v4.content.LocalBroadcastManager
import android.util.AttributeSet import android.util.AttributeSet
import android.util.TypedValue import android.util.TypedValue
import android.view.Gravity import android.view.Gravity
@ -19,35 +22,89 @@ import kotlinx.android.synthetic.main.activity_path.*
import network.loki.messenger.R import network.loki.messenger.R
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.loki.utilities.animateSizeChange import org.thoughtcrime.securesms.loki.utilities.animateSizeChange
import org.thoughtcrime.securesms.loki.utilities.fadeIn
import org.thoughtcrime.securesms.loki.utilities.fadeOut
import org.thoughtcrime.securesms.loki.utilities.getColorWithID import org.thoughtcrime.securesms.loki.utilities.getColorWithID
import org.whispersystems.signalservice.loki.api.onionrequests.OnionRequestAPI import org.whispersystems.signalservice.loki.api.onionrequests.OnionRequestAPI
import org.whispersystems.signalservice.loki.api.onionrequests.Snode import org.whispersystems.signalservice.loki.api.onionrequests.Snode
class PathActivity : PassphraseRequiredActionBarActivity() { class PathActivity : PassphraseRequiredActionBarActivity() {
private val broadcastReceivers = mutableListOf<BroadcastReceiver>()
// region Lifecycle // region Lifecycle
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) { override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
super.onCreate(savedInstanceState, isReady) super.onCreate(savedInstanceState, isReady)
setContentView(R.layout.activity_path) setContentView(R.layout.activity_path)
supportActionBar!!.title = resources.getString(R.string.activity_path_title) supportActionBar!!.title = resources.getString(R.string.activity_path_title)
val youRow = getPathRow("You", null, LineView.Location.Top, 1000, 4000) rebuildPathButton.setOnClickListener { rebuildPath() }
val path = OnionRequestAPI.paths.firstOrNull() ?: return finish() update(false)
val pathRows = path.mapIndexed { index, snode -> registerObservers()
val isGuardSnode = (OnionRequestAPI.guardSnodes.contains(snode)) }
getPathRow(snode, LineView.Location.Middle, index.toLong() * 1000 + 2000, 4000, isGuardSnode)
} private fun registerObservers() {
val destinationRow = getPathRow("Destination", null, LineView.Location.Bottom, 5000, 4000) val buildingPathsReceiver: BroadcastReceiver = object : BroadcastReceiver() {
pathRowsContainer.addView(youRow)
for (pathRow in pathRows) { override fun onReceive(context: Context, intent: Intent) {
pathRowsContainer.addView(pathRow) handleBuildingPathsEvent()
} }
pathRowsContainer.addView(destinationRow) }
broadcastReceivers.add(buildingPathsReceiver)
LocalBroadcastManager.getInstance(this).registerReceiver(buildingPathsReceiver, IntentFilter("buildingPaths"))
val pathsBuiltReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
handlePathsBuiltEvent()
}
}
broadcastReceivers.add(pathsBuiltReceiver)
LocalBroadcastManager.getInstance(this).registerReceiver(pathsBuiltReceiver, IntentFilter("pathsBuilt"))
} }
override fun onCreateOptionsMenu(menu: Menu?): Boolean { override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_path, menu) menuInflater.inflate(R.menu.menu_path, menu)
return true return true
} }
override fun onDestroy() {
for (receiver in broadcastReceivers) {
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver)
}
super.onDestroy()
}
// endregion
// region Updating
private fun handleBuildingPathsEvent() { update(false) }
private fun handlePathsBuiltEvent() { update(false) }
private fun update(isAnimated: Boolean) {
pathRowsContainer.removeAllViews()
if (OnionRequestAPI.paths.count() >= OnionRequestAPI.pathCount) {
val path = OnionRequestAPI.paths.firstOrNull() ?: return finish()
val dotAnimationRepeatInterval = path.count().toLong() * 1000 + 2000
val pathRows = path.mapIndexed { index, snode ->
val isGuardSnode = (OnionRequestAPI.guardSnodes.contains(snode))
getPathRow(snode, LineView.Location.Middle, index.toLong() * 1000 + 2000, dotAnimationRepeatInterval, isGuardSnode)
}
val youRow = getPathRow("You", null, LineView.Location.Top, 1000, dotAnimationRepeatInterval)
val destinationRow = getPathRow("Destination", null, LineView.Location.Bottom, path.count().toLong() * 1000 + 2000, dotAnimationRepeatInterval)
val rows = listOf( youRow ) + pathRows + listOf( destinationRow )
for (row in rows) {
pathRowsContainer.addView(row)
}
if (isAnimated) {
spinner.fadeOut()
} else {
spinner.alpha = 0.0f
}
} else {
if (isAnimated) {
spinner.fadeIn()
} else {
spinner.alpha = 1.0f
}
}
}
// endregion // endregion
// region General // region General
@ -108,6 +165,12 @@ class PathActivity : PassphraseRequiredActionBarActivity() {
Toast.makeText(this, R.string.invalid_url, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.invalid_url, Toast.LENGTH_SHORT).show()
} }
} }
private fun rebuildPath() {
OnionRequestAPI.guardSnodes = setOf()
OnionRequestAPI.paths = listOf()
OnionRequestAPI.buildPaths()
}
// endregion // endregion
// region Line View // region Line View

@ -1,7 +1,5 @@
package org.thoughtcrime.securesms.loki.activities package org.thoughtcrime.securesms.loki.activities
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.app.Activity import android.app.Activity
import android.content.ClipData import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
@ -31,6 +29,8 @@ import org.thoughtcrime.securesms.database.Address
import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.loki.dialogs.ClearAllDataDialog import org.thoughtcrime.securesms.loki.dialogs.ClearAllDataDialog
import org.thoughtcrime.securesms.loki.dialogs.SeedDialog import org.thoughtcrime.securesms.loki.dialogs.SeedDialog
import org.thoughtcrime.securesms.loki.utilities.fadeIn
import org.thoughtcrime.securesms.loki.utilities.fadeOut
import org.thoughtcrime.securesms.loki.utilities.push import org.thoughtcrime.securesms.loki.utilities.push
import org.thoughtcrime.securesms.loki.utilities.toPx import org.thoughtcrime.securesms.loki.utilities.toPx
import org.thoughtcrime.securesms.mms.GlideApp import org.thoughtcrime.securesms.mms.GlideApp
@ -147,7 +147,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
} }
private fun updateProfile(isUpdatingProfilePicture: Boolean) { private fun updateProfile(isUpdatingProfilePicture: Boolean) {
showLoader() loader.fadeIn()
val promises = mutableListOf<Promise<*, Exception>>() val promises = mutableListOf<Promise<*, Exception>>()
val displayName = displayNameToBeUploaded val displayName = displayNameToBeUploaded
if (displayName != null) { if (displayName != null) {
@ -187,24 +187,9 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
profilePictureView.update() profilePictureView.update()
} }
profilePictureToBeUploaded = null profilePictureToBeUploaded = null
hideLoader() loader.fadeOut()
} }
} }
private fun showLoader() {
loader.visibility = View.VISIBLE
loader.animate().setDuration(150).alpha(1.0f).start()
}
private fun hideLoader() {
loader.animate().setDuration(150).alpha(0.0f).setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
super.onAnimationEnd(animation)
loader.visibility = View.GONE
}
})
}
// endregion // endregion
// region Interaction // region Interaction

@ -1,5 +1,7 @@
package org.thoughtcrime.securesms.loki.utilities package org.thoughtcrime.securesms.loki.utilities
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.FloatEvaluator import android.animation.FloatEvaluator
import android.animation.ValueAnimator import android.animation.ValueAnimator
import android.graphics.PointF import android.graphics.PointF
@ -31,4 +33,19 @@ fun View.animateSizeChange(@DimenRes startSizeID: Int, @DimenRes endSizeID: Int,
this.layoutParams = layoutParams this.layoutParams = layoutParams
} }
animation.start() animation.start()
} }
fun View.fadeIn(duration: Long = 150) {
visibility = View.VISIBLE
animate().setDuration(duration).alpha(1.0f).start()
}
fun View.fadeOut(duration: Long = 150) {
animate().setDuration(duration).alpha(0.0f).setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
super.onAnimationEnd(animation)
visibility = View.GONE
}
})
}

@ -0,0 +1,77 @@
package org.thoughtcrime.securesms.loki.views
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.support.v4.content.LocalBroadcastManager
import android.util.AttributeSet
import android.view.View
import network.loki.messenger.R
import org.whispersystems.signalservice.loki.api.onionrequests.OnionRequestAPI
class PathStatusView : View {
private val broadcastReceivers = mutableListOf<BroadcastReceiver>()
constructor(context: Context) : super(context) {
initialize()
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
initialize()
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
initialize()
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
initialize()
}
private fun initialize() {
update()
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
registerObservers()
}
private fun registerObservers() {
val buildingPathsReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
handleBuildingPathsEvent()
}
}
broadcastReceivers.add(buildingPathsReceiver)
LocalBroadcastManager.getInstance(context).registerReceiver(buildingPathsReceiver, IntentFilter("buildingPaths"))
val pathsBuiltReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
handlePathsBuiltEvent()
}
}
broadcastReceivers.add(pathsBuiltReceiver)
LocalBroadcastManager.getInstance(context).registerReceiver(pathsBuiltReceiver, IntentFilter("pathsBuilt"))
}
override fun onDetachedFromWindow() {
for (receiver in broadcastReceivers) {
LocalBroadcastManager.getInstance(context).unregisterReceiver(receiver)
}
super.onDetachedFromWindow()
}
private fun handleBuildingPathsEvent() { update() }
private fun handlePathsBuiltEvent() { update() }
private fun update() {
if (OnionRequestAPI.paths.count() >= OnionRequestAPI.pathCount) {
setBackgroundResource(R.drawable.accent_dot)
} else {
setBackgroundResource(R.drawable.paths_building_dot)
}
}
}
Loading…
Cancel
Save