Chapter 3: Java - Part 23
Unfortunately, getting our app to distribute the tax proportionally among Diners is actually a little tricky. Whereas the tip was simply a percentage that we could multiply every Diner's total by, the tax is an absolute number. We can't split the tax between all Diners evenly; that wouldn't be fair. We want to allocate the tax so that each Diner pays an amount that is proportional to what they ordered. Let's start by declaring a new variable.
private double taxPercentValue;
This double, taxPercentValue, will be used to keep track of the tax percentage. Normally, when you get a bill at a restaurant, it'll show the tax as an absolute amount, which is then added to your subtotal, to get to the grand total. Sometimes, the bill will say what the tax percentage is, but not always. Thus, we only give the user the option to put in the absolute amount for tax, since that should always be stated clearly on the bill, and generate the percentage ourselves. Now, assign it a starting value of 0.
taxPercentValue = 0.0;
Now go to the calcGrandTotal method we wrote. Under the for loop that is used to calculate grandTotal, add this line:
taxPercentValue = tax / grandTotal;
for (int i = 0; i < dinerList.size(); i++) {
dinerList.get(i).setTotalText(tipPercentValue, taxPercentValue);
}
Every time we do something that necessitates a call to calcGrandTotal, we now also calculate taxPercentValue. This double is analogous to tipPercentValue, but for tax. We're going to use this to percentage to calculate how much tax each Diner owes. We do this with the for loop here. For each Diner in dinerList, we call its setTotalText method, passing it tipPercentValue and taxPercentValue as arguments. We haven't created the setTotalText method for the Diner class yet, but we will now. Its purpose is to set the tvSplitBill of a Diner to the Diner's total bill, including tip and tax. Go to the Diner class and create this method:
public void setTotalText(double tip, double tax) {
tvSplitBill.setText("$" + String.format("%,.2f", total * (1 + tip) + total * tax));
}
This method is pretty easy to figure out. It only does one thing. It takes the tip and tax percentages it's passed, and uses them to set tvSplitBill. The math is pretty simple: total * (1 + tip) + total * tax. We get the total, multiply it by 1 plus the tip percent, giving us the total including the tip, then add the total multiplied by the tax percent. Thus, the sum we get will be the Diner's total bill, tip, tax, and all. Now, you may be wondering, since we're setting tvSplitBill in this new method, do we still need to set it in the updateTotal method? The answer is no. So go to the updateTotal method, and delete the line that sets the Text for tvSplitBill. And since we don't need to set tvSplitBill in updateTotal anymore (since we now take care of that in setTotalText), we don't need updateTotal to have a tip parameter anymore either. So we can go ahead and remove it. In other words, our updateTotal method should now look like this:
public void updateTotal(EditText toBeUpdated) {
total = 0.0;
toBeUpdated.setText("$" + String.format("%,.2f", editTextToDouble(toBeUpdated)));
for (int i = 0; i < orderList.size(); i++) {
total += editTextToDouble(orderList.get(i));
}
}
Moreover, we can now delete our overloaded updateTotal method entirely. We created the overloaded updateTotal method in order to update tvSplitBill whenever we changed the tip. Since that's no longer updateTotal's job, we don't need that version of updateTotal. Yup, the real reason we even bothered to use it in the first place was so I could fit method overloading into this tutorial. It was never the plan to keep it in the app. Deal with it.
Of course, since we've changed the definition here, we need to change the way we call updateTotal in MainActivity. Go back to MainActivity, and replace the updateTotal call in onFocusChange with this:
dinerList.get(i).updateTotal((EditText) v);
And delete the for loop that uses the now-defunct overloaded updateTotal method in onProgressChanged. We're now relying on the code in calcGrandTotal to do what that used to do. Actually, instead of just deleting it, feel free to replace it with a comment, like this:
// We used to have an overloaded updateTotal method here, but we no longer need it.
// public void updateTotal() {
// updateTotal(etFirstOrder);
// }
Commenting out parts of your code is a good way of preserving the history of your app, or just testing what happens if some lines are skipped.
Cool, we're basically done with tax now. To re-cap what we did: We changed the updateTotal method so that its main job was just to calculate a Diner's total, and not to actually set tvSplitBill. We made a new method that is specifically meant to set tvSplitBill. This new method does so using the tip percent and tax percent. We get the tax percent by dividing the tax by grandTotal. Test our app!
Put some crazy numbers in and, if you have the patience, check the numbers our app calculates to see if they're accurate. Everything should be working great. The grand total should include all orders, the tip, and the tax. Each Diner's portion of the bill should be his own order(s), plus the appropriate amount of tip and tax. We pretty much have our tip calculator, good and ready, right here. The only thing you may notice is some small rounding errors in the split bill (although not in this screenshot). This will occasionally happen, especially with a large number of Diners. The individual amounts in the split bill may not quite add up to the grand total. It's not a big enough issue that I want to spend time on this tutorial to fix it. That said, if it bothers you, you can treat this as an opportunity to do some of your own coding, without the training wheels. Have fun*!