Show and hide the keyboard when navigating to and from the EditFragment

This commit is contained in:
William Brawner 2019-08-04 18:47:23 -07:00 committed by William Brawner
parent 09809cada9
commit feae3be2ec
7 changed files with 93 additions and 40 deletions

View file

@ -29,7 +29,7 @@ android {
exclude 'META-INF/LICENSE' exclude 'META-INF/LICENSE'
exclude 'META-INF/DEPENDENCIES' exclude 'META-INF/DEPENDENCIES'
} }
compileSdkVersion 28 compileSdkVersion 29
buildToolsVersion '28.0.3' buildToolsVersion '28.0.3'
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
@ -38,7 +38,7 @@ android {
defaultConfig { defaultConfig {
applicationId "com.wbrawner.simplemarkdown" applicationId "com.wbrawner.simplemarkdown"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 28 targetSdkVersion 29
multiDexEnabled true multiDexEnabled true
versionCode 20 versionCode 20
versionName "0.7.0" versionName "0.7.0"
@ -64,7 +64,6 @@ android {
buildConfigField "boolean", "ENABLE_CUSTOM_CSS", "false" buildConfigField "boolean", "ENABLE_CUSTOM_CSS", "false"
} }
} }
flavorDimensions "platform"
dexOptions { dexOptions {
jumboMode true jumboMode true
} }
@ -83,11 +82,11 @@ dependencies {
androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', { androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', {
exclude group: 'com.android.support', module: 'support-annotations' exclude group: 'com.android.support', module: 'support-annotations'
}) })
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test:rules:1.1.1' androidTestImplementation 'androidx.test:rules:1.2.0'
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
implementation 'androidx.appcompat:appcompat:1.1.0-alpha05' implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.material:material:1.0.0' implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.legacy:legacy-support-v13:1.0.0' implementation 'androidx.legacy:legacy-support-v13:1.0.0'
@ -100,9 +99,9 @@ dependencies {
implementation 'com.jakewharton.rxbinding2:rxbinding-design:2.0.0' implementation 'com.jakewharton.rxbinding2:rxbinding-design:2.0.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation 'io.reactivex.rxjava2:rxjava:2.2.7' implementation 'io.reactivex.rxjava2:rxjava:2.2.7'
implementation 'com.google.firebase:firebase-core:16.0.9' implementation 'com.google.firebase:firebase-core:17.0.1'
implementation 'com.android.billingclient:billing:1.2' implementation 'com.android.billingclient:billing:1.2'
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.0' implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.multidex:multidex:2.0.1'
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"

View file

@ -0,0 +1,13 @@
package com.wbrawner.simplemarkdown.utility
import android.content.Context
import android.view.View
import android.view.inputmethod.InputMethodManager
fun View.showKeyboard() =
(context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager)
.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0)
fun View.hideKeyboard() =
(context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager)
.hideSoftInputFromWindow(windowToken, 0)

View file

@ -0,0 +1,6 @@
package com.wbrawner.simplemarkdown.view
interface ViewPagerPage {
fun onSelected()
fun onDeselected()
}

View file

@ -50,7 +50,9 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes
) )
} }
(application as MarkdownApplication).component.inject(this) (application as MarkdownApplication).component.inject(this)
pager.adapter = EditPagerAdapter(supportFragmentManager, this@MainActivity) val adapter = EditPagerAdapter(supportFragmentManager, this@MainActivity)
pager.adapter = adapter
pager.addOnPageChangeListener(adapter)
pager.pageMargin = 1 pager.pageMargin = 1
pager.setPageMarginDrawable(R.color.colorAccent) pager.setPageMarginDrawable(R.color.colorAccent)
tabLayout.setupWithViewPager(pager) tabLayout.setupWithViewPager(pager)

View file

