diff --git a/res/anim/fade_scale_out.xml b/res/anim/fade_scale_out.xml index 2ee729071b..c87edc7ee6 100644 --- a/res/anim/fade_scale_out.xml +++ b/res/anim/fade_scale_out.xml @@ -1,7 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> -<set xmlns:android="http://schemas.android.com/apk/res/android" +<set + xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/decelerate_interpolator"> + <scale android:duration="150" android:fromXScale="1.0" @@ -10,8 +12,10 @@ android:toYScale="0.85" android:pivotX="50%" android:pivotY="50%" /> + <alpha android:duration="150" android:fromAlpha="1.0" android:toAlpha="0.6" /> + </set> \ No newline at end of file diff --git a/res/anim/slide_from_left.xml b/res/anim/slide_from_left.xml index 7e00a0272f..5369636d1e 100644 --- a/res/anim/slide_from_left.xml +++ b/res/anim/slide_from_left.xml @@ -1,9 +1,12 @@ <?xml version="1.0" encoding="utf-8"?> -<set xmlns:android="http://schemas.android.com/apk/res/android" - android:interpolator="@android:anim/decelerate_interpolator"> +<set + xmlns:android="http://schemas.android.com/apk/res/android" + android:interpolator="@android:anim/decelerate_interpolator"> + <translate - android:duration="250" + android:duration="150" android:fromXDelta="-100%" android:toXDelta="0%" /> + </set> \ No newline at end of file diff --git a/res/anim/slide_from_right.xml b/res/anim/slide_from_right.xml index feeaaf7513..f94fbcc957 100644 --- a/res/anim/slide_from_right.xml +++ b/res/anim/slide_from_right.xml @@ -1,9 +1,12 @@ <?xml version="1.0" encoding="utf-8"?> -<set xmlns:android="http://schemas.android.com/apk/res/android" - android:interpolator="@android:anim/decelerate_interpolator"> +<set + xmlns:android="http://schemas.android.com/apk/res/android" + android:interpolator="@android:anim/decelerate_interpolator"> + <translate - android:duration="250" + android:duration="150" android:fromXDelta="100%" android:toXDelta="0%" /> + </set> \ No newline at end of file diff --git a/res/drawable/conversation_view_background.xml b/res/drawable/conversation_view_background.xml new file mode 100644 index 0000000000..ee5f321c99 --- /dev/null +++ b/res/drawable/conversation_view_background.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<ripple + xmlns:android="http://schemas.android.com/apk/res/android" + android:color="@color/cell_selected"> + + <item> + <color android:color="@color/cell_background" /> + </item> +</ripple> \ No newline at end of file diff --git a/res/layout/activity_home.xml b/res/layout/activity_home.xml index 6a47433f51..4dc06c5cc3 100644 --- a/res/layout/activity_home.xml +++ b/res/layout/activity_home.xml @@ -25,6 +25,7 @@ android:background="@drawable/new_conversation_button_background" /> <Button + android:id="@+id/newConversationButton" android:layout_width="@dimen/new_conversation_button_size" android:layout_height="@dimen/new_conversation_button_size" android:layout_centerInParent="true" diff --git a/res/layout/conversation_view.xml b/res/layout/conversation_view.xml index f2977dd4bb..d91fbee0d4 100644 --- a/res/layout/conversation_view.xml +++ b/res/layout/conversation_view.xml @@ -3,7 +3,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@color/cell_background" + android:background="@drawable/conversation_view_background" android:orientation="horizontal" android:gravity="center_vertical"> @@ -31,12 +31,15 @@ <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="horizontal"> + android:orientation="horizontal" + android:gravity="center_vertical"> <TextView android:id="@+id/displayNameTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:maxLines="1" + android:ellipsize="end" android:textSize="@dimen/medium_font_size" android:textStyle="bold" android:textColor="@color/text" @@ -52,6 +55,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/medium_spacing" + android:maxLines="1" + android:ellipsize="end" android:textSize="@dimen/small_font_size" android:textColor="@color/text" android:alpha="0.4" @@ -62,12 +67,15 @@ <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="horizontal"> + android:orientation="horizontal" + android:gravity="center_vertical"> <TextView android:id="@+id/snippetTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:maxLines="1" + android:ellipsize="end" android:textSize="@dimen/medium_font_size" android:textColor="@color/text" android:text="Sorry, gotta go fight crime again" /> diff --git a/src/org/thoughtcrime/securesms/loki/redesign/activities/DisplayNameActivity.kt b/src/org/thoughtcrime/securesms/loki/redesign/activities/DisplayNameActivity.kt index 95ee82b41d..5bb483e7c5 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/activities/DisplayNameActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/activities/DisplayNameActivity.kt @@ -10,6 +10,7 @@ import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.BaseActionBarActivity import org.thoughtcrime.securesms.ConversationListActivity import org.thoughtcrime.securesms.database.DatabaseFactory +import org.thoughtcrime.securesms.loki.redesign.utilities.push import org.thoughtcrime.securesms.loki.redesign.utilities.setUpActionBarSessionLogo import org.thoughtcrime.securesms.util.TextSecurePreferences import org.whispersystems.signalservice.api.crypto.ProfileCipher @@ -54,6 +55,6 @@ class DisplayNameActivity : BaseActionBarActivity() { servers.forEach { publicChatAPI.setDisplayName(displayName, it) } } startActivity(Intent(this, ConversationListActivity::class.java)) - finish() + push(intent) } } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/redesign/activities/HomeActivity.kt b/src/org/thoughtcrime/securesms/loki/redesign/activities/HomeActivity.kt index 099199fb86..e1f50616a8 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/activities/HomeActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/activities/HomeActivity.kt @@ -1,15 +1,21 @@ package org.thoughtcrime.securesms.loki.redesign.activities +import android.content.Intent import android.os.Bundle import android.support.v7.widget.LinearLayoutManager import kotlinx.android.synthetic.main.activity_home.* import network.loki.messenger.R import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity +import org.thoughtcrime.securesms.conversation.ConversationActivity import org.thoughtcrime.securesms.database.DatabaseFactory +import org.thoughtcrime.securesms.database.model.ThreadRecord +import org.thoughtcrime.securesms.loki.NewConversationActivity +import org.thoughtcrime.securesms.loki.redesign.utilities.push +import org.thoughtcrime.securesms.loki.redesign.views.ConversationView import org.thoughtcrime.securesms.util.TextSecurePreferences -class HomeActivity : PassphraseRequiredActionBarActivity { +class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListener { constructor() : super() @@ -21,8 +27,12 @@ class HomeActivity : PassphraseRequiredActionBarActivity { supportActionBar!!.title = "Messages" // Set up recycler view val cursor = DatabaseFactory.getThreadDatabase(this).conversationList - recyclerView.adapter = ConversationAdapter(this, cursor) + val conversationAdapter = ConversationAdapter(this, cursor) + conversationAdapter.conversationClickListener = this + recyclerView.adapter = conversationAdapter recyclerView.layoutManager = LinearLayoutManager(this) + // Set up new conversation button + newConversationButton.setOnClickListener { createPrivateChat() } // Set up public chats and RSS feeds if needed if (TextSecurePreferences.getLocalNumber(this) != null) { val application = ApplicationContext.getInstance(this) @@ -32,4 +42,29 @@ class HomeActivity : PassphraseRequiredActionBarActivity { application.startRSSFeedPollersIfNeeded() } } + + override fun onConversationClick(view: ConversationView) { + val thread = view.thread ?: return + openConversation(thread) + } + + override fun onLongConversationClick(view: ConversationView) { + // TODO: Implement + } + + private fun openConversation(thread: ThreadRecord) { + val intent = Intent(this, ConversationActivity::class.java) + intent.putExtra(ConversationActivity.ADDRESS_EXTRA, thread.recipient.getAddress()) + intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, thread.threadId) + intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, thread.distributionType) + intent.putExtra(ConversationActivity.TIMING_EXTRA, System.currentTimeMillis()) + intent.putExtra(ConversationActivity.LAST_SEEN_EXTRA, thread.lastSeen) + intent.putExtra(ConversationActivity.STARTING_POSITION_EXTRA, -1) + push(intent) + } + + private fun createPrivateChat() { + val intent = Intent(this, NewConversationActivity::class.java) + startActivity(intent) + } } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/redesign/activities/LandingActivity.kt b/src/org/thoughtcrime/securesms/loki/redesign/activities/LandingActivity.kt index d1204e6dd4..b7231db086 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/activities/LandingActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/activities/LandingActivity.kt @@ -5,6 +5,7 @@ import android.os.Bundle import kotlinx.android.synthetic.main.activity_landing.* import network.loki.messenger.R import org.thoughtcrime.securesms.BaseActionBarActivity +import org.thoughtcrime.securesms.loki.redesign.utilities.push import org.thoughtcrime.securesms.loki.redesign.utilities.setUpActionBarSessionLogo class LandingActivity : BaseActionBarActivity() { @@ -20,11 +21,11 @@ class LandingActivity : BaseActionBarActivity() { private fun register() { val intent = Intent(this, RegisterActivity::class.java) - startActivity(intent) + push(intent) } private fun restore() { val intent = Intent(this, RestoreActivity::class.java) - startActivity(intent) + push(intent) } } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/redesign/activities/RegisterActivity.kt b/src/org/thoughtcrime/securesms/loki/redesign/activities/RegisterActivity.kt index ff73be7db8..6e7aa93f94 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/activities/RegisterActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/activities/RegisterActivity.kt @@ -18,6 +18,7 @@ import org.thoughtcrime.securesms.crypto.IdentityKeyUtil import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.IdentityDatabase +import org.thoughtcrime.securesms.loki.redesign.utilities.push import org.thoughtcrime.securesms.loki.redesign.utilities.setUpActionBarSessionLogo import org.thoughtcrime.securesms.util.Base64 import org.thoughtcrime.securesms.util.Hex @@ -103,7 +104,7 @@ class RegisterActivity : BaseActionBarActivity() { true, System.currentTimeMillis(), true) TextSecurePreferences.setLocalNumber(this, userHexEncodedPublicKey) val intent = Intent(this, DisplayNameActivity::class.java) - startActivity(intent) + push(intent) } private fun copyPublicKey() { diff --git a/src/org/thoughtcrime/securesms/loki/redesign/activities/RestoreActivity.kt b/src/org/thoughtcrime/securesms/loki/redesign/activities/RestoreActivity.kt index ffc4105758..6cf18b0670 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/activities/RestoreActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/activities/RestoreActivity.kt @@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.crypto.IdentityKeyUtil import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.IdentityDatabase +import org.thoughtcrime.securesms.loki.redesign.utilities.push import org.thoughtcrime.securesms.loki.redesign.utilities.setUpActionBarSessionLogo import org.thoughtcrime.securesms.util.Base64 import org.thoughtcrime.securesms.util.Hex @@ -92,7 +93,7 @@ class RestoreActivity : BaseActionBarActivity() { true, System.currentTimeMillis(), true) TextSecurePreferences.setLocalNumber(this, userHexEncodedPublicKey) val intent = Intent(this, DisplayNameActivity::class.java) - startActivity(intent) + push(intent) } catch (e: Exception) { val message = if (e is MnemonicCodec.DecodingError) e.description else MnemonicCodec.DecodingError.Generic.description return Toast.makeText(this, message, Toast.LENGTH_SHORT).show() diff --git a/src/org/thoughtcrime/securesms/loki/redesign/utilities/ActivityUtilities.kt b/src/org/thoughtcrime/securesms/loki/redesign/utilities/ActivityUtilities.kt index d112684e0f..316ec8a503 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/utilities/ActivityUtilities.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/utilities/ActivityUtilities.kt @@ -1,5 +1,6 @@ package org.thoughtcrime.securesms.loki.redesign.utilities +import android.content.Intent import android.support.v7.app.ActionBar import android.support.v7.app.AppCompatActivity import android.view.Gravity @@ -18,4 +19,9 @@ fun AppCompatActivity.setUpActionBarSessionLogo() { val logoImageViewContainerLayoutParams = ActionBar.LayoutParams(ActionBar.LayoutParams.MATCH_PARENT, ActionBar.LayoutParams.WRAP_CONTENT) supportActionBar!!.setCustomView(logoImageViewContainer, logoImageViewContainerLayoutParams) supportActionBar!!.setDisplayShowCustomEnabled(true) +} + +fun AppCompatActivity.push(intent: Intent) { + startActivity(intent) + overridePendingTransition(R.anim.slide_from_right, R.anim.fade_scale_out) } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/redesign/views/ConversationView.kt b/src/org/thoughtcrime/securesms/loki/redesign/views/ConversationView.kt index 647699a844..c2d292ee1e 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/views/ConversationView.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/views/ConversationView.kt @@ -1,14 +1,22 @@ package org.thoughtcrime.securesms.loki.redesign.views import android.content.Context +import android.graphics.Typeface import android.util.AttributeSet import android.view.LayoutInflater +import android.view.View import android.view.ViewGroup import android.widget.LinearLayout +import kotlinx.android.synthetic.main.conversation_view.view.* import network.loki.messenger.R import org.thoughtcrime.securesms.database.model.ThreadRecord +import org.thoughtcrime.securesms.loki.LokiAPIUtilities.populateUserHexEncodedPublicKeyCacheIfNeeded +import org.thoughtcrime.securesms.loki.MentionUtilities.highlightMentions +import org.thoughtcrime.securesms.util.DateUtils +import java.util.* class ConversationView : LinearLayout { + var thread: ThreadRecord? = null // region Lifecycle companion object { @@ -29,7 +37,16 @@ class ConversationView : LinearLayout { // region Updating fun bind(thread: ThreadRecord) { - + this.thread = thread + populateUserHexEncodedPublicKeyCacheIfNeeded(thread.threadId, context) // FIXME: This is a terrible place to do this + unreadMessagesIndicatorView.visibility = if (thread.unreadCount > 0) View.VISIBLE else View.INVISIBLE + val senderDisplayName = if (thread.recipient.isLocalNumber) context.getString(R.string.note_to_self) else thread.recipient.name + displayNameTextView.text = senderDisplayName + timestampTextView.text = DateUtils.getBriefRelativeTimeSpanString(context, Locale.getDefault(), thread.date) + val rawSnippet = thread.getDisplayBody(context) + val snippet = highlightMentions(rawSnippet, thread.threadId, context) + snippetTextView.text = snippet + snippetTextView.typeface = if (thread.unreadCount > 0) Typeface.DEFAULT_BOLD else Typeface.DEFAULT } // endregion } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/redesign/views/FakeChatView.kt b/src/org/thoughtcrime/securesms/loki/redesign/views/FakeChatView.kt index 74a14ed4eb..88a739beb5 100644 --- a/src/org/thoughtcrime/securesms/loki/redesign/views/FakeChatView.kt +++ b/src/org/thoughtcrime/securesms/loki/redesign/views/FakeChatView.kt @@ -10,7 +10,6 @@ import android.widget.ScrollView import kotlinx.android.synthetic.main.fake_chat_content_view.view.* import network.loki.messenger.R - class FakeChatView : ScrollView { // region Settings