mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-19 19:38:45 +00:00
Fix conversation deletion & public chat joining
This commit is contained in:
parent
fb3bd26538
commit
7da4f1f6ae
@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/contentView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
|
@ -1,14 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.v4.view.ViewPager
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/viewPager"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.design.widget.TabLayout
|
||||
style="@style/Session.DarkTabLayout"
|
||||
android:id="@+id/tabLayout"
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/viewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/tab_bar_height" />
|
||||
android:layout_height="match_parent" >
|
||||
|
||||
</android.support.v4.view.ViewPager>
|
||||
<android.support.design.widget.TabLayout
|
||||
style="@style/Session.DarkTabLayout"
|
||||
android:id="@+id/tabLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/tab_bar_height" />
|
||||
|
||||
</android.support.v4.view.ViewPager>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/loader"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#A4000000"
|
||||
android:visibility="gone"
|
||||
android:alpha="0">
|
||||
|
||||
<com.github.ybq.android.spinkit.SpinKitView
|
||||
style="@style/SpinKitView.Large.ThreeBounce"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_centerInParent="true"
|
||||
app:SpinKit_Color="@color/text" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</RelativeLayout>
|
@ -37,7 +37,7 @@
|
||||
<dimen name="large_spacing">24dp</dimen>
|
||||
<dimen name="very_large_spacing">35dp</dimen>
|
||||
<dimen name="massive_spacing">64dp</dimen>
|
||||
<dimen name="new_conversation_button_bottom_offset">40dp</dimen>
|
||||
<dimen name="new_conversation_button_bottom_offset">56dp</dimen>
|
||||
<dimen name="onboarding_button_bottom_offset">40dp</dimen>
|
||||
|
||||
<!-- Session -->
|
||||
|
@ -16,6 +16,19 @@
|
||||
<item name="android:textSize">@dimen/very_large_font_size</item>
|
||||
</style>
|
||||
|
||||
<style name="Session.AlertDialog" parent="ThemeOverlay.AppCompat.Dialog.Alert">
|
||||
<item name="buttonBarNegativeButtonStyle">@style/Session.AlertDialog.NegativeButtonStyle</item>
|
||||
<item name="buttonBarPositiveButtonStyle">@style/Session.AlertDialog.PositiveButtonStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="Session.AlertDialog.NegativeButtonStyle" parent="Widget.AppCompat.Button.ButtonBar.AlertDialog">
|
||||
<item name="android:textColor">@color/accent</item>
|
||||
</style>
|
||||
|
||||
<style name="Session.AlertDialog.PositiveButtonStyle" parent="Widget.AppCompat.Button.ButtonBar.AlertDialog">
|
||||
<item name="android:textColor">@color/accent</item>
|
||||
</style>
|
||||
|
||||
<style name="Session.DarkTabLayout" parent="Widget.Design.TabLayout">
|
||||
<item name="tabIndicatorColor">@color/accent</item>
|
||||
<item name="tabIndicatorHeight">@dimen/accent_line_thickness</item>
|
||||
|
@ -8,6 +8,7 @@
|
||||
<item name="colorPrimary">@color/action_bar_background</item>
|
||||
<item name="colorPrimaryDark">@color/action_bar_background</item>
|
||||
<item name="android:navigationBarColor">@color/navigation_bar_background</item>
|
||||
<item name="alertDialogTheme">@style/Session.AlertDialog</item>
|
||||
</style>
|
||||
|
||||
<style name="Session.DarkTheme.NoActionBar" parent="@style/Theme.AppCompat.NoActionBar">
|
||||
@ -15,6 +16,7 @@
|
||||
<item name="colorPrimary">@color/action_bar_background</item>
|
||||
<item name="colorPrimaryDark">@color/action_bar_background</item>
|
||||
<item name="android:navigationBarColor">@color/navigation_bar_background</item>
|
||||
<item name="alertDialogTheme">@style/Session.AlertDialog</item>
|
||||
</style>
|
||||
<!-- Session -->
|
||||
|
||||
|
@ -1,9 +1,7 @@
|
||||
package org.thoughtcrime.securesms.loki.redesign.activities
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.arch.lifecycle.Observer
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.database.Cursor
|
||||
import android.graphics.BitmapFactory
|
||||
@ -11,9 +9,10 @@ import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.support.design.widget.Snackbar
|
||||
import android.support.v4.app.LoaderManager
|
||||
import android.support.v4.content.Loader
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.support.v7.widget.LinearLayoutManager
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.support.v7.widget.helper.ItemTouchHelper
|
||||
@ -23,6 +22,7 @@ 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.ThreadDatabase
|
||||
import org.thoughtcrime.securesms.database.model.ThreadRecord
|
||||
import org.thoughtcrime.securesms.loki.getColorWithID
|
||||
import org.thoughtcrime.securesms.loki.redesign.utilities.push
|
||||
@ -48,6 +48,24 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
|
||||
super.onCreate(savedInstanceState, isReady)
|
||||
// Process any outstanding deletes
|
||||
val threadDatabase = DatabaseFactory.getThreadDatabase(this)
|
||||
val archivedConversationCount = threadDatabase.archivedConversationListCount
|
||||
if (archivedConversationCount > 0) {
|
||||
val archivedConversations = threadDatabase.archivedConversationList
|
||||
archivedConversations.moveToFirst()
|
||||
fun deleteThreadAtCurrentPosition() {
|
||||
val threadID = archivedConversations.getLong(archivedConversations.getColumnIndex(ThreadDatabase.ID))
|
||||
AsyncTask.execute {
|
||||
threadDatabase.deleteConversation(threadID)
|
||||
MessageNotifier.updateNotification(this)
|
||||
}
|
||||
}
|
||||
deleteThreadAtCurrentPosition()
|
||||
while (archivedConversations.moveToNext()) {
|
||||
deleteThreadAtCurrentPosition()
|
||||
}
|
||||
}
|
||||
// Set content view
|
||||
setContentView(R.layout.activity_home)
|
||||
// Set custom toolbar
|
||||
@ -106,7 +124,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
||||
}
|
||||
|
||||
override fun onLongConversationClick(view: ConversationView) {
|
||||
// TODO: Implement
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
private fun openConversation(thread: ThreadRecord) {
|
||||
@ -135,7 +153,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
private class SwipeCallback(val context: Context) : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
|
||||
private class SwipeCallback(val activity: HomeActivity) : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
|
||||
|
||||
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
|
||||
return false
|
||||
@ -143,51 +161,48 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||
val builder = AlertDialog.Builder(context)
|
||||
builder.setIconAttribute(R.attr.dialog_alert_icon)
|
||||
builder.setTitle("Delete Selected Conversation?")
|
||||
builder.setMessage("This will permanently delete the selected conversation.")
|
||||
builder.setCancelable(true)
|
||||
builder.setPositiveButton("Delete") { dialog, _ ->
|
||||
val threadID = (viewHolder as HomeAdapter.ViewHolder).view.thread!!.threadId
|
||||
AsyncTask.execute {
|
||||
DatabaseFactory.getThreadDatabase(context).deleteConversation(threadID)
|
||||
MessageNotifier.updateNotification(context)
|
||||
val threadID = (viewHolder as HomeAdapter.ViewHolder).view.thread!!.threadId
|
||||
val threadDatabase = DatabaseFactory.getThreadDatabase(activity)
|
||||
threadDatabase.archiveConversation(threadID)
|
||||
val deleteThread = object : Runnable {
|
||||
|
||||
override fun run() {
|
||||
AsyncTask.execute {
|
||||
threadDatabase.deleteConversation(threadID)
|
||||
MessageNotifier.updateNotification(activity)
|
||||
}
|
||||
}
|
||||
dialog.dismiss()
|
||||
}
|
||||
builder.setNegativeButton(android.R.string.cancel) { dialog, _ ->
|
||||
val animator = ValueAnimator.ofFloat(viewHolder.itemView.translationX, 0.0f)
|
||||
animator.duration = 150
|
||||
animator.addUpdateListener {
|
||||
update(viewHolder, animator.animatedValue as Float)
|
||||
}
|
||||
animator.start()
|
||||
dialog.dismiss()
|
||||
val handler = Handler()
|
||||
handler.postDelayed(deleteThread, 5000)
|
||||
val snackbar = Snackbar.make(activity.contentView, "Conversation Deleted", Snackbar.LENGTH_LONG)
|
||||
snackbar.setAction("Undo") {
|
||||
threadDatabase.unarchiveConversation(threadID)
|
||||
handler.removeCallbacks(deleteThread)
|
||||
animate(viewHolder, 0.0f)
|
||||
}
|
||||
builder.create().show()
|
||||
snackbar.setActionTextColor(activity.resources.getColorWithID(R.color.accent, activity.theme))
|
||||
snackbar.show()
|
||||
}
|
||||
|
||||
override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dx: Float, dy: Float, actionState: Int, isCurrentlyActive: Boolean) {
|
||||
if (actionState != ItemTouchHelper.ACTION_STATE_SWIPE) {
|
||||
super.onChildDraw(c, recyclerView, viewHolder, dx, dy, actionState, isCurrentlyActive)
|
||||
} else {
|
||||
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE && dx < 0) {
|
||||
val itemView = viewHolder.itemView
|
||||
if (dx < 0) {
|
||||
val backgroundPaint = Paint()
|
||||
backgroundPaint.color = context.resources.getColorWithID(R.color.destructive, context.theme)
|
||||
c.drawRect(itemView.right.toFloat() - abs(dx), itemView.top.toFloat(), itemView.right.toFloat(), itemView.bottom.toFloat(), backgroundPaint)
|
||||
val icon = BitmapFactory.decodeResource(context.resources, R.drawable.ic_trash_filled_32)
|
||||
val iconPaint = Paint()
|
||||
val left = itemView.right.toFloat() - abs(dx) + context.resources.getDimension(R.dimen.medium_spacing)
|
||||
val top = itemView.top.toFloat() + (itemView.bottom.toFloat() - itemView.top.toFloat() - icon.height) / 2
|
||||
c.drawBitmap(icon, left, top, iconPaint)
|
||||
}
|
||||
update(viewHolder, dx)
|
||||
animate(viewHolder, dx)
|
||||
val backgroundPaint = Paint()
|
||||
backgroundPaint.color = activity.resources.getColorWithID(R.color.destructive, activity.theme)
|
||||
c.drawRect(itemView.right.toFloat() - abs(dx), itemView.top.toFloat(), itemView.right.toFloat(), itemView.bottom.toFloat(), backgroundPaint)
|
||||
val icon = BitmapFactory.decodeResource(activity.resources, R.drawable.ic_trash_filled_32)
|
||||
val iconPaint = Paint()
|
||||
val left = itemView.right.toFloat() - abs(dx) + activity.resources.getDimension(R.dimen.medium_spacing)
|
||||
val top = itemView.top.toFloat() + (itemView.bottom.toFloat() - itemView.top.toFloat() - icon.height) / 2
|
||||
c.drawBitmap(icon, left, top, iconPaint)
|
||||
} else {
|
||||
super.onChildDraw(c, recyclerView, viewHolder, dx, dy, actionState, isCurrentlyActive)
|
||||
}
|
||||
}
|
||||
|
||||
private fun update(viewHolder: RecyclerView.ViewHolder, dx: Float) {
|
||||
private fun animate(viewHolder: RecyclerView.ViewHolder, dx: Float) {
|
||||
val alpha = 1.0f - abs(dx) / viewHolder.itemView.width.toFloat()
|
||||
viewHolder.itemView.alpha = alpha
|
||||
viewHolder.itemView.translationX = dx
|
||||
|
@ -1,17 +1,28 @@
|
||||
package org.thoughtcrime.securesms.loki.redesign.activities
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v4.app.FragmentPagerAdapter
|
||||
import android.util.Patterns
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.activity_join_public_chat.*
|
||||
import kotlinx.android.synthetic.main.fragment_enter_chat_url.*
|
||||
import network.loki.messenger.R
|
||||
import nl.komponents.kovenant.ui.failUi
|
||||
import nl.komponents.kovenant.ui.successUi
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil
|
||||
import org.thoughtcrime.securesms.loki.redesign.fragments.ScanQRCodeWrapperFragment
|
||||
import org.thoughtcrime.securesms.loki.redesign.fragments.ScanQRCodeWrapperFragmentDelegate
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
|
||||
class JoinPublicChatActivity : PassphraseRequiredActionBarActivity(), ScanQRCodeWrapperFragmentDelegate {
|
||||
private val adapter = JoinPublicChatActivityAdapter(this)
|
||||
@ -29,13 +40,48 @@ class JoinPublicChatActivity : PassphraseRequiredActionBarActivity(), ScanQRCode
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Updating
|
||||
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
|
||||
|
||||
// region Interaction
|
||||
override fun handleQRCodeScanned(url: String) {
|
||||
joinPublicChatIfPossible(url)
|
||||
}
|
||||
|
||||
fun joinPublicChatIfPossible(url: String) {
|
||||
// TODO: Implement
|
||||
if (!Patterns.WEB_URL.matcher(url).matches() || !url.startsWith("https://")) {
|
||||
return Toast.makeText(this, "Invalid URL", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
showLoader()
|
||||
val application = ApplicationContext.getInstance(this)
|
||||
val channel: Long = 1
|
||||
val displayName = TextSecurePreferences.getProfileName(this)
|
||||
val lokiPublicChatAPI = application.lokiPublicChatAPI!!
|
||||
application.lokiPublicChatManager.addChat(url, channel).successUi {
|
||||
lokiPublicChatAPI.getMessages(channel, url)
|
||||
lokiPublicChatAPI.setDisplayName(displayName, url)
|
||||
val profileKey: ByteArray = ProfileKeyUtil.getProfileKey(this)
|
||||
val profileUrl: String? = TextSecurePreferences.getProfileAvatarUrl(this)
|
||||
lokiPublicChatAPI.setProfilePicture(url, profileKey, profileUrl)
|
||||
finish()
|
||||
}.failUi {
|
||||
hideLoader()
|
||||
Toast.makeText(this, "Couldn't Join Public Chat", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
@ -83,7 +129,9 @@ class EnterChatURLFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun joinPublicChatIfPossible() {
|
||||
val chatURL = chatURLEditText.text.trim().toString()
|
||||
val inputMethodManager = context!!.getSystemService(BaseActionBarActivity.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
inputMethodManager.hideSoftInputFromWindow(chatURLEditText.windowToken, 0)
|
||||
val chatURL = chatURLEditText.text.trim().toString().toLowerCase().replace("http://", "https://")
|
||||
(activity!! as JoinPublicChatActivity).joinPublicChatIfPossible(chatURL)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user