lebonprix.apk/java/io/xdrm/lebonprix/HomeActivity.kt

240 lines
7.7 KiB
Kotlin
Raw Permalink Normal View History

2018-12-15 11:17:28 +00:00
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.KeyEvent
2018-12-15 11:17:28 +00:00
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.setOnKeyListener { v, keyCode, event ->
if( event.action != KeyEvent.ACTION_DOWN || keyCode != KeyEvent.KEYCODE_ENTER )
return@setOnKeyListener false
2018-12-15 11:17:28 +00:00
launch_search()
return@setOnKeyListener true
2018-12-15 11:17:28 +00:00
}
search_button.setOnClickListener { launch_search() }
2018-12-15 11:17:28 +00:00
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 launch_search(){
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)
}
}
2018-12-15 11:17:28 +00:00
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<String> {
val list = mutableListOf<String>()
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
}
}