mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-24 16:57:50 +00:00
Implement remaining onion request UI
This commit is contained in:
parent
326b5a9475
commit
3a646476ff
@ -5,4 +5,4 @@
|
|||||||
|
|
||||||
<solid android:color="@color/accent" />
|
<solid android:color="@color/accent" />
|
||||||
|
|
||||||
</shape>
|
</shape>
|
8
res/drawable/paths_building_dot.xml
Normal file
8
res/drawable/paths_building_dot.xml
Normal file
@ -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 buildingPathsReceiver: BroadcastReceiver = object : BroadcastReceiver() {
|
||||||
|
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
handleBuildingPathsEvent()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val destinationRow = getPathRow("Destination", null, LineView.Location.Bottom, 5000, 4000)
|
broadcastReceivers.add(buildingPathsReceiver)
|
||||||
pathRowsContainer.addView(youRow)
|
LocalBroadcastManager.getInstance(this).registerReceiver(buildingPathsReceiver, IntentFilter("buildingPaths"))
|
||||||
for (pathRow in pathRows) {
|
val pathsBuiltReceiver: BroadcastReceiver = object : BroadcastReceiver() {
|
||||||
pathRowsContainer.addView(pathRow)
|
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
handlePathsBuiltEvent()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pathRowsContainer.addView(destinationRow)
|
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
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
77
src/org/thoughtcrime/securesms/loki/views/PathStatusView.kt
Normal file
77
src/org/thoughtcrime/securesms/loki/views/PathStatusView.kt
Normal file
@ -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…
x
Reference in New Issue
Block a user