-
Notifications
You must be signed in to change notification settings - Fork 21
/
SalesListFragment.java
773 lines (689 loc) · 34.9 KB
/
SalesListFragment.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
/*
* Copyright 2018 Kaushik N. Sanji
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http:https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.kaushiknsanji.storeapp.ui.inventory;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.constraint.Group;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.content.res.AppCompatResources;
import android.support.v7.recyclerview.extensions.ListAdapter;
import android.support.v7.util.DiffUtil;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.kaushiknsanji.storeapp.R;
import com.example.kaushiknsanji.storeapp.data.local.models.SalesLite;
import com.example.kaushiknsanji.storeapp.ui.common.ListItemSpacingDecoration;
import com.example.kaushiknsanji.storeapp.ui.inventory.config.SalesConfigActivity;
import com.example.kaushiknsanji.storeapp.utils.ColorUtility;
import com.example.kaushiknsanji.storeapp.utils.SnackbarUtility;
import com.example.kaushiknsanji.storeapp.utils.TextAppearanceUtility;
import com.example.kaushiknsanji.storeapp.workers.ImageDownloaderFragment;
import java.util.ArrayList;
import java.util.Currency;
import java.util.Locale;
/**
* {@link com.example.kaushiknsanji.storeapp.ui.MainActivity}'s ViewPager Fragment that inflates
* the layout 'R.layout.layout_main_content_page' to display the list of Products with their Sales information configured
* in the database. This implements the {@link SalesListContract.View}
* on the lines of Model-View-Presenter architecture.
*
* @author Kaushik N Sanji
*/
public class SalesListFragment extends Fragment
implements SalesListContract.View, SwipeRefreshLayout.OnRefreshListener {
//Constant used for logs
private static final String LOG_TAG = SalesListFragment.class.getSimpleName();
//The Presenter interface for this View
private SalesListContract.Presenter mPresenter;
//References to the Views shown in this Fragment
private SwipeRefreshLayout mSwipeRefreshLayout;
private RecyclerView mRecyclerViewContentList;
private Group mGroupEmptyList;
//Adapter of the RecyclerView
private SalesListAdapter mAdapter;
/**
* Mandatory Empty Constructor of {@link SalesListFragment}.
* This is required by the {@link android.support.v4.app.FragmentManager} to instantiate
* the fragment (e.g. upon screen orientation changes).
*/
public SalesListFragment() {
}
/**
* Static Factory constructor that creates an instance of {@link SalesListFragment}
*
* @return Instance of {@link SalesListFragment}
*/
public static SalesListFragment newInstance() {
return new SalesListFragment();
}
/**
* Called to have the fragment instantiate its user interface view.
* This is optional, and non-graphical fragments can return null (which
* is the default implementation). This will be called between
* {@link #onCreate(Bundle)} and {@link #onActivityCreated(Bundle)}.
* <p>
* <p>If you return a View from here, you will later be called in
* {@link #onDestroyView} when the view is being released.
*
* @param inflater The LayoutInflater object that can be used to inflate
* any views in the fragment,
* @param container If non-null, this is the parent view that the fragment's
* UI should be attached to. The fragment should not add the view itself,
* but this can be used to generate the LayoutParams of the view.
* @param savedInstanceState If non-null, this fragment is being re-constructed
* from a previous saved state as given here.
* @return Returns the View for the fragment's UI ('R.layout.layout_main_content_page')
*/
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//Inflating the layout 'R.layout.layout_main_content_page'
//Passing false as we are attaching the layout ourselves
View rootView = inflater.inflate(R.layout.layout_main_content_page, container, false);
//Finding the Views
mSwipeRefreshLayout = rootView.findViewById(R.id.swipe_refresh_content_page);
mRecyclerViewContentList = rootView.findViewById(R.id.recyclerview_content_page);
TextView textViewEmptyList = rootView.findViewById(R.id.text_content_page_empty_list);
ImageView imageViewStepNumber = rootView.findViewById(R.id.image_content_page_step_number);
mGroupEmptyList = rootView.findViewById(R.id.group_content_page_empty);
//Initialize the ImageView with the proper step number drawable
imageViewStepNumber.setImageDrawable(AppCompatResources.getDrawable(requireContext(), R.drawable.ic_main_sales_page_number));
//Initialize the Empty TextView with Text
textViewEmptyList.setText(getString(R.string.sales_list_empty_text));
//Initialize SwipeRefreshLayout
setupSwipeRefresh();
//Initialize RecyclerView
setupRecyclerView();
//Returning the prepared layout
return rootView;
}
/**
* Method that initializes the SwipeRefreshLayout 'R.id.swipe_refresh_content_page'
* and its listener
*/
private void setupSwipeRefresh() {
//Registering the refresh listener which triggers a new load on swipe to refresh
mSwipeRefreshLayout.setOnRefreshListener(this);
//Configuring the Colors for Swipe Refresh Progress Indicator
mSwipeRefreshLayout.setColorSchemeColors(ColorUtility.obtainColorsFromTypedArray(requireContext(), R.array.swipe_refresh_colors, R.color.colorPrimary));
}
/**
* Method that initializes a RecyclerView with its Adapter for loading and displaying the list of Products to Sell.
*/
private void setupRecyclerView() {
//Creating a Vertical Linear Layout Manager with the default layout order
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(requireContext(),
LinearLayoutManager.VERTICAL, false) {
/**
* Called when items have been added to the adapter. The LayoutManager may choose to
* requestLayout if the inserted items would require refreshing the currently visible set
* of child views. (e.g. currently empty space would be filled by appended items, etc.)
*
* @param recyclerView The {@link RecyclerView} this LayoutManager is bound to.
* @param positionStart The Start position from where the Items were added to the {@link RecyclerView}
* @param itemCount Number of Items added
*/
@Override
public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) {
if (getChildCount() > 0 && itemCount == 1) {
//When there are some items visible and number of items added is 1
//Getting the last item position in the RecyclerView
int positionLast = getItemCount() - 1;
if (positionLast > positionStart) {
//When the last item position is more than the start position
for (int index = positionStart; index <= positionLast; index++) {
//Remove all the views from RecyclerView Cache till the last item position
//so that the RecyclerView grows in size properly to accommodate the items
//with proper item decoration height
removeView(findViewByPosition(index));
}
//Auto Scroll to the item position in the end
recyclerView.smoothScrollToPosition(positionStart);
}
}
}
};
//Setting the Layout Manager to use
mRecyclerViewContentList.setLayoutManager(linearLayoutManager);
//Initializing the Adapter for the RecyclerView
mAdapter = new SalesListAdapter(requireContext(), new UserActionsListener());
//Setting the Adapter on the RecyclerView
mRecyclerViewContentList.setAdapter(mAdapter);
//Retrieving the Item spacing to use
int itemSpacing = getResources().getDimensionPixelSize(R.dimen.sales_list_items_spacing);
//Setting Item offsets using Item Decoration
mRecyclerViewContentList.addItemDecoration(new ListItemSpacingDecoration(
itemSpacing, itemSpacing
));
}
/**
* Called when the fragment is visible to the user and actively running.
* This is generally
* tied to {@link Activity#onResume() Activity.onResume} of the containing
* Activity's lifecycle.
*/
@Override
public void onResume() {
super.onResume();
//Start loading the Products with Sales data
mPresenter.start();
}
/**
* Called when the fragment is no longer in use. This is called
* after {@link #onStop()} and before {@link #onDetach()}.
*/
@Override
public void onDestroy() {
super.onDestroy();
//Dispatching the event to the Presenter to invalidate any critical resources
mPresenter.releaseResources();
}
/**
* Method that returns the registered Presenter for this View.
*
* @return The registered Presenter for this View. Can be {@code null}
*/
@Nullable
@Override
public SalesListContract.Presenter getPresenter() {
return mPresenter;
}
/**
* Method that registers the Presenter {@code presenter} with the View implementing {@link com.example.kaushiknsanji.storeapp.ui.BaseView}
*
* @param presenter Presenter instance implementing the {@link com.example.kaushiknsanji.storeapp.ui.BasePresenter}
*/
@Override
public void setPresenter(SalesListContract.Presenter presenter) {
mPresenter = presenter;
}
/**
* Called when a swipe gesture triggers a refresh.
*/
@Override
public void onRefresh() {
//Forcefully start a new load
mPresenter.triggerProductSalesLoad(true);
}
/**
* Receive the result from a previous call to
* {@link #startActivityForResult(Intent, int)}. This follows the
* related Activity API as described there in
* {@link android.support.v4.app.FragmentActivity#onActivityResult(int, int, Intent)}.
*
* @param requestCode The integer request code originally supplied to
* startActivityForResult(), allowing you to identify who this
* result came from.
* @param resultCode The integer result code returned by the child activity
* through its setResult().
* @param data An Intent, which can return result data to the caller
* (various data can be attached to Intent "extras").
*/
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
//Delegating to the Presenter to handle
mPresenter.onActivityResult(requestCode, resultCode, data);
}
/**
* Method that displays the Progress indicator
*/
@Override
public void showProgressIndicator() {
//Enabling the Swipe to Refresh if disabled prior to showing the Progress indicator
if (!mSwipeRefreshLayout.isEnabled()) {
mSwipeRefreshLayout.setEnabled(true);
}
//Displaying the Progress Indicator only when not already shown
if (!mSwipeRefreshLayout.isRefreshing()) {
mSwipeRefreshLayout.setRefreshing(true);
}
}
/**
* Method that hides the Progress indicator
*/
@Override
public void hideProgressIndicator() {
//Hiding the Progress indicator
mSwipeRefreshLayout.setRefreshing(false);
}
/**
* Method invoked when an error is encountered during Sales information
* retrieval or delete process.
*
* @param messageId String Resource of the error Message to be displayed
* @param args Variable number of arguments to replace the format specifiers
*/
@Override
public void showError(@StringRes int messageId, @Nullable Object... args) {
if (getView() != null) {
//When we have the root view
//Evaluating the message to be shown
String messageToBeShown;
if (args != null && args.length > 0) {
//For the String Resource with args
messageToBeShown = getString(messageId, args);
} else {
//For the String Resource without args
messageToBeShown = getString(messageId);
}
if (!TextUtils.isEmpty(messageToBeShown)) {
//Displaying the Snackbar message of indefinite time length
//when we have the error message to be shown
new SnackbarUtility(Snackbar.make(getView(), messageToBeShown, Snackbar.LENGTH_INDEFINITE))
.revealCompleteMessage() //Removes the limit on max lines
.setDismissAction(R.string.snackbar_action_ok) //For the Dismiss "OK" action
.showSnack();
}
}
}
/**
* Method invoked when the Sales List is empty. This should show a TextView with a
* Text that suggests Users to first configure Products and its Suppliers into the database.
*/
@Override
public void showEmptyView() {
//Hiding the RecyclerView
mRecyclerViewContentList.setVisibility(View.INVISIBLE);
//Displaying the Empty List TextView and Step Number Drawable
mGroupEmptyList.setVisibility(View.VISIBLE);
//Disabling the Swipe to Refresh
mSwipeRefreshLayout.setEnabled(false);
}
/**
* Method invoked when we have the Sales List. This should show the Sales List and
* hide the Empty List TextView and Step Number Drawable.
*/
@Override
public void hideEmptyView() {
//Displaying the RecyclerView
mRecyclerViewContentList.setVisibility(View.VISIBLE);
//Hiding the Empty List TextView and Step Number Drawable
mGroupEmptyList.setVisibility(View.GONE);
}
/**
* Method that updates the RecyclerView's Adapter with new {@code salesList} data.
*
* @param salesList List of Products with Sales data defined by {@link SalesLite},
* loaded from the database.
*/
@Override
public void loadSalesList(ArrayList<SalesLite> salesList) {
//Submitting the new updated list to the Adapter
mAdapter.submitList(salesList);
}
/**
* Method that displays a message on Success of Deleting an Existing Product.
*
* @param productSku String containing the SKU of the Product that was deleted successfully.
*/
@Override
public void showDeleteSuccess(String productSku) {
if (getView() != null) {
Snackbar.make(getView(), getString(R.string.product_list_item_delete_success, productSku), Snackbar.LENGTH_LONG).show();
}
}
/**
* Method that displays a message on Success of Selling a quantity of the Product
* from the Top Supplier.
*
* @param productSku The Product SKU of the Product sold.
* @param supplierCode The Supplier Code of the Top Supplier for the Product sold.
*/
@Override
public void showSellQuantitySuccess(String productSku, String supplierCode) {
if (getView() != null) {
Snackbar.make(getView(), getString(R.string.sales_list_item_sell_success, productSku, supplierCode), Snackbar.LENGTH_LONG).show();
}
}
/**
* Method that displays a message on Success of updating the Inventory of the Product.
*
* @param productSku String containing the SKU of the Product that was updated
* with Inventory successfully.
*/
@Override
public void showUpdateInventorySuccess(String productSku) {
if (getView() != null) {
Snackbar.make(getView(), getString(R.string.sales_list_item_update_inventory_success, productSku), Snackbar.LENGTH_LONG).show();
}
}
/**
* Method invoked when the user clicks on the Item View itself. This should launch the
* {@link SalesConfigActivity}
* for editing the Sales data of the Product.
*
* @param productId The Primary Key of the Product to be edited.
* @param activityOptionsCompat Instance of {@link ActivityOptionsCompat} that has the
* details for Shared Element Transition
*/
@Override
public void launchEditProductSales(int productId, ActivityOptionsCompat activityOptionsCompat) {
//Creating the Intent to launch SalesConfigActivity
Intent salesConfigIntent = new Intent(requireContext(), SalesConfigActivity.class);
//Passing in the Product ID of the Product to be edited
salesConfigIntent.putExtra(SalesConfigActivity.EXTRA_PRODUCT_ID, productId);
//Starting the Activity with Result
startActivityForResult(salesConfigIntent, SalesConfigActivity.REQUEST_EDIT_SALES, activityOptionsCompat.toBundle());
}
/**
* {@link ListAdapter} class for RecyclerView to load the list of Products for Selling.
*/
private static class SalesListAdapter extends ListAdapter<SalesLite, SalesListAdapter.ViewHolder> {
/**
* {@link DiffUtil.ItemCallback} for calculating the difference between two {@link SalesLite} objects.
*/
private static DiffUtil.ItemCallback<SalesLite> DIFF_SALES
= new DiffUtil.ItemCallback<SalesLite>() {
/**
* Called to check whether two objects represent the same item.
* <p>
* For example, if your items have unique ids, this method should check their id equality.
*
* @param oldItem The item in the old list.
* @param newItem The item in the new list.
* @return True if the two items represent the same object or false if they are different.
*
* @see DiffUtil.Callback#areItemsTheSame(int, int)
*/
@Override
public boolean areItemsTheSame(SalesLite oldItem, SalesLite newItem) {
//Returning the comparison of Item Id and Supplier Id
return oldItem.getProductId() == newItem.getProductId()
&& oldItem.getSupplierId() == newItem.getSupplierId();
}
/**
* Called to check whether two items have the same data.
* <p>
* This information is used to detect if the contents of an item have changed.
* <p>
* This method to check equality instead of {@link Object#equals(Object)} so that you can
* change its behavior depending on your UI.
* <p>
* For example, if you are using DiffUtil with a
* {@link android.support.v7.widget.RecyclerView.Adapter RecyclerView.Adapter}, you should
* return whether the items' visual representations are the same.
* <p>
* This method is called only if {@link #areItemsTheSame(SalesLite, SalesLite)} returns {@code true} for
* these items.
*
* @param oldItem The item in the old list.
* @param newItem The item in the new list.
* @return True if the contents of the items are the same or false if they are different.
*
* @see DiffUtil.Callback#areContentsTheSame(int, int)
*/
@Override
public boolean areContentsTheSame(SalesLite oldItem, SalesLite newItem) {
//Returning the comparison of entire SalesLite
return oldItem.equals(newItem);
}
};
//Stores the Typeface used for Product SKU text
private Typeface mProductSkuTypeface;
//Listener for User Actions on Product List items
private SalesListUserActionsListener mActionsListener;
/**
* Constructor of {@link SalesListAdapter}
*
* @param context Context used for retrieving a Font
* @param userActionsListener Instance of {@link SalesListUserActionsListener}
* to receive event callbacks for User Actions on Item Views
*/
SalesListAdapter(Context context, SalesListUserActionsListener userActionsListener) {
super(DIFF_SALES);
//Registering the User Actions Listener
mActionsListener = userActionsListener;
//Reading the Typeface for Product SKU
mProductSkuTypeface = ResourcesCompat.getFont(context, R.font.libre_barcode_128_text_regular);
}
/**
* Called when RecyclerView needs a new {@link ViewHolder} of the given type to represent
* an item.
*
* @param parent The ViewGroup into which the new View will be added after it is bound to
* an adapter position.
* @param viewType The view type of the new View.
* @return A new ViewHolder that holds a View of the given view type.
*/
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//Inflating the item layout 'R.layout.item_sales_list'
//Passing False since we are attaching the layout ourselves
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_sales_list, parent, false);
//Returning the Instance of ViewHolder for the inflated Item View
return new ViewHolder(itemView);
}
/**
* Called by RecyclerView to display the data at the specified position. This method should
* update the contents of the {@link ViewHolder#itemView} to reflect the item at the given
* position.
*
* @param holder The ViewHolder which should be updated to represent the contents of the
* item at the given position in the data set.
* @param position The position of the item within the adapter's data set.
*/
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
//Get the data at the position
SalesLite salesLite = getItem(position);
//Bind the Views with the data at the position
holder.bind(position, salesLite);
}
/**
* ViewHolder class for caching View components of the template item view 'R.layout.item_sales_list'
*/
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
//References to the Views required, in the Item View
private TextView mTextViewProductName;
private ImageView mImageViewProductPhoto;
private TextView mTextViewProductSku;
private TextView mTextViewProductCategory;
private TextView mTextViewTotalAvailable;
private TextView mTextViewSupplierNameCode;
private TextView mTextViewSupplierPrice;
private TextView mTextViewSupplierAvailability;
private Button mButtonDeleteProduct;
private Button mButtonSell;
private Group mGroupTopSupplier;
private Typeface mTotalAvailableTypeface;
/**
* Constructor of {@link ViewHolder}
*
* @param itemView Inflated Instance of the Item View 'R.layout.item_sales_list'
*/
ViewHolder(View itemView) {
super(itemView);
//Finding the Views needed
mTextViewProductName = itemView.findViewById(R.id.text_product_item_name);
mImageViewProductPhoto = itemView.findViewById(R.id.image_product_item_photo);
mTextViewProductSku = itemView.findViewById(R.id.text_product_item_sku);
mTextViewProductCategory = itemView.findViewById(R.id.text_product_item_category);
mTextViewTotalAvailable = itemView.findViewById(R.id.text_sales_list_item_total_available);
mTextViewSupplierNameCode = itemView.findViewById(R.id.text_sales_list_item_supplier_name_code);
mTextViewSupplierPrice = itemView.findViewById(R.id.text_sales_list_item_supplier_price);
mTextViewSupplierAvailability = itemView.findViewById(R.id.text_sales_list_item_supplier_availability);
mButtonDeleteProduct = itemView.findViewById(R.id.btn_sales_list_item_delete);
mButtonSell = itemView.findViewById(R.id.btn_sales_list_item_sell);
mGroupTopSupplier = itemView.findViewById(R.id.group_sales_list_item_top_supplier);
//Reading the original typeface of "Total Available" TextView
mTotalAvailableTypeface = mTextViewTotalAvailable.getTypeface();
//Registering the Click listeners on the required views
mButtonDeleteProduct.setOnClickListener(this);
mButtonSell.setOnClickListener(this);
itemView.setOnClickListener(this);
}
/**
* Method that binds the views with the data at the position {@code salesLite}
*
* @param position The position of the Item in the list
* @param salesLite The {@link SalesLite} data at the item position
*/
void bind(int position, SalesLite salesLite) {
//Bind the Product Name
mTextViewProductName.setText(salesLite.getProductName());
//Bind the Product SKU
mTextViewProductSku.setText(salesLite.getProductSku());
//Set Barcode typeface for the SKU
mTextViewProductSku.setTypeface(mProductSkuTypeface);
//Download and Bind the Product Photo at the position
ImageDownloaderFragment.newInstance(
((FragmentActivity) mImageViewProductPhoto.getContext()).getSupportFragmentManager(), position)
.executeAndUpdate(mImageViewProductPhoto, salesLite.getDefaultImageUri(), position);
//Bind the Product Category
mTextViewProductCategory.setText(salesLite.getCategoryName());
//Retrieving the Resources instance
Resources resources = itemView.getContext().getResources();
//Reading the Total Available Quantity
int totalAvailableQuantity = salesLite.getTotalAvailableQuantity();
//Checking the Total Available Quantity
if (totalAvailableQuantity > 0) {
//When we have some quantity to sell
//Setting the Text, Color and Typeface to show the Total Available Quantity
TextAppearanceUtility.setHtmlText(mTextViewTotalAvailable, resources.getString(R.string.sales_list_item_total_available, totalAvailableQuantity));
mTextViewTotalAvailable.setTextColor(ContextCompat.getColor(itemView.getContext(), R.color.salesListItemTotalAvailableColor));
mTextViewTotalAvailable.setTypeface(mTotalAvailableTypeface);
mTextViewTotalAvailable.setAllCaps(false);
//Ensuring the Top Supplier details and the button to sell are visible
mGroupTopSupplier.setVisibility(View.VISIBLE);
//Setting the Supplier Name and its Code
mTextViewSupplierNameCode.setText(resources.getString(R.string.sales_list_item_supplier_name_code_format, salesLite.getTopSupplierName(), salesLite.getTopSupplierCode()));
//Setting the Selling Price of the Item
mTextViewSupplierPrice.setText(resources.getString(R.string.sales_list_item_supplier_selling_price,
Currency.getInstance(Locale.getDefault()).getSymbol() + " " + salesLite.getSupplierUnitPrice()));
//Setting the Availability at the Supplier
mTextViewSupplierAvailability.setText(String.valueOf(salesLite.getSupplierAvailableQuantity()));
} else {
//When we have no quantity to sell
//Setting the Text, Color and Typeface to display "Out of Stock!"
mTextViewTotalAvailable.setText(resources.getString(R.string.sales_list_item_out_of_stock));
mTextViewTotalAvailable.setTextColor(ContextCompat.getColor(itemView.getContext(), R.color.salesListItemOutOfStockColor));
mTextViewTotalAvailable.setTypeface(mTotalAvailableTypeface, Typeface.BOLD);
mTextViewTotalAvailable.setAllCaps(true);
//Hiding the Top Supplier details and the button to sell
mGroupTopSupplier.setVisibility(View.GONE);
}
}
/**
* Called when a view has been clicked.
*
* @param view The view that was clicked.
*/
@Override
public void onClick(View view) {
//Checking if the adapter position is valid
int adapterPosition = getAdapterPosition();
if (adapterPosition > RecyclerView.NO_POSITION) {
//When the adapter position is valid
//Get the data at the position
SalesLite salesLite = getItem(adapterPosition);
//Get the View Id clicked
int clickedViewId = view.getId();
//Taking action based on the view clicked
if (clickedViewId == itemView.getId()) {
//When the entire Item View is clicked
//Dispatch the event to the action listener
mActionsListener.onEditSales(adapterPosition, salesLite, mImageViewProductPhoto);
} else if (clickedViewId == mButtonDeleteProduct.getId()) {
//When the "Delete Product" button is clicked
//Dispatch the event to the action listener
mActionsListener.onDeleteProduct(adapterPosition, salesLite);
} else if (clickedViewId == mButtonSell.getId()) {
//When the "Sell 1" button is clicked
//Dispatch the event to the action listener
mActionsListener.onSellOneQuantity(adapterPosition, salesLite);
}
}
}
}
}
/**
* Listener that implements {@link SalesListUserActionsListener} to receive
* event callbacks for User actions on RecyclerView list of Products for Selling.
*/
private class UserActionsListener implements SalesListUserActionsListener {
/**
* Callback Method of {@link SalesListUserActionsListener} invoked when
* the user clicks on the Item View itself. This should launch the
* {@link SalesConfigActivity}
* for editing the Sales data of the Product identified by {@link SalesLite#mProductId}.
*
* @param itemPosition The adapter position of the Item View clicked.
* @param salesLite The {@link SalesLite} associated with the Item View clicked.
* @param imageViewProductPhoto The ImageView of the Adapter Item that displays the Image
*/
@Override
public void onEditSales(int itemPosition, SalesLite salesLite, ImageView imageViewProductPhoto) {
//Creating ActivityOptions for Shared Element Transition
//where the ImageView is the Shared Element
ActivityOptionsCompat activityOptionsCompat =
ActivityOptionsCompat.makeSceneTransitionAnimation(requireActivity(),
imageViewProductPhoto,
TextUtils.isEmpty(salesLite.getDefaultImageUri()) ? getString(R.string.transition_name_product_photo) : salesLite.getDefaultImageUri()
);
//Delegating to the Presenter to handle the event
mPresenter.editProductSales(salesLite.getProductId(), activityOptionsCompat);
}
/**
* Callback Method of {@link SalesListUserActionsListener} invoked when
* the user clicks on the "Delete Product" button. This should delete the Product
* identified by {@link SalesLite#mProductId} from the database along with its relationship
* with other tables in database.
*
* @param itemPosition The adapter position of the Item View clicked.
* @param salesLite The {@link SalesLite} associated with the Item View clicked.
*/
@Override
public void onDeleteProduct(int itemPosition, SalesLite salesLite) {
//Delegating to the Presenter to handle the event
mPresenter.deleteProduct(salesLite.getProductId(), salesLite.getProductSku());
}
/**
* Callback Method of {@link SalesListUserActionsListener} invoked when
* the user clicks on the "Sell 1" button. This should decrease the Available Quantity
* from the Top Supplier {@link SalesLite#mSupplierAvailableQuantity} by 1, indicating one Quantity
* of the Product was sold/shipped.
*
* @param itemPosition The adapter position of the Item View clicked.
* @param salesLite The {@link SalesLite} associated with the Item View clicked.
*/
@Override
public void onSellOneQuantity(int itemPosition, SalesLite salesLite) {
//Delegating to the Presenter to handle the event
mPresenter.sellOneQuantity(salesLite);
}
}
}