11package io .snabble .sdk .ui .checkout ;
22
3+ import android .annotation .SuppressLint ;
34import android .content .Context ;
5+ import android .graphics .Rect ;
46import android .os .Handler ;
57import android .os .Looper ;
68import androidx .annotation .NonNull ;
79import android .util .DisplayMetrics ;
10+ import android .view .MotionEvent ;
811import android .view .View ;
912import android .view .ViewGroup ;
1013import android .widget .Button ;
2932import io .snabble .sdk .ui .scanner .BarcodeView ;
3033import io .snabble .sdk .ui .telemetry .Telemetry ;
3134import io .snabble .sdk .ui .utils .OneShotClickListener ;
35+ import io .snabble .sdk .utils .Logger ;
3236
3337class CheckoutEncodedCodesView extends FrameLayout implements View .OnLayoutChangeListener {
3438 private FrameLayout scrollContainer ;
@@ -38,6 +42,9 @@ class CheckoutEncodedCodesView extends FrameLayout implements View.OnLayoutChang
3842 private CodeListView codeListView ;
3943 private int maxSizeMm ;
4044 private Button paidButton ;
45+ private boolean isTouchReleased ;
46+ private boolean isScrollingDown ;
47+ private boolean handleScrollIdleState ;
4148
4249 public CheckoutEncodedCodesView (Context context ) {
4350 super (context );
@@ -78,17 +85,7 @@ public void click() {
7885
7986 Telemetry .event (Telemetry .Event .CheckoutFinishByUser );
8087 } else {
81- final LinearLayoutManager linearLayoutManager = (LinearLayoutManager ) codeListView .getLayoutManager ();
82- RecyclerView .SmoothScroller smoothScroller = new LinearSmoothScroller (getContext ()) {
83- @ Override
84- protected int getVerticalSnapPreference () {
85- return SNAP_TO_START ;
86- }
87- };
88-
89- int scrollTo = getNextBarcodeIndex ();
90- smoothScroller .setTargetPosition (scrollTo );
91- linearLayoutManager .startSmoothScroll (smoothScroller );
88+ scrollTo (getNextBarcodeIndex ());
9289 }
9390 }
9491 });
@@ -109,23 +106,98 @@ protected int getVerticalSnapPreference() {
109106 }
110107
111108 public int getNextBarcodeIndex () {
112- final LinearLayoutManager linearLayoutManager = (LinearLayoutManager ) codeListView .getLayoutManager ();
113- if (linearLayoutManager != null ) {
114- return linearLayoutManager .findLastVisibleItemPosition ();
109+ final LinearLayoutManager llm = (LinearLayoutManager ) codeListView .getLayoutManager ();
110+ if (llm != null ) {
111+ return llm .findLastVisibleItemPosition ();
115112 }
116113
117114 return 0 ;
118115 }
119116
120117 public boolean isAtLastBarcode () {
121- final LinearLayoutManager linearLayoutManager = (LinearLayoutManager ) codeListView .getLayoutManager ();
122- if (linearLayoutManager != null ) {
123- return linearLayoutManager .findLastCompletelyVisibleItemPosition () == linearLayoutManager .getItemCount () - 1 ;
118+ final LinearLayoutManager llm = (LinearLayoutManager ) codeListView .getLayoutManager ();
119+ if (llm != null ) {
120+ return llm .findLastCompletelyVisibleItemPosition () == llm .getItemCount () - 1 ;
124121 }
125122
126123 return true ;
127124 }
128125
126+ private void scrollTo (int position ) {
127+ final LinearLayoutManager linearLayoutManager = (LinearLayoutManager ) codeListView .getLayoutManager ();
128+ RecyclerView .SmoothScroller smoothScroller = new LinearSmoothScroller (getContext ()) {
129+ @ Override
130+ protected int getVerticalSnapPreference () {
131+ return SNAP_TO_START ;
132+ }
133+ };
134+
135+ smoothScroller .setTargetPosition (position );
136+ linearLayoutManager .startSmoothScroll (smoothScroller );
137+ }
138+
139+ private void handleTouchUp () {
140+ isTouchReleased = true ;
141+
142+ if (handleScrollIdleState ) {
143+ handleScrollIdleState = false ;
144+ handleScrollIdleState ();
145+ }
146+ }
147+
148+ private void handleScroll (int dy ) {
149+ isScrollingDown = dy > 0 ;
150+
151+ CodeListViewAdapter adapter = ((CodeListViewAdapter )codeListView .getAdapter ());
152+
153+ if (isAtLastBarcode ()) {
154+ paidButton .setText (R .string .Snabble_QRCode_didPay );
155+ } else {
156+ paidButton .setText (getResources ().getString (R .string .Snabble_QRCode_nextCode ,
157+ getNextBarcodeIndex () + 1 , adapter .getItemCount ()));
158+ }
159+ }
160+
161+ private void handleScrollStateChanged (int newState ) {
162+ if (newState == RecyclerView .SCROLL_STATE_SETTLING && isTouchReleased ) {
163+ isTouchReleased = false ;
164+
165+ final LinearLayoutManager llm = (LinearLayoutManager ) codeListView .getLayoutManager ();
166+ if (llm != null ) {
167+ int currentPosition = llm .findFirstVisibleItemPosition ();
168+
169+ if (isScrollingDown ) {
170+ scrollTo (currentPosition + 1 );
171+ } else {
172+ scrollTo (currentPosition );
173+ }
174+ }
175+ } else if (newState == RecyclerView .SCROLL_STATE_IDLE ) {
176+ if (isTouchReleased ) {
177+ handleScrollIdleState ();
178+ isTouchReleased = false ;
179+ } else {
180+ handleScrollIdleState = true ;
181+ }
182+ }
183+ }
184+
185+ private void handleScrollIdleState () {
186+ final LinearLayoutManager llm = (LinearLayoutManager ) codeListView .getLayoutManager ();
187+ if (llm != null ) {
188+ int currentPosition = llm .findFirstVisibleItemPosition ();
189+ View view = llm .findViewByPosition (currentPosition );
190+
191+ Rect r = new Rect ();
192+ view .getGlobalVisibleRect (r );
193+ if (r .height () < view .getHeight () / 2 ) {
194+ scrollTo (currentPosition + 1 );
195+ } else {
196+ scrollTo (currentPosition );
197+ }
198+ }
199+ }
200+
129201 @ Override
130202 protected void onAttachedToWindow () {
131203 super .onAttachedToWindow ();
@@ -148,6 +220,7 @@ public void onLayoutChange(View v, int left, int top, int right, int bottom,
148220 // this avoids a bug in <= API 16 where added views while layouting were discarded
149221 Handler handler = new Handler (Looper .getMainLooper ());
150222 handler .post (new Runnable () {
223+ @ SuppressLint ("ClickableViewAccessibility" )
151224 @ Override
152225 public void run () {
153226 DisplayMetrics dm = getResources ().getDisplayMetrics ();
@@ -160,18 +233,27 @@ public void run() {
160233 scrollContainer .removeAllViews ();
161234 codeListView = new CodeListView (getContext ());
162235 scrollContainer .addView (codeListView , lp );
236+
237+ codeListView .setOnTouchListener (new OnTouchListener () {
238+ @ Override
239+ public boolean onTouch (View v , MotionEvent event ) {
240+ if (event .getAction () == MotionEvent .ACTION_UP ) {
241+ handleTouchUp ();
242+ }
243+
244+ return false ;
245+ }
246+ });
247+
163248 codeListView .addOnScrollListener (new RecyclerView .OnScrollListener () {
249+ @ Override
250+ public void onScrollStateChanged (@ NonNull RecyclerView recyclerView , int newState ) {
251+ handleScrollStateChanged (newState );
252+ }
253+
164254 @ Override
165255 public void onScrolled (@ NonNull RecyclerView recyclerView , int dx , int dy ) {
166- super .onScrolled (recyclerView , dx , dy );
167-
168- CodeListViewAdapter adapter = ((CodeListViewAdapter )codeListView .getAdapter ());
169- if (isAtLastBarcode ()) {
170- paidButton .setText (R .string .Snabble_QRCode_didPay );
171- } else {
172- paidButton .setText (getResources ().getString (R .string .Snabble_QRCode_nextCode ,
173- getNextBarcodeIndex () + 1 , adapter .getItemCount ()));
174- }
256+ handleScroll (dy );
175257 }
176258 });
177259
0 commit comments