@ -5,16 +5,21 @@ import android.content.res.Configuration
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter import androidx.fragment.app.FragmentPagerAdapter
import androidx.viewpager.widget.ViewPager
import com.wbrawner.simplemarkdown.R import com.wbrawner.simplemarkdown.R
import com.wbrawner.simplemarkdown.view.fragment.EditFragment import com.wbrawner.simplemarkdown.view.fragment.EditFragment
import com.wbrawner.simplemarkdown.view.fragment.PreviewFragment import com.wbrawner.simplemarkdown.view.fragment.PreviewFragment
class EditPagerAdapter(fm: FragmentManager, private val context: Context) : FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { class EditPagerAdapter(fm: FragmentManager, private val context: Context)
: FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT), ViewPager.OnPageChangeListener {
private val editFragment = EditFragment()
private val previewFragment = PreviewFragment()
override fun getItem(position: Int): Fragment { override fun getItem(position: Int): Fragment {
return when (position) { return when (position) {
FRAGMENT_EDIT -> EditFragment() FRAGMENT_EDIT -> editFragment
FRAGMENT_PREVIEW -> PreviewFragment() FRAGMENT_PREVIEW -> previewFragment
else -> throw IllegalStateException("Attempting to get fragment for invalid page number") else -> throw IllegalStateException("Attempting to get fragment for invalid page number")
} }
} }
@ -40,6 +45,23 @@ class EditPagerAdapter(fm: FragmentManager, private val context: Context) : Frag
} }
} }
override fun onPageScrollStateChanged(state: Int) {
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
}
override fun onPageSelected(position: Int) {
when (position) {
FRAGMENT_EDIT -> {
editFragment.onSelected()
}
FRAGMENT_PREVIEW -> {
editFragment.onDeselected()
}
}
}
companion object { companion object {
const val FRAGMENT_EDIT = 0 const val FRAGMENT_EDIT = 0
const val FRAGMENT_PREVIEW = 1 const val FRAGMENT_PREVIEW = 1

View file

@ -1,14 +1,12 @@
package com.wbrawner.simplemarkdown.view.fragment package com.wbrawner.simplemarkdown.view.fragment
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.EditText import android.widget.EditText
import android.widget.ScrollView import android.widget.ScrollView
import android.widget.Toast import android.widget.Toast
@ -19,20 +17,22 @@ import com.wbrawner.simplemarkdown.R
import com.wbrawner.simplemarkdown.presentation.MarkdownPresenter import com.wbrawner.simplemarkdown.presentation.MarkdownPresenter
import com.wbrawner.simplemarkdown.utility.MarkdownObserver import com.wbrawner.simplemarkdown.utility.MarkdownObserver
import com.wbrawner.simplemarkdown.utility.ReadabilityObserver import com.wbrawner.simplemarkdown.utility.ReadabilityObserver
import com.wbrawner.simplemarkdown.utility.hideKeyboard
import com.wbrawner.simplemarkdown.utility.showKeyboard
import com.wbrawner.simplemarkdown.view.MarkdownEditView import com.wbrawner.simplemarkdown.view.MarkdownEditView
import com.wbrawner.simplemarkdown.view.ViewPagerPage
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.abs
class EditFragment : Fragment(), MarkdownEditView { class EditFragment : Fragment(), MarkdownEditView, ViewPagerPage {
@Inject @Inject
lateinit var presenter: MarkdownPresenter lateinit var presenter: MarkdownPresenter
private var markdownEditor: EditText? = null private var markdownEditor: EditText? = null
private var markdownEditorScroller: ScrollView? = null private var markdownEditorScroller: ScrollView? = null
private var lastScrollEvent = -1
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? { savedInstanceState: Bundle?): View? {
@ -68,19 +68,26 @@ class EditFragment : Fragment(), MarkdownEditView {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
presenter.setEditView(this@EditFragment) presenter.setEditView(this@EditFragment)
markdownEditorScroller!!.setOnTouchListener { v, event -> var touchDown = 0L
// The focus should only be set if this was a click, and not a scroll var oldX = 0f
if (lastScrollEvent == MotionEvent.ACTION_DOWN && event.action == MotionEvent.ACTION_UP) { var oldY = 0f
if (activity == null) { markdownEditorScroller!!.setOnTouchListener { _, event ->
return@setOnTouchListener false // The ScrollView's onClickListener doesn't seem to be called, so I've had to
// implement a sort of custom click listener that checks that the tap was both quick
// and didn't drag.
when (event?.action) {
MotionEvent.ACTION_DOWN -> {
touchDown = System.currentTimeMillis()
oldX = event.rawX
oldY = event.rawY
}
MotionEvent.ACTION_UP -> {
if (System.currentTimeMillis() - touchDown < 150
&& abs(event.rawX - oldX) < 25
&& abs(event.rawY - oldY) < 25)
markdownEditor?.showKeyboard()
} }
val imm = activity
?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
?: return@setOnTouchListener false
imm.showSoftInput(markdownEditor, InputMethodManager.SHOW_IMPLICIT)
markdownEditor!!.requestFocus()
} }
lastScrollEvent = event.action
false false
} }
} }
@ -94,6 +101,15 @@ class EditFragment : Fragment(), MarkdownEditView {
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
presenter.setEditView(null) presenter.setEditView(null)
markdownEditor?.hideKeyboard()
}
override fun onSelected() {
markdownEditor?.showKeyboard()
}
override fun onDeselected() {
markdownEditor?.hideKeyboard()
} }
override fun getMarkdown(): String { override fun getMarkdown(): String {

View file

@ -29,18 +29,13 @@ class PreviewFragment : Fragment(), MarkdownPreviewView {
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? = inflater.inflate(R.layout.fragment_preview, container, false)
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(container!!.context)
// Inflate the layout for this fragment override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val view = inflater.inflate(R.layout.fragment_preview, container, false) sharedPreferences = PreferenceManager.getDefaultSharedPreferences(view.context)
markdownPreview = view.findViewById(R.id.markdown_view) markdownPreview = view.findViewById(R.id.markdown_view)
val activity = activity (activity?.application as? MarkdownApplication)?.component?.inject(this)
if (activity != null) { WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG)
(activity.application as MarkdownApplication).component.inject(this)
}
if (BuildConfig.DEBUG)
WebView.setWebContentsDebuggingEnabled(true)
return view
} }
override fun updatePreview(html: String) { override fun updatePreview(html: String) {