package io.xdrm.lebonprix import android.content.Intent import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.os.Handler import android.text.Editable import android.text.TextWatcher import android.util.Log import android.view.WindowManager import android.widget.Toast import io.xdrm.lebonprix.anim.HomeFilterAnimation import io.xdrm.lebonprix.anim.UnderlineAnimation import io.xdrm.lebonprix.api.CategoryFetcher import io.xdrm.lebonprix.api.PricesFetcher import io.xdrm.lebonprix.model.Category import io.xdrm.lebonprix.model.CategoryItem import io.xdrm.lebonprix.model.CategoryItemStore import io.xdrm.todoleast.adapter.CategoryAdapter import kotlinx.android.synthetic.main.activity_home.* import kotlinx.coroutines.* import okhttp3.OkHttpClient import org.json.JSONArray class HomeActivity : AppCompatActivity() { companion object { val SEARCH_KEY_TIMEOUT: Long = 500 } private val categoryStore = CategoryItemStore private val categoryAdapter = CategoryAdapter(CategoryItemStore.data) private lateinit var underline_animator: UnderlineAnimation private lateinit var load_animator: HomeFilterAnimation private var last_search_time: Long = 0 private var last_search: String = "" private var httpJob: Job? = null private val httpClient = OkHttpClient() private var ended = false private var loader: Job? = null private lateinit var apiCategories: CategoryFetcher private lateinit var apiPrices: PricesFetcher override fun onResume() { super.onResume() runOnUiThread { load_animator.stage(HomeFilterAnimation.CLEAR_ALL).during(0).start() } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.activity_home) // manage underline animation underline_animator = UnderlineAnimation(search_underline) load_animator = HomeFilterAnimation(applicationContext, filter) apiCategories = CategoryFetcher(this, search_underline, underline_animator, httpClient) apiPrices = PricesFetcher(this, httpClient) // listen for focus changes search.setOnFocusChangeListener{v, focus -> if( focus ) underline_animator.animate(0F, 1F).during(30).start() else underline_animator.animate(1F, 0F).during(30).start() } // listen for clicks search.setOnClickListener { underline_animator.animate(0F, 1F).during(30).start() } category_grid.adapter = categoryAdapter // launch category fetch search.addTextChangedListener(object : TextWatcher{ override fun afterTextChanged(s: Editable?) {} override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { categoryCoordinator(search.text.toString().trim()) // manage when key is pressed before the SEARCH_KEY_TIMEOUT is reached, so ignored Handler().postDelayed({ categoryCoordinator(search.text.toString().trim()) }, HomeActivity.SEARCH_KEY_TIMEOUT) } }) // launch search search_button.setOnClickListener { val selectedCategories = getCategories() // (1) Loader if( loader != null && loader!!.isActive ) loader!!.cancel() loader = GlobalScope.launch(Dispatchers.Main) { // launch animation load_animator.stage(HomeFilterAnimation.STAGE_CLEAN).during(300).start() delay(300) load_animator.stage(HomeFilterAnimation.STAGE_CENTER).during(300).start() delay(300) while(true){ load_animator.stage(HomeFilterAnimation.STAGE_LOAD).during(5000).start() delay(5000) } } if( httpJob != null && httpJob!!.isActive ) httpJob!!.cancel() httpJob = GlobalScope.launch { // exec request val prices = apiPrices.fetch(search.text.toString(), selectedCategories.toTypedArray()) loader?.cancel() // stop all if no result if( prices.isNullOrEmpty() ) { runOnUiThread { load_animator.stage(HomeFilterAnimation.CLEAR_ALL).during(0).start() } return@launch } // transition runOnUiThread { load_animator.stage(HomeFilterAnimation.STAGE_END).during(500).start() } delay(500) val int = Intent(this@HomeActivity, ResultActivity::class.java) int.putExtra("prices", prices) startActivity(int) overridePendingTransition(0, 0) } } updateCategories(JSONArray("[]")) } private fun categoryCoordinator(keywords: String){ val now = System.currentTimeMillis() if( last_search_time > 0 && now-last_search_time < HomeActivity.SEARCH_KEY_TIMEOUT ) return if( keywords == last_search ) return last_search_time = now last_search = keywords if( httpJob != null && httpJob!!.isActive ) { httpJob!!.cancel() underline_animator.animateContinue(1F).during(0).start() } httpJob = GlobalScope.launch { updateCategories( apiCategories.fetch(last_search) ) } } private fun updateCategories(categories: JSONArray){ // 1. Update categories categoryStore.data.clear() categoryStore.data.add(CategoryItem(Category.ALL, false, 1F)) // preselected var total = 0 for( i in 0..categories.length() ){ // extract features var label: String = "" var count: Int = 0 try { label = categories.getJSONArray(i).getString(0) count = categories.getJSONArray(i).getInt(1) }catch(e: Exception){ continue } total += count // try to parse val cat: Category = Category.fromLabel(label) ?: continue // add category categoryStore.data.add(CategoryItem(cat, false, count.toFloat())) // progress feedback val progress = 0.5F + 0.5*i/categories.length() runOnUiThread{ underline_animator.animateContinue(progress.toFloat()).during(200).start() } } for( i in 1..categories.length() ){ categoryStore.data[i].count /= total } // 3. update adapter runOnUiThread{ categoryAdapter.notifyDataSetChanged() underline_animator.animateContinue(1F).during(10).start() } } private fun getCategories() : MutableList { val list = mutableListOf() for( item in categoryStore.data ){ // not selected -> ignore if( !item.selected ) continue; // select all -> return empty if( item.category == Category.ALL ) return mutableListOf() // else, add each one list.add(item.category.label) } return list } }