-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5553 from grzesiek2010/COLLECT-5486
Made form navigation language-direction aware
- Loading branch information
Showing
17 changed files
with
181 additions
and
215 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
collect_app/src/main/java/org/odk/collect/android/formentry/FormAnimation.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package org.odk.collect.android.formentry | ||
|
||
import android.content.Context | ||
import org.odk.collect.strings.localization.isLTR | ||
|
||
enum class FormAnimationType { | ||
LEFT, RIGHT, FADE | ||
} | ||
|
||
object FormAnimation { | ||
@JvmStatic | ||
fun getAnimationTypeBasedOnLanguageDirection(context: Context, formAnimationType: FormAnimationType): FormAnimationType { | ||
return if (context.isLTR()) { | ||
formAnimationType | ||
} else { | ||
when (formAnimationType) { | ||
FormAnimationType.LEFT -> FormAnimationType.RIGHT | ||
FormAnimationType.RIGHT -> FormAnimationType.LEFT | ||
else -> FormAnimationType.FADE | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
133 changes: 133 additions & 0 deletions
133
collect_app/src/main/java/org/odk/collect/android/formentry/SwipeHandler.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package org.odk.collect.android.formentry | ||
|
||
import android.content.Context | ||
import android.view.GestureDetector | ||
import android.view.MotionEvent | ||
import android.widget.FrameLayout | ||
import androidx.core.widget.NestedScrollView | ||
import org.odk.collect.android.utilities.FlingRegister | ||
import org.odk.collect.androidshared.utils.ScreenUtils | ||
import org.odk.collect.settings.keys.ProjectKeys | ||
import org.odk.collect.shared.settings.Settings | ||
import org.odk.collect.strings.localization.isLTR | ||
import kotlin.math.abs | ||
import kotlin.math.atan2 | ||
|
||
class SwipeHandler(context: Context, generalSettings: Settings) { | ||
val gestureDetector: GestureDetector | ||
private val onSwipe: OnSwipeListener | ||
private var view: View? = null | ||
private var allowSwiping = true | ||
private var beenSwiped = false | ||
private val generalSettings: Settings | ||
|
||
interface OnSwipeListener { | ||
fun onSwipeBackward() | ||
fun onSwipeForward() | ||
} | ||
|
||
init { | ||
gestureDetector = GestureDetector(context, GestureListener()) | ||
onSwipe = context as OnSwipeListener | ||
this.generalSettings = generalSettings | ||
} | ||
|
||
fun setView(view: View?) { | ||
this.view = view | ||
} | ||
|
||
fun setAllowSwiping(allowSwiping: Boolean) { | ||
this.allowSwiping = allowSwiping | ||
} | ||
|
||
fun setBeenSwiped(beenSwiped: Boolean) { | ||
this.beenSwiped = beenSwiped | ||
} | ||
|
||
fun beenSwiped() = beenSwiped | ||
|
||
inner class GestureListener : GestureDetector.OnGestureListener { | ||
override fun onDown(event: MotionEvent) = false | ||
override fun onSingleTapUp(e: MotionEvent) = false | ||
|
||
override fun onShowPress(e: MotionEvent) = Unit | ||
override fun onLongPress(e: MotionEvent) = Unit | ||
|
||
override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean { | ||
// The onFling() captures the 'up' event so our view thinks it gets long pressed. We don't want that, so cancel it. | ||
view?.cancelLongPress() | ||
return false | ||
} | ||
|
||
override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean { | ||
if (view == null) { | ||
return false | ||
} | ||
|
||
FlingRegister.flingDetected() | ||
|
||
if (generalSettings.getString(ProjectKeys.KEY_NAVIGATION)!!.contains(ProjectKeys.NAVIGATION_SWIPE) && allowSwiping) { | ||
// Looks for user swipes. If the user has swiped, move to the appropriate screen. | ||
|
||
// For all screens a swipe is left/right of at least .25" and up/down of less than .25" OR left/right of > .5" | ||
val xpixellimit = (ScreenUtils.xdpi(view!!.context) * .25).toInt() | ||
val ypixellimit = (ScreenUtils.ydpi(view!!.context) * .25).toInt() | ||
|
||
if (view != null && view!!.shouldSuppressFlingGesture()) { | ||
return false | ||
} | ||
|
||
if (beenSwiped) { | ||
return false | ||
} | ||
|
||
val diffX = abs(e1.x - e2.x) | ||
val diffY = abs(e1.y - e2.y) | ||
|
||
if (view != null && canScrollVertically() && getGestureAngle(diffX, diffY) > 30) { | ||
return false | ||
} | ||
|
||
if (diffX > xpixellimit && diffY < ypixellimit || diffX > xpixellimit * 2) { | ||
beenSwiped = true | ||
if (e1.x > e2.x) { | ||
if (view!!.context.isLTR()) { | ||
onSwipe.onSwipeForward() | ||
} else { | ||
onSwipe.onSwipeBackward() | ||
} | ||
} else { | ||
if (view!!.context.isLTR()) { | ||
onSwipe.onSwipeBackward() | ||
} else { | ||
onSwipe.onSwipeForward() | ||
} | ||
} | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
private fun getGestureAngle(diffX: Float, diffY: Float): Double { | ||
return Math.toDegrees(atan2(diffY.toDouble(), diffX.toDouble())) | ||
} | ||
|
||
private fun canScrollVertically(): Boolean { | ||
val scrollView = view!!.verticalScrollView | ||
|
||
return if (scrollView != null) { | ||
val screenHeight = scrollView.height | ||
val viewHeight = scrollView.getChildAt(0).height | ||
viewHeight > screenHeight | ||
} else { | ||
false | ||
} | ||
} | ||
} | ||
|
||
abstract class View(context: Context) : FrameLayout(context) { | ||
abstract fun shouldSuppressFlingGesture(): Boolean | ||
abstract val verticalScrollView: NestedScrollView? | ||
} | ||
} |
Oops, something went wrong.