Make autocomplete work locally

This commit is contained in:
Phillip Thelen 2019-03-14 19:50:21 +01:00
parent e23f5e033d
commit ccf873a359
10 changed files with 74 additions and 4 deletions

View file

@ -16,5 +16,9 @@
<key>spriteSubstitutions</key>
<value>{}</value>
</entry>
<entry>
<key>enableUsernameAutocomplete</key>
<value>false</value>
</entry>
</defaultsMap>
<!-- END xml_defaults -->

View file

@ -17,6 +17,7 @@ import com.amplitude.api.Amplitude
import com.amplitude.api.Identify
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.imagepipeline.core.ImagePipelineConfig
import com.google.firebase.iid.FirebaseInstanceId
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings
import com.habitrpg.android.habitica.api.HostConfig
@ -82,6 +83,7 @@ abstract class HabiticaBaseApplication : MultiDexApplication() {
setupRealm()
setupDagger()
setupRemoteConfig()
setupNotifications()
refWatcher = LeakCanary.install(this)
setupInstabug()
createBillingAndCheckout()
@ -216,6 +218,23 @@ abstract class HabiticaBaseApplication : MultiDexApplication() {
}
}
private fun setupNotifications() {
FirebaseInstanceId.getInstance().instanceId.addOnCompleteListener { task ->
if (!task.isSuccessful) {
Log.w("Token", "getInstanceId failed", task.exception)
return@addOnCompleteListener
}
// Get new Instance ID token
val token = task.result?.token
// Log and toast
if (BuildConfig.DEBUG) {
Log.d("Token", "Firebase Notification Token: $token")
}
}
}
companion object {
var component: AppComponent? = null

View file

@ -6,10 +6,12 @@ import com.habitrpg.android.habitica.data.local.SocialLocalRepository
import com.habitrpg.android.habitica.extensions.notNull
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.AchievementResult
import com.habitrpg.android.habitica.models.auth.LocalAuthentication
import com.habitrpg.android.habitica.models.inventory.Quest
import com.habitrpg.android.habitica.models.members.Member
import com.habitrpg.android.habitica.models.responses.PostChatMessageResult
import com.habitrpg.android.habitica.models.social.*
import com.habitrpg.android.habitica.models.user.Authentication
import com.habitrpg.android.habitica.models.user.User
import io.reactivex.Flowable
import io.reactivex.Single

View file

@ -2,6 +2,7 @@ package com.habitrpg.android.habitica.data.local
import com.habitrpg.android.habitica.models.members.Member
import com.habitrpg.android.habitica.models.social.ChatMessage
import com.habitrpg.android.habitica.models.social.FindUsernameResult
import com.habitrpg.android.habitica.models.social.Group
import com.habitrpg.android.habitica.models.social.GroupMembership
import com.habitrpg.android.habitica.models.user.User

View file

@ -46,4 +46,8 @@ class RemoteConfigManager {
fun supportEmail(): String {
return remoteConfig.getString("supportEmail")
}
fun enableUsernameAutocomplete(): Boolean {
return remoteConfig.getBoolean("enableUsernameAutocomplete")
}
}

View file

@ -3,6 +3,7 @@ package com.habitrpg.android.habitica.models.social
import com.google.gson.annotations.SerializedName
import com.habitrpg.android.habitica.models.user.Authentication
import com.habitrpg.android.habitica.models.user.ContributorInfo
import com.habitrpg.android.habitica.models.user.Profile
import io.realm.annotations.PrimaryKey
class FindUsernameResult {
@ -12,6 +13,7 @@ class FindUsernameResult {
var contributor: ContributorInfo? = null
var authentication: Authentication? = null
var profile: Profile? = null
val username: String?
get() = authentication?.localAuthentication?.username

View file

@ -228,6 +228,7 @@ class ChatFragment constructor() : BaseFragment(), SwipeRefreshLayout.OnRefreshL
private fun setChatMessages(chatMessages: RealmResults<ChatMessage>) {
chatAdapter?.updateData(chatMessages)
chatBarView.chatMessages = viewModel.socialRepository.getUnmanagedCopy(chatMessages)
recyclerView.scrollToPosition(0)
viewModel.gotNewMessages = true

View file

@ -290,6 +290,7 @@ class ChatListFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener {
private fun setChatMessages(chatMessages: RealmResults<ChatMessage>) {
chatAdapter?.updateData(chatMessages)
chatBarView.chatMessages = socialRepository.getUnmanagedCopy(chatMessages)
recyclerView.scrollToPosition(0)
gotNewMessages = true

View file

@ -11,14 +11,21 @@ import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.data.SocialRepository
import com.habitrpg.android.habitica.extensions.dpToPx
import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.auth.LocalAuthentication
import com.habitrpg.android.habitica.models.social.ChatMessage
import com.habitrpg.android.habitica.models.social.FindUsernameResult
import com.habitrpg.android.habitica.models.user.Authentication
import com.habitrpg.android.habitica.models.user.Profile
import com.habitrpg.android.habitica.ui.views.social.UsernameLabel
import io.reactivex.functions.Consumer
import net.pherth.android.emoji_library.EmojiMap
import net.pherth.android.emoji_library.EmojiParser
import net.pherth.android.emoji_library.EmojiTextView
import java.util.Date
class AutocompleteAdapter(val context: Context, val socialRepository: SocialRepository? = null, var autocompleteContext: String? = null, var groupID: String? = null) : BaseAdapter(), Filterable {
class AutocompleteAdapter(val context: Context, val socialRepository: SocialRepository? = null, var autocompleteContext: String? = null, var groupID: String? = null, val remoteAutocomplete: Boolean = false) : BaseAdapter(), Filterable {
var chatMessages: List<ChatMessage> = arrayListOf()
private var userResults: List<FindUsernameResult> = arrayListOf()
private var emojiResults: List<String> = arrayListOf()
private var isAutocompletingUsers = true
@ -29,7 +36,7 @@ class AutocompleteAdapter(val context: Context, val socialRepository: SocialRepo
override fun performFiltering(constraint: CharSequence?): FilterResults {
val filterResults = FilterResults()
if (constraint != null && constraint.isNotEmpty()) {
if (constraint[0] == '@' && constraint.length >= 3 && socialRepository != null) {
if (constraint[0] == '@' && constraint.length >= 3 && socialRepository != null && remoteAutocomplete) {
if (Date().time - lastAutocomplete > 2000) {
lastAutocomplete = Date().time
userResults = arrayListOf()
@ -43,6 +50,24 @@ class AutocompleteAdapter(val context: Context, val socialRepository: SocialRepo
filterResults.values = userResults
filterResults.count = userResults.size
}
} else if (constraint[0] == '@') {
lastAutocomplete = Date().time
isAutocompletingUsers = true
userResults = chatMessages.distinctBy {
it.username
}.filter { it.username?.startsWith(constraint.toString().drop(1)) ?: false }.map {message ->
val result = FindUsernameResult()
result.authentication = Authentication()
result.authentication?.localAuthentication = LocalAuthentication()
result.authentication?.localAuthentication?.userID = message.uuid
result.authentication?.localAuthentication?.username = message.username
result.contributor = message.contributor
result.profile = Profile()
result.profile?.name = message.user
result
}
filterResults.values = userResults
filterResults.count = userResults.size
} else if (constraint[0] == ':') {
isAutocompletingUsers = false
emojiResults = EmojiMap.invertedEmojiMap.keys.filter { it.startsWith(constraint) }
@ -68,7 +93,7 @@ class AutocompleteAdapter(val context: Context, val socialRepository: SocialRepo
val view = parent?.inflate(R.layout.autocomplete_username)
val result = getItem(position) as? FindUsernameResult
val displaynameView = view?.findViewById<UsernameLabel>(R.id.display_name_view)
displaynameView?.username = result?.username
displaynameView?.username = result?.profile?.name
displaynameView?.tier = result?.contributor?.level ?: 0
view?.findViewById<TextView>(R.id.username_view)?.text = result?.formattedUsername
view

View file

@ -13,6 +13,8 @@ import androidx.core.view.updateLayoutParams
import com.habitrpg.android.habitica.HabiticaBaseApplication
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.data.SocialRepository
import com.habitrpg.android.habitica.helpers.RemoteConfigManager
import com.habitrpg.android.habitica.models.social.ChatMessage
import com.habitrpg.android.habitica.ui.helpers.AutocompleteAdapter
import com.habitrpg.android.habitica.ui.helpers.AutocompleteTokenizer
import com.habitrpg.android.habitica.ui.helpers.NavbarUtils
@ -25,6 +27,9 @@ class ChatBarView : FrameLayout {
@Inject
lateinit var socialRepository: SocialRepository
@Inject
lateinit var remoteConfig: RemoteConfigManager
private val sendButton: ImageButton by bindView(R.id.sendButton)
private val chatEditText: MultiAutoCompleteTextView by bindView(R.id.chatEditText)
private val textIndicator: TextView by bindView(R.id.text_indicator)
@ -32,6 +37,12 @@ class ChatBarView : FrameLayout {
private val spacing: Space by bindView(R.id.spacing)
private var navBarAccountedHeightCalculated = false
var chatMessages: List<ChatMessage>
get() = autocompleteAdapter?.chatMessages ?: listOf()
set(value) {
autocompleteAdapter?.chatMessages = value
}
internal var maxChatLength = 3000L
var sendAction: ((String) -> Unit)? = null
@ -78,7 +89,7 @@ class ChatBarView : FrameLayout {
resizeForDrawingUnderNavbar()
autocompleteAdapter = AutocompleteAdapter(context, socialRepository, autocompleteContext, groupID)
autocompleteAdapter = AutocompleteAdapter(context, socialRepository, autocompleteContext, groupID, remoteConfig.enableUsernameAutocomplete())
chatEditText.setAdapter(autocompleteAdapter)
chatEditText.threshold = 2