mirror of
https://github.com/oxen-io/session-android.git
synced 2025-01-12 20:53:38 +00:00
Use actual path data, clean and fix incorrect copy
This commit is contained in:
parent
c7adf9f232
commit
326b5a9475
12
res/drawable/ic_question_mark.xml
Normal file
12
res/drawable/ic_question_mark.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="496dp"
|
||||
android:height="496dp"
|
||||
android:viewportWidth="496"
|
||||
android:viewportHeight="496">
|
||||
<path
|
||||
android:pathData="M248,0C111.043,0 0,111.083 0,248C0,384.997 111.043,496 248,496C384.957,496 496,384.997 496,248C496,111.083 384.957,0 248,0ZM248.5,467C127.744,467 30,369.297 30,248.5C30,127.784 127.748,30 248.5,30C369.211,30 467,127.747 467,248.5C467,369.254 369.297,467 248.5,467ZM270.703,285.663L270.703,292C270.703,298.627 268.33,304 261.703,304L238.056,304C231.429,304 226.056,298.627 226.056,292L226.056,283.341C226.056,247.596 250.224,244.566 270.703,233.084C288.264,223.239 314.235,222.608 314.235,185.76C314.235,164.861 286.202,147.355 253.674,147.355C230.485,147.355 204.281,169.53 189.233,188.522C185.176,193.642 177.773,194.593 172.567,190.646L155.743,185.548C150.636,181.676 149.492,174.482 153.099,169.185C176.726,134.491 206.82,104 253.674,104C302.745,104 355.124,142.304 355.124,192.8C355.124,267.221 270.703,260.884 270.703,285.663ZM282,373C282,388.991 268.991,402 253,402C237.009,402 224,388.991 224,373C224,357.009 237.009,344 253,344C268.991,344 282,357.009 282,373Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="@color/text"
|
||||
android:fillType="nonZero"
|
||||
android:strokeColor="@color/text"/>
|
||||
</vector>
|
10
res/menu/menu_path.xml
Normal file
10
res/menu/menu_path.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?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/learnMoreButton"
|
||||
android:icon="@drawable/ic_question_mark"
|
||||
app:showAsAction="always" />
|
||||
|
||||
</menu>
|
@ -1699,7 +1699,7 @@
|
||||
<string name="fragment_enter_session_id_edit_text_hint">Enter your Session ID</string>
|
||||
|
||||
<string name="activity_display_name_title_2">Pick your display name</string>
|
||||
<string name="activity_display_name_explanation">This will be your name when you use Session.</string>
|
||||
<string name="activity_display_name_explanation">This will be your name when you use Session. It can be your real name, an alias, or anything else you like.</string>
|
||||
<string name="activity_display_name_edit_text_hint">Enter a display name</string>
|
||||
<string name="activity_display_name_display_name_missing_error">Please pick a display name</string>
|
||||
<string name="activity_display_name_display_name_invalid_error">Please pick a display name that consists of only a-z, A-Z, 0-9 and _ characters</string>
|
||||
@ -1708,9 +1708,9 @@
|
||||
<string name="activity_pn_mode_title">Push Notifications</string>
|
||||
<string name="activity_pn_mode_explanation">There are two ways Session can handle push notifications. Make sure to read the descriptions carefully before you choose.</string>
|
||||
<string name="activity_pn_mode_fcm_option_title">Firebase Cloud Messaging</string>
|
||||
<string name="activity_pn_mode_fcm_option_explanation">Session will use the Firebase Cloud Messaging service to receive push notifications. You\’ll be notified of new messages reliably and immediately. Using FCM means that this device will communicate directly with Google\’s servers to retrieve push notifications, which will expose your IP address to Google. Your messages will still be onion-routed and end-to-end encrypted, so the contents of your messages will remain completely private.</string>
|
||||
<string name="activity_pn_mode_fcm_option_explanation">Session will use the Firebase Cloud Messaging service to receive push notifications. You\'ll be notified of new messages reliably and immediately. Using FCM means that your IP address and device token will be exposed to Google. If you use push notifications for other apps, this will already be the case. Your IP address and device token will also be exposed to Loki, but your messages will still be onion-routed and end-to-end encrypted, so the contents of your messages will remain completely private.</string>
|
||||
<string name="activity_pn_mode_background_polling_option_title">Background Polling</string>
|
||||
<string name="activity_pn_mode_background_polling_option_explanation">Session will occasionally check for new messages in the background. This guarantees full privacy protection, but message notifications may be significantly delayed.</string>
|
||||
<string name="activity_pn_mode_background_polling_option_explanation">Session will occasionally check for new messages in the background. This guarantees full metadata protection, but message notifications may be significantly delayed.</string>
|
||||
<string name="activity_pn_mode_recommended_option_tag">Recommended</string>
|
||||
<string name="activity_pn_mode_no_option_picked_dialog_title">Please Pick an Option</string>
|
||||
|
||||
@ -1724,9 +1724,9 @@
|
||||
<string name="sheet_pn_mode_title">Push Notifications</string>
|
||||
<string name="sheet_pn_mode_explanation">Session now features two ways to handle push notifications. Make sure to read the descriptions carefully before you choose.</string>
|
||||
<string name="sheet_pn_mode_fcm_option_title">Firebase Cloud Messaging</string>
|
||||
<string name="sheet_pn_mode_fcm_option_explanation">Session will use the Firebase Cloud Messaging service to receive push notifications. You\’ll be notified of new messages reliably and immediately. Using FCM means that this device will communicate directly with Google\’s servers to retrieve push notifications, which will expose your IP address to Google. Your messages will still be onion-routed and end-to-end encrypted, so the contents of your messages will remain completely private.</string>
|
||||
<string name="sheet_pn_mode_fcm_option_explanation">Session will use the Firebase Cloud Messaging service to receive push notifications. You\'ll be notified of new messages reliably and immediately. Using FCM means that your IP address and device token will be exposed to Google. If you use push notifications for other apps, this will already be the case. Your IP address and device token will also be exposed to Loki, but your messages will still be onion-routed and end-to-end encrypted, so the contents of your messages will remain completely private.</string>
|
||||
<string name="sheet_pn_mode_background_polling_option_title">Background Polling</string>
|
||||
<string name="sheet_pn_mode_background_polling_option_explanation">Session will occasionally check for new messages in the background. This guarantees full privacy protection, but message notifications may be significantly delayed.</string>
|
||||
<string name="sheet_pn_mode_background_polling_option_explanation">Session will occasionally check for new messages in the background. This guarantees full metadata protection, but message notifications may be significantly delayed.</string>
|
||||
<string name="sheet_pn_mode_recommended_option_tag">Recommended</string>
|
||||
<string name="sheet_pn_mode_no_option_picked_dialog_title">Please Pick an Option</string>
|
||||
<string name="sheet_pn_mode_confirm_button_title">Confirm</string>
|
||||
@ -1734,7 +1734,7 @@
|
||||
|
||||
<string name="activity_seed_title">Your Recovery Phrase</string>
|
||||
<string name="activity_seed_title_2">Meet your recovery phrase</string>
|
||||
<string name="activity_seed_explanation">Your recovery phrase is the master key to your Session ID — you can use it to restore your Session ID if you lose access to your device. Store your recovery phrase in a safe place, and don\’t give it to anyone. To restore your Session ID, launch Session and tap Continue your Session.</string>
|
||||
<string name="activity_seed_explanation">Your recovery phrase is the master key to your Session ID — you can use it to restore your Session ID if you lose access to your device. Store your recovery phrase in a safe place, and don\’t give it to anyone.</string>
|
||||
<string name="activity_seed_reveal_button_title">Hold to reveal</string>
|
||||
|
||||
<string name="view_seed_reminder_subtitle_1">Secure your account by saving your recovery phrase</string>
|
||||
@ -1804,7 +1804,7 @@
|
||||
|
||||
<string name="preferences_notifications_strategy_category_title">Notification Strategy</string>
|
||||
<string name="preferences_notifications_use_fcm_option_title">Use FCM</string>
|
||||
<string name="preferences_notifications_use_fcm_option_explanation">Using Firebase Cloud Messaging allows for more reliable push notifications, but exposes your IP to Google.</string>
|
||||
<string name="preferences_notifications_use_fcm_option_explanation">Using Firebase Cloud Messaging allows for more reliable push notifications, but exposes your IP and device token to Google and Loki.</string>
|
||||
|
||||
<string name="dialog_link_device_slave_mode_title_1">Waiting for Authorization</string>
|
||||
<string name="dialog_link_device_slave_mode_title_2">Device Link Authorized</string>
|
||||
@ -1828,7 +1828,7 @@
|
||||
<string name="dialog_seed_explanation">This is your recovery phrase. With it, you can restore or migrate your Session ID to a new device.</string>
|
||||
|
||||
<string name="dialog_clear_all_data_title">Clear All Data</string>
|
||||
<string name="dialog_clear_all_data_explanation">This will permanently delete your Session ID, including all messages, sessions, and contacts.</string>
|
||||
<string name="dialog_clear_all_data_explanation">This will permanently delete your messages, sessions, and contacts.</string>
|
||||
|
||||
<string name="activity_qr_code_title">QR Code</string>
|
||||
<string name="activity_qr_code_view_my_qr_code_tab_title">View My QR Code</string>
|
||||
|
@ -1,23 +1,27 @@
|
||||
package org.thoughtcrime.securesms.loki.activities
|
||||
|
||||
import android.animation.FloatEvaluator
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.support.annotation.DimenRes
|
||||
import android.util.AttributeSet
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.activity_path.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.loki.utilities.animateSizeChange
|
||||
import org.thoughtcrime.securesms.loki.utilities.getColorWithID
|
||||
import org.thoughtcrime.securesms.loki.views.NewConversationButtonSetView
|
||||
import org.whispersystems.signalservice.loki.api.onionrequests.OnionRequestAPI
|
||||
import org.whispersystems.signalservice.loki.api.onionrequests.Snode
|
||||
|
||||
class PathActivity : PassphraseRequiredActionBarActivity() {
|
||||
|
||||
@ -27,23 +31,36 @@ class PathActivity : PassphraseRequiredActionBarActivity() {
|
||||
setContentView(R.layout.activity_path)
|
||||
supportActionBar!!.title = resources.getString(R.string.activity_path_title)
|
||||
val youRow = getPathRow("You", null, LineView.Location.Top, 1000, 4000)
|
||||
val row1 = getPathRow("Guard Node", "0.0.0.0", LineView.Location.Middle, 2000, 4000)
|
||||
val row2 = getPathRow("Service Node", "0.0.0.0", LineView.Location.Middle, 3000, 4000)
|
||||
val row3 = getPathRow("Service Node", "0.0.0.0", LineView.Location.Middle, 4000, 4000)
|
||||
val path = OnionRequestAPI.paths.firstOrNull() ?: return finish()
|
||||
val pathRows = path.mapIndexed { index, snode ->
|
||||
val isGuardSnode = (OnionRequestAPI.guardSnodes.contains(snode))
|
||||
getPathRow(snode, LineView.Location.Middle, index.toLong() * 1000 + 2000, 4000, isGuardSnode)
|
||||
}
|
||||
val destinationRow = getPathRow("Destination", null, LineView.Location.Bottom, 5000, 4000)
|
||||
pathRowsContainer.addView(youRow)
|
||||
pathRowsContainer.addView(row1)
|
||||
pathRowsContainer.addView(row2)
|
||||
pathRowsContainer.addView(row3)
|
||||
for (pathRow in pathRows) {
|
||||
pathRowsContainer.addView(pathRow)
|
||||
}
|
||||
pathRowsContainer.addView(destinationRow)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
menuInflater.inflate(R.menu.menu_path, menu)
|
||||
return true
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region General
|
||||
private fun getPathRow(title: String, subtitle: String?, location: LineView.Location, dotAnimationStartDelay: Long, dotAnimationRepeatInterval: Long): LinearLayout {
|
||||
val mainContainer = LinearLayout(this)
|
||||
mainContainer.orientation = LinearLayout.HORIZONTAL
|
||||
mainContainer.gravity = Gravity.CENTER_VERTICAL
|
||||
val mainContainerLayoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||
mainContainer.layoutParams = mainContainerLayoutParams
|
||||
val lineView = LineView(this, location, dotAnimationStartDelay, dotAnimationRepeatInterval)
|
||||
val lineViewLayoutParams = LinearLayout.LayoutParams(resources.getDimensionPixelSize(R.dimen.path_row_expanded_dot_size), resources.getDimensionPixelSize(R.dimen.path_row_height))
|
||||
lineView.layoutParams = lineViewLayoutParams
|
||||
mainContainer.addView(lineView)
|
||||
val titleTextView = TextView(this)
|
||||
titleTextView.setTextColor(resources.getColorWithID(R.color.text, theme))
|
||||
titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, resources.getDimension(R.dimen.medium_font_size))
|
||||
@ -54,6 +71,7 @@ class PathActivity : PassphraseRequiredActionBarActivity() {
|
||||
val titleContainerLayoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||
titleContainerLayoutParams.marginStart = resources.getDimensionPixelSize(R.dimen.large_spacing)
|
||||
titleContainer.layoutParams = titleContainerLayoutParams
|
||||
mainContainer.addView(titleContainer)
|
||||
if (subtitle != null) {
|
||||
val subtitleTextView = TextView(this)
|
||||
subtitleTextView.setTextColor(resources.getColorWithID(R.color.text, theme))
|
||||
@ -61,15 +79,35 @@ class PathActivity : PassphraseRequiredActionBarActivity() {
|
||||
subtitleTextView.text = subtitle
|
||||
titleContainer.addView(subtitleTextView)
|
||||
}
|
||||
val mainContainer = LinearLayout(this)
|
||||
mainContainer.orientation = LinearLayout.HORIZONTAL
|
||||
mainContainer.gravity = Gravity.CENTER_VERTICAL
|
||||
val mainContainerLayoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
|
||||
mainContainer.layoutParams = mainContainerLayoutParams
|
||||
mainContainer.addView(lineView)
|
||||
mainContainer.addView(titleContainer)
|
||||
return mainContainer
|
||||
}
|
||||
|
||||
private fun getPathRow(snode: Snode, location: LineView.Location, dotAnimationStartDelay: Long, dotAnimationRepeatInterval: Long, isGuardSnode: Boolean): LinearLayout {
|
||||
val title = if (isGuardSnode) resources.getString(R.string.activity_path_guard_node_row_title) else resources.getString(R.string.activity_path_service_node_row_title)
|
||||
val subtitle = snode.toString().removePrefix("https://").substringBefore(":")
|
||||
return getPathRow(title, subtitle, location, dotAnimationStartDelay, dotAnimationRepeatInterval)
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Interaction
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
val id = item.itemId
|
||||
when(id) {
|
||||
R.id.learnMoreButton -> learnMore()
|
||||
else -> { /* Do nothing */ }
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
private fun learnMore() {
|
||||
try {
|
||||
val url = "https://getsession.org/faq/#onion-routing"
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||
startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
Toast.makeText(this, R.string.invalid_url, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Line View
|
||||
@ -147,26 +185,11 @@ class PathActivity : PassphraseRequiredActionBarActivity() {
|
||||
}
|
||||
|
||||
private fun expand() {
|
||||
animateDotViewSizeChange(R.dimen.path_row_dot_size, R.dimen.path_row_expanded_dot_size)
|
||||
dotView.animateSizeChange(R.dimen.path_row_dot_size, R.dimen.path_row_expanded_dot_size)
|
||||
}
|
||||
|
||||
private fun collapse() {
|
||||
animateDotViewSizeChange(R.dimen.path_row_expanded_dot_size, R.dimen.path_row_dot_size)
|
||||
}
|
||||
|
||||
private fun animateDotViewSizeChange(@DimenRes startSizeID: Int, @DimenRes endSizeID: Int) {
|
||||
val layoutParams = dotView.layoutParams
|
||||
val startSize = resources.getDimension(startSizeID)
|
||||
val endSize = resources.getDimension(endSizeID)
|
||||
val animation = ValueAnimator.ofObject(FloatEvaluator(), startSize, endSize)
|
||||
animation.duration = NewConversationButtonSetView.Button.animationDuration
|
||||
animation.addUpdateListener { animator ->
|
||||
val size = animator.animatedValue as Float
|
||||
layoutParams.width = size.toInt()
|
||||
layoutParams.height = size.toInt()
|
||||
dotView.layoutParams = layoutParams
|
||||
}
|
||||
animation.start()
|
||||
dotView.animateSizeChange(R.dimen.path_row_expanded_dot_size, R.dimen.path_row_dot_size)
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
@ -1,7 +1,10 @@
|
||||
package org.thoughtcrime.securesms.loki.utilities
|
||||
|
||||
import android.animation.FloatEvaluator
|
||||
import android.animation.ValueAnimator
|
||||
import android.graphics.PointF
|
||||
import android.graphics.Rect
|
||||
import android.support.annotation.DimenRes
|
||||
import android.view.View
|
||||
|
||||
fun View.contains(point: PointF): Boolean {
|
||||
@ -13,4 +16,19 @@ val View.hitRect: Rect
|
||||
val rect = Rect()
|
||||
getHitRect(rect)
|
||||
return rect
|
||||
}
|
||||
}
|
||||
|
||||
fun View.animateSizeChange(@DimenRes startSizeID: Int, @DimenRes endSizeID: Int, animationDuration: Long = 250) {
|
||||
val layoutParams = this.layoutParams
|
||||
val startSize = resources.getDimension(startSizeID)
|
||||
val endSize = resources.getDimension(endSizeID)
|
||||
val animation = ValueAnimator.ofObject(FloatEvaluator(), startSize, endSize)
|
||||
animation.duration = animationDuration
|
||||
animation.addUpdateListener { animator ->
|
||||
val size = animator.animatedValue as Float
|
||||
layoutParams.width = size.toInt()
|
||||
layoutParams.height = size.toInt()
|
||||
this.layoutParams = layoutParams
|
||||
}
|
||||
animation.start()
|
||||
}
|
@ -96,13 +96,13 @@ class NewConversationButtonSetView : RelativeLayout {
|
||||
|
||||
fun expand() {
|
||||
animateImageViewColorChange(R.color.new_conversation_button_collapsed_background, R.color.accent)
|
||||
animateImageViewSizeChange(R.dimen.new_conversation_button_collapsed_size, R.dimen.new_conversation_button_expanded_size)
|
||||
imageView.animateSizeChange(R.dimen.new_conversation_button_collapsed_size, R.dimen.new_conversation_button_expanded_size, animationDuration)
|
||||
animateImageViewPositionChange(collapsedImageViewPosition, expandedImageViewPosition)
|
||||
}
|
||||
|
||||
fun collapse() {
|
||||
animateImageViewColorChange(R.color.accent, R.color.new_conversation_button_collapsed_background)
|
||||
animateImageViewSizeChange(R.dimen.new_conversation_button_expanded_size, R.dimen.new_conversation_button_collapsed_size)
|
||||
imageView.animateSizeChange(R.dimen.new_conversation_button_expanded_size, R.dimen.new_conversation_button_collapsed_size, animationDuration)
|
||||
animateImageViewPositionChange(expandedImageViewPosition, collapsedImageViewPosition)
|
||||
}
|
||||
|
||||
@ -119,21 +119,6 @@ class NewConversationButtonSetView : RelativeLayout {
|
||||
animation.start()
|
||||
}
|
||||
|
||||
private fun animateImageViewSizeChange(@DimenRes startSizeID: Int, @DimenRes endSizeID: Int) {
|
||||
val layoutParams = imageView.layoutParams
|
||||
val startSize = resources.getDimension(startSizeID)
|
||||
val endSize = resources.getDimension(endSizeID)
|
||||
val animation = ValueAnimator.ofObject(FloatEvaluator(), startSize, endSize)
|
||||
animation.duration = animationDuration
|
||||
animation.addUpdateListener { animator ->
|
||||
val size = animator.animatedValue as Float
|
||||
layoutParams.width = size.toInt()
|
||||
layoutParams.height = size.toInt()
|
||||
imageView.layoutParams = layoutParams
|
||||
}
|
||||
animation.start()
|
||||
}
|
||||
|
||||
private fun animateImageViewPositionChange(startPosition: PointF, endPosition: PointF) {
|
||||
val animation = ValueAnimator.ofObject(PointFEvaluator(), startPosition, endPosition)
|
||||
animation.duration = animationDuration
|
||||
|
Loading…
x
Reference in New Issue
Block a user