55import android .os .Looper ;
66import androidx .annotation .NonNull ;
77import android .util .DisplayMetrics ;
8- import android .view .Gravity ;
98import android .view .View ;
109import android .view .ViewGroup ;
1110import android .widget .Button ;
1211import android .widget .FrameLayout ;
12+ import android .widget .LinearLayout ;
1313import android .widget .TextView ;
1414
1515import java .util .ArrayList ;
1616
1717import androidx .recyclerview .widget .LinearLayoutManager ;
18+ import androidx .recyclerview .widget .LinearSmoothScroller ;
1819import androidx .recyclerview .widget .RecyclerView ;
1920import io .snabble .sdk .Checkout ;
2021import io .snabble .sdk .Project ;
2324import io .snabble .sdk .encodedcodes .EncodedCodesOptions ;
2425import io .snabble .sdk .ui .R ;
2526import io .snabble .sdk .ui .SnabbleUI ;
26- import io .snabble .sdk .ui .SnabbleUICallback ;
2727import io .snabble .sdk .BarcodeFormat ;
28+ import io .snabble .sdk .ui .SnabbleUICallback ;
2829import io .snabble .sdk .ui .scanner .BarcodeView ;
2930import io .snabble .sdk .ui .telemetry .Telemetry ;
3031import io .snabble .sdk .ui .utils .OneShotClickListener ;
3132
3233class CheckoutEncodedCodesView extends FrameLayout implements View .OnLayoutChangeListener {
3334 private FrameLayout scrollContainer ;
34- private TextView explanationText ;
3535 private TextView explanationText2 ;
3636 private Project project ;
3737 private EncodedCodesGenerator encodedCodesGenerator ;
38+ private CodeListView codeListView ;
3839 private int maxSizeMm ;
40+ private Button paidButton ;
3941
4042 public CheckoutEncodedCodesView (Context context ) {
4143 super (context );
@@ -56,38 +58,38 @@ private void inflateView(EncodedCodesOptions options) {
5658
5759 scrollContainer = findViewById (R .id .scroll_container );
5860
59- explanationText = findViewById (R .id .explanation1 );
6061 explanationText2 = findViewById (R .id .explanation2 );
6162
6263 maxSizeMm = options .maxSizeMm ;
6364 encodedCodesGenerator = new EncodedCodesGenerator (options );
6465
65- final Button paidButton = findViewById (R .id .paid );
66-
67- paidButton .setVisibility (View .INVISIBLE );
68- paidButton .setAlpha (0 );
69- Handler handler = new Handler (Looper .getMainLooper ());
70- handler .postDelayed (new Runnable () {
71- @ Override
72- public void run () {
73- paidButton .setVisibility (View .VISIBLE );
74- paidButton .animate ().setDuration (150 ).alpha (1 ).start ();
75- paidButton .setEnabled (true );
76- }
77- }, 5000 );
78-
66+ paidButton = findViewById (R .id .paid );
7967 paidButton .setOnClickListener (new OneShotClickListener () {
8068 @ Override
8169 public void click () {
82- Project project = SnabbleUI .getProject ();
83- project .getCheckout ().approveOfflineMethod ();
70+ if (isAtLastBarcode ()) {
71+ Project project = SnabbleUI .getProject ();
72+ project .getCheckout ().approveOfflineMethod ();
8473
85- SnabbleUICallback uiCallback = SnabbleUI .getUiCallback ();
86- if (uiCallback != null ) {
87- uiCallback .goBack ();
88- }
74+ SnabbleUICallback uiCallback = SnabbleUI .getUiCallback ();
75+ if (uiCallback != null ) {
76+ uiCallback .goBack ();
77+ }
8978
90- Telemetry .event (Telemetry .Event .CheckoutFinishByUser );
79+ Telemetry .event (Telemetry .Event .CheckoutFinishByUser );
80+ } 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 );
92+ }
9193 }
9294 });
9395
@@ -106,20 +108,22 @@ public void click() {
106108 }
107109 }
108110
109- private void updateExplanationText (int codeCount ) {
110- int resId ;
111- if (codeCount > 1 ) {
112- resId = R .string .Snabble_QRCode_showTheseCodes ;
113- } else {
114- resId = R .string .Snabble_QRCode_showThisCode ;
111+ public int getNextBarcodeIndex () {
112+ final LinearLayoutManager linearLayoutManager = (LinearLayoutManager ) codeListView .getLayoutManager ();
113+ if (linearLayoutManager != null ) {
114+ return linearLayoutManager .findLastVisibleItemPosition ();
115115 }
116116
117- if (SnabbleUI .getActionBar () != null ) {
118- explanationText .setVisibility (View .GONE );
119- SnabbleUI .getActionBar ().setTitle (resId );
120- } else {
121- explanationText .setText (resId );
117+ return 0 ;
118+ }
119+
120+ public boolean isAtLastBarcode () {
121+ final LinearLayoutManager linearLayoutManager = (LinearLayoutManager ) codeListView .getLayoutManager ();
122+ if (linearLayoutManager != null ) {
123+ return linearLayoutManager .findLastCompletelyVisibleItemPosition () == linearLayoutManager .getItemCount () - 1 ;
122124 }
125+
126+ return true ;
123127 }
124128
125129 @ Override
@@ -146,19 +150,37 @@ public void onLayoutChange(View v, int left, int top, int right, int bottom,
146150 handler .post (new Runnable () {
147151 @ Override
148152 public void run () {
153+ DisplayMetrics dm = getResources ().getDisplayMetrics ();
154+
149155 if (scrollContainer .getWidth () > 0 && scrollContainer .getHeight () > 0 ) {
150156 FrameLayout .LayoutParams lp = new FrameLayout .LayoutParams (
151157 ViewGroup .LayoutParams .MATCH_PARENT ,
152- ViewGroup .LayoutParams .WRAP_CONTENT );
153- lp . gravity = Gravity . CENTER ;
158+ ViewGroup .LayoutParams .MATCH_PARENT );
159+
154160 scrollContainer .removeAllViews ();
155- scrollContainer .addView (new CodeListView (getContext ()), lp );
161+ codeListView = new CodeListView (getContext ());
162+ scrollContainer .addView (codeListView , lp );
163+ codeListView .addOnScrollListener (new RecyclerView .OnScrollListener () {
164+ @ Override
165+ 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+ }
175+ }
176+ });
177+
178+ codeListView .setPadding (0 , (int ) (12 * dm .density ), 0 , 0 );
179+ codeListView .setOverScrollMode (View .OVER_SCROLL_NEVER );
156180 }
157181
158- DisplayMetrics dm = getResources ().getDisplayMetrics ();
159182 int dpHeight = Math .round (scrollContainer .getHeight () / dm .density );
160183 if (dpHeight < 220 ) {
161- explanationText .setVisibility (View .GONE );
162184 explanationText2 .setVisibility (View .GONE );
163185 }
164186 }
@@ -176,12 +198,18 @@ public CodeListView(@NonNull Context context) {
176198 }
177199
178200 private class ViewHolder extends RecyclerView .ViewHolder {
201+ BarcodeView barcodeView ;
202+ TextView title ;
203+
179204 ViewHolder (@ NonNull View itemView ) {
180205 super (itemView );
206+
207+ barcodeView = itemView .findViewById (R .id .barcode );
208+ title = itemView .findViewById (R .id .title );
181209 }
182210 }
183211
184- private class CodeListViewAdapter extends RecyclerView .Adapter {
212+ private class CodeListViewAdapter extends RecyclerView .Adapter < ViewHolder > {
185213 private ArrayList <String > codes ;
186214
187215 CodeListViewAdapter () {
@@ -193,41 +221,61 @@ private class CodeListViewAdapter extends RecyclerView.Adapter {
193221
194222 encodedCodesGenerator .add (project .getShoppingCart ());
195223 codes = encodedCodesGenerator .generate ();
196- updateExplanationText (codes .size ());
197224 }
198225
199226 @ NonNull
200227 @ Override
201- public RecyclerView . ViewHolder onCreateViewHolder (@ NonNull ViewGroup parent , int viewType ) {
202- return new ViewHolder (new BarcodeView (getContext ()));
228+ public ViewHolder onCreateViewHolder (@ NonNull ViewGroup parent , int viewType ) {
229+ return new ViewHolder (View . inflate (getContext (), R . layout . snabble_item_encodedcodes , null ));
203230 }
204231
205232 @ Override
206- public void onBindViewHolder (@ NonNull RecyclerView .ViewHolder holder , int position ) {
207- BarcodeView barcodeView = (BarcodeView )holder .itemView ;
233+ public void onBindViewHolder (@ NonNull ViewHolder holder , int position ) {
234+ boolean smallScreen = explanationText2 .getVisibility () == View .GONE ;
235+ DisplayMetrics dm = getResources ().getDisplayMetrics ();
236+
237+ holder .itemView .setLayoutParams (new LinearLayout .LayoutParams (
238+ ViewGroup .LayoutParams .MATCH_PARENT ,
239+ ViewGroup .LayoutParams .WRAP_CONTENT ));
240+
241+ if (position == 0 ) {
242+ if (codes .size () > 1 ) {
243+ holder .title .setText (getResources ().getString (R .string .Snabble_QRCode_showTheseCodes , getItemCount ()));
244+ } else {
245+ holder .title .setText (R .string .Snabble_QRCode_showThisCode );
246+ }
247+ } else {
248+ if (explanationText2 .getVisibility () == View .GONE ) {
249+ holder .title .setVisibility (View .GONE );
250+ } else {
251+ holder .title .setVisibility (View .VISIBLE );
252+ holder .title .setText (getResources ().getString (R .string .Snabble_QRCode_entry_title , (position + 1 )));
253+ }
254+ }
208255
209- int h = scrollContainer .getHeight ();
210- int barcodeHeight = codes .size () == 1 ? h : h - h / 5 ;
256+ int offsetH = holder .title .getVisibility () != View .GONE ? (int ) (48 * dm .density ) : 0 ;
257+ int h = scrollContainer .getHeight () - offsetH ;
258+ int barcodeHeight = codes .size () == 1 ? h : h - (smallScreen ? 0 : h / 4 );
211259
212260 if (maxSizeMm > 0 ) {
213- DisplayMetrics dm = getResources ().getDisplayMetrics ();
214261 float pixelsPerMmX = dm .xdpi / 25.4f ;
215262 int size = (int ) (pixelsPerMmX * maxSizeMm );
216263 size = Math .min (barcodeHeight , size );
217264
218- barcodeView .setLayoutParams (new RecyclerView .LayoutParams (ViewGroup .LayoutParams .MATCH_PARENT , size ));
265+ holder . barcodeView .setLayoutParams (new LinearLayout .LayoutParams (ViewGroup .LayoutParams .MATCH_PARENT , size ));
219266 } else {
220- barcodeView .setLayoutParams (new RecyclerView .LayoutParams (
267+ holder . barcodeView .setLayoutParams (new LinearLayout .LayoutParams (
221268 ViewGroup .LayoutParams .MATCH_PARENT ,
222269 barcodeHeight ));
223270 }
224271
225- barcodeView . setFormat ( BarcodeFormat . QR_CODE );
226-
227- int padding = Math . round ( 12.0f * getResources (). getDisplayMetrics (). density );
228- barcodeView . setPadding ( padding , padding , padding , padding );
272+ if (! smallScreen ) {
273+ int padding = Math . round ( 12.0f * getResources (). getDisplayMetrics (). density );
274+ holder . barcodeView . setPadding ( padding , padding , padding , padding );
275+ }
229276
230- barcodeView .setText (codes .get (position ));
277+ holder .barcodeView .setFormat (BarcodeFormat .QR_CODE );
278+ holder .barcodeView .setText (codes .get (position ));
231279 }
232280
233281 @ Override
0 commit comments