<commit_before>package org.stepic.droid.core.presenters

import io.reactivex.Observable
import io.reactivex.Scheduler
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.subjects.PublishSubject
import org.stepic.droid.analytic.Analytic
import org.stepic.droid.di.qualifiers.BackgroundScheduler
import org.stepic.droid.di.qualifiers.MainScheduler
import org.stepic.droid.storage.operations.DatabaseFacade
import org.stepic.droid.ui.adapters.SearchQueriesAdapter
import org.stepic.droid.ui.custom.AutoCompleteSearchView
import org.stepic.droid.web.Api
import java.util.concurrent.TimeUnit
import javax.inject.Inject


class SearchSuggestionsPresenter
@Inject constructor(
        private val api: Api,
        private val databaseFacade: DatabaseFacade,
        private val analytic: Analytic,
        @BackgroundScheduler
        private val scheduler: Scheduler,
        @MainScheduler
        private val mainScheduler: Scheduler
        ) : PresenterBase<AutoCompleteSearchView>() {

    companion object {
        private const val AUTOCOMPLETE_DEBOUNCE_MS = 300L
        private const val DB_ELEMENTS_COUNT = 2
    }

    private val compositeDisposable = CompositeDisposable()
    private var searchQueriesAdapter: SearchQueriesAdapter? = null
    private val publisher = PublishSubject.create<String>()

    override fun attachView(view: AutoCompleteSearchView) {
        super.attachView(view)
        initSearchView(view)
    }

    private fun initSearchView(searchView: AutoCompleteSearchView) {
        val compositeDisposable = CompositeDisposable()
        val adapter = searchView.searchQueriesAdapter

        val queryPublisher = publisher
                .debounce(AUTOCOMPLETE_DEBOUNCE_MS, TimeUnit.MILLISECONDS)
                .subscribeOn(scheduler)

        compositeDisposable.add(queryPublisher
                .flatMap { query -> Observable.fromCallable { databaseFacade.getSearchQueries(query, DB_ELEMENTS_COUNT) }.onErrorResumeNext(Observable.empty()) }
                .observeOn(mainScheduler)
                .subscribe({ adapter.rawDBItems = it }, { e -> e.printStackTrace() }))

        compositeDisposable.add(queryPublisher
                .flatMap { query -> api.getSearchQueries(query).toObservable().onErrorResumeNext(Observable.empty()) }
                .observeOn(mainScheduler)
                .subscribe({ adapter.rawAPIItems = it.queries }, { e -> e.printStackTrace() }))
        searchQueriesAdapter = adapter
    }

    fun onQueryTextChange(query: String) {
        searchQueriesAdapter?.constraint = query
        publisher.onNext(query)
    }

    fun onQueryTextSubmit(query: String) {
        analytic.reportEventWithName(Analytic.Search.SEARCH_SUBMITTED, query)
    }

    fun refreshSuggestions() {
        searchQueriesAdapter?.let {
            publisher.onNext(it.constraint)
        }
    }

    override fun detachView(view: AutoCompleteSearchView) {
        compositeDisposable.dispose()
        searchQueriesAdapter = null
        super.detachView(view)
    }
}<commit_msg>use clear instead of dispose to preserve ability of adding new disposables<commit_after>package org.stepic.droid.core.presenters

import io.reactivex.Observable
import io.reactivex.Scheduler
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.subjects.PublishSubject
import org.stepic.droid.analytic.Analytic
import org.stepic.droid.di.qualifiers.BackgroundScheduler
import org.stepic.droid.di.qualifiers.MainScheduler
import org.stepic.droid.storage.operations.DatabaseFacade
import org.stepic.droid.ui.adapters.SearchQueriesAdapter
import org.stepic.droid.ui.custom.AutoCompleteSearchView
import org.stepic.droid.web.Api
import java.util.concurrent.TimeUnit
import javax.inject.Inject


class SearchSuggestionsPresenter
@Inject constructor(
        private val api: Api,
        private val databaseFacade: DatabaseFacade,
        private val analytic: Analytic,
        @BackgroundScheduler
        private val scheduler: Scheduler,
        @MainScheduler
        private val mainScheduler: Scheduler
        ) : PresenterBase<AutoCompleteSearchView>() {

    companion object {
        private const val AUTOCOMPLETE_DEBOUNCE_MS = 300L
        private const val DB_ELEMENTS_COUNT = 2
    }

    private val compositeDisposable = CompositeDisposable()
    private var searchQueriesAdapter: SearchQueriesAdapter? = null
    private val publisher = PublishSubject.create<String>()

    override fun attachView(view: AutoCompleteSearchView) {
        super.attachView(view)
        initSearchView(view)
    }

    private fun initSearchView(searchView: AutoCompleteSearchView) {
        val compositeDisposable = CompositeDisposable()
        val adapter = searchView.searchQueriesAdapter

        val queryPublisher = publisher
                .debounce(AUTOCOMPLETE_DEBOUNCE_MS, TimeUnit.MILLISECONDS)
                .subscribeOn(scheduler)

        compositeDisposable.add(queryPublisher
                .flatMap { query -> Observable.fromCallable { databaseFacade.getSearchQueries(query, DB_ELEMENTS_COUNT) }.onErrorResumeNext(Observable.empty()) }
                .observeOn(mainScheduler)
                .subscribe({ adapter.rawDBItems = it }, { e -> e.printStackTrace() }))

        compositeDisposable.add(queryPublisher
                .flatMap { query -> api.getSearchQueries(query).toObservable().onErrorResumeNext(Observable.empty()) }
                .observeOn(mainScheduler)
                .subscribe({ adapter.rawAPIItems = it.queries }, { e -> e.printStackTrace() }))
        searchQueriesAdapter = adapter
    }

    fun onQueryTextChange(query: String) {
        searchQueriesAdapter?.constraint = query
        publisher.onNext(query)
    }

    fun onQueryTextSubmit(query: String) {
        analytic.reportEventWithName(Analytic.Search.SEARCH_SUBMITTED, query)
    }

    fun refreshSuggestions() {
        searchQueriesAdapter?.let {
            publisher.onNext(it.constraint)
        }
    }

    override fun detachView(view: AutoCompleteSearchView) {
        compositeDisposable.clear()
        searchQueriesAdapter = null
        super.detachView(view)
    }
}
{'fraction_non_alphanumeric': 0.0798312510141165, 'fraction_numerical': 0.0012980691221807562, 'mean_word_length': 3.2451790633608817, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5662354', 'n_tokens_mistral': 1779, 'n_tokens_neox': 1688, 'n_words': 311}