PlanningFragment.kt 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. package ml.adamsprogs.bimba.fragments
  2. import android.content.Context
  3. import android.os.Build
  4. import android.os.Bundle
  5. import androidx.fragment.app.Fragment
  6. import android.view.LayoutInflater
  7. import android.view.View
  8. import android.view.ViewGroup
  9. import androidx.appcompat.app.AppCompatActivity
  10. import androidx.appcompat.widget.Toolbar
  11. import com.google.android.material.appbar.AppBarLayout
  12. import ml.adamsprogs.bimba.R
  13. import ml.adamsprogs.bimba.activities.MainActivity
  14. import com.pedromassango.ibackdrop.Backdrop
  15. import kotlinx.android.synthetic.main.fragment_planning.view.*
  16. import android.text.Spanned
  17. import android.text.style.ImageSpan
  18. import com.google.android.material.chip.ChipDrawable
  19. import android.widget.*
  20. import android.graphics.drawable.Drawable
  21. import android.graphics.Canvas
  22. import android.graphics.Paint
  23. import android.text.Editable
  24. import android.text.SpannableStringBuilder
  25. import android.util.TypedValue
  26. import ml.adamsprogs.bimba.views.StopAutoCompleteTextView
  27. class PlanningFragment : Fragment(), MainActivity.OnActivityActionListener {
  28. private lateinit var root: View
  29. private lateinit var toolbar: Toolbar
  30. override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
  31. savedInstanceState: Bundle?): View? {
  32. root = inflater.inflate(R.layout.fragment_planning, container, false)
  33. root.post {
  34. val height = root.measuredHeight
  35. with(root.findViewById<Backdrop>(R.id.backdrop_view)) {
  36. val px = TypedValue.applyDimension(
  37. TypedValue.COMPLEX_UNIT_DIP,
  38. 48f, resources.displayMetrics).toInt()
  39. backdropSize = height - px
  40. buildWithToolbar(toolbar)
  41. root.arrow_icon.visibility = View.VISIBLE
  42. openBackdrop()
  43. setOnSwitchListener(object : Backdrop.OnSwitchListener {
  44. override fun onSwitch(hidden: Boolean) {
  45. root.arrow_icon.visibility = if (hidden) View.VISIBLE else View.GONE
  46. }
  47. })
  48. root.arrow_icon.setOnClickListener {
  49. closeBackdrop()
  50. }
  51. }
  52. }
  53. val activity = context as AppCompatActivity
  54. val appBarLayout = activity.findViewById<AppBarLayout>(R.id.appbar)
  55. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  56. appBarLayout.outlineProvider = null
  57. }
  58. toolbar = activity.findViewById(R.id.toolbar)
  59. StopsAutoCompleteEditText(root.from_input as StopAutoCompleteTextView, context as Context)
  60. StopsAutoCompleteEditText(root.to_input as StopAutoCompleteTextView, context as Context)
  61. root.search_button.setOnClickListener {
  62. // todo
  63. }
  64. return root
  65. }
  66. override fun onDetach() {
  67. super.onDetach()
  68. toolbar.navigationIcon = null
  69. }
  70. /*private fun getStops(view: EditText): HashSet<String> {
  71. val result: HashSet<String> = HashSet(1)
  72. for (s in view.text.toString().split(";")) {
  73. result.add(s)
  74. }
  75. return result
  76. }
  77. private fun search(view: View) {
  78. val x = Calendar.getInstance()
  79. val t = time.text.toString().split(":")
  80. x.set(Calendar.HOUR_OF_DAY, t[0].toInt())
  81. x.set(Calendar.MINUTE, t[1].toInt())
  82. route.text = RouteFinder.findRoute(getStops(start), getStops(end), x, context!!)
  83. for (i in 1..6) {
  84. x.add(Calendar.MINUTE, 6)
  85. val s = RouteFinder.findRoute(getStops(start), getStops(end), x, context!!)
  86. if (s != route.text.toString()) {
  87. route.text = "${route.text}\n$s"
  88. break
  89. }
  90. }
  91. }*/
  92. override fun onBackPressed(): Boolean {
  93. return false
  94. }
  95. class StopsAutoCompleteEditText(private val inputView: StopAutoCompleteTextView, val context: Context) {
  96. private val PEOPLE = arrayOf("John Smith", "Kate Eckhart", "Emily Sun", "Frodo Baggins")
  97. private val stops = ArrayList<String>()
  98. init {
  99. val adapter = StopsAdapter(context,
  100. android.R.layout.simple_dropdown_item_1line, PEOPLE)
  101. inputView.setAdapter(adapter)
  102. inputView.setOnKeyPressListener(object : StopAutoCompleteTextView.OnBackspacePressedListener {
  103. override fun onBackspacePressed(s: Editable, start: Int, end: Int) {
  104. val tokens = s.getSpans(0, s.length, VerticalImageSpan::class.java)
  105. val result = ArrayList<StopsAutoCompleteEditText.VerticalImageSpan>()
  106. var length = 0
  107. tokens.forEach {
  108. val textLength = (it.drawable as ChipDrawable).text.length
  109. if (textLength + length != start)
  110. result.add(it)
  111. length += textLength
  112. }
  113. stops.clear()
  114. stops.addAll(result.map {
  115. (it.drawable as ChipDrawable).text.toString()
  116. })
  117. }
  118. })
  119. inputView.setOnItemClickListener { parent, _, position, _ ->
  120. val selected = parent.getItemAtPosition(position) as String
  121. stops.add(selected)
  122. addChipToGroup()
  123. inputView.setSelection(inputView.text.length)
  124. }
  125. }
  126. private fun addChipToGroup() {
  127. val ss = SpannableStringBuilder()
  128. for (stop in stops)
  129. ss.append(stop)
  130. var l = 0
  131. for (stop in stops) {
  132. val chip = ChipDrawable.createFromResource(context, R.xml.chip)
  133. chip.setText(stop)
  134. chip.setBounds(0, 0, chip.intrinsicWidth, chip.intrinsicHeight)
  135. val span = VerticalImageSpan(chip) // todo margins
  136. ss.setSpan(span, l, l + stop.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
  137. l += stop.length
  138. }
  139. inputView.text = ss
  140. }
  141. inner class StopsAdapter(context: Context, val layout: Int, items: Array<String>) : BaseAdapter(), Filterable {
  142. private val originalData = ArrayList<String>()
  143. private val filteredData = ArrayList<String>()
  144. private val inflater = LayoutInflater.from(context)
  145. init {
  146. filteredData.addAll(items)
  147. originalData.addAll(items)
  148. }
  149. override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
  150. val view: View = convertView ?: inflater.inflate(layout, parent, false)
  151. val text = view as TextView
  152. val item = getItem(position)
  153. text.text = item
  154. return view
  155. }
  156. override fun getItemId(position: Int): Long {
  157. return position.toLong()
  158. }
  159. override fun getCount(): Int {
  160. return filteredData.size
  161. }
  162. override fun getItem(position: Int): String {
  163. return filteredData[position]
  164. }
  165. override fun getFilter(): Filter {
  166. return object : Filter() {
  167. override fun performFiltering(constraint: CharSequence?): FilterResults {
  168. val filterString = constraint.toString().replace(stops.joinToString(""), "").toLowerCase()
  169. val filtered = originalData.filter {
  170. it.toLowerCase().contains(filterString)
  171. }
  172. return FilterResults().apply {
  173. values = filtered
  174. this.count = filtered.size
  175. }
  176. }
  177. override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
  178. filteredData.clear()
  179. @Suppress("UNCHECKED_CAST")
  180. filteredData.addAll(results?.values as ArrayList<String>)
  181. notifyDataSetChanged()
  182. }
  183. }
  184. }
  185. }
  186. inner class VerticalImageSpan(drawable: Drawable) : ImageSpan(drawable) {
  187. override fun getSize(paint: Paint, text: CharSequence, start: Int, end: Int,
  188. fontMetricsInt: Paint.FontMetricsInt?): Int {
  189. val drawable = drawable
  190. val rect = drawable.bounds
  191. if (fontMetricsInt != null) {
  192. val fmPaint = paint.fontMetricsInt
  193. val fontHeight = fmPaint.descent - fmPaint.ascent
  194. val drHeight = rect.bottom - rect.top
  195. val centerY = fmPaint.ascent + fontHeight / 2
  196. fontMetricsInt.ascent = centerY - drHeight / 2
  197. fontMetricsInt.top = fontMetricsInt.ascent
  198. fontMetricsInt.bottom = centerY + drHeight / 2
  199. fontMetricsInt.descent = fontMetricsInt.bottom
  200. }
  201. return rect.right
  202. }
  203. override fun draw(canvas: Canvas, text: CharSequence, start: Int, end: Int,
  204. x: Float, top: Int, y: Int, bottom: Int, paint: Paint) {
  205. val drawable = drawable
  206. canvas.save()
  207. val fmPaint = paint.fontMetricsInt
  208. val fontHeight = fmPaint.descent - fmPaint.ascent
  209. val centerY = y + fmPaint.descent - fontHeight / 2
  210. val transY = centerY - (drawable.bounds.bottom - drawable.bounds.top) / 2
  211. canvas.translate(x, transY.toFloat())
  212. drawable.draw(canvas)
  213. canvas.restore()
  214. }
  215. }
  216. }
  217. }