Skip to content

Commit

Permalink
Merge pull request #89 from Picard4/Group-14-Main
Browse files Browse the repository at this point in the history
Pushing Group 14's changes into main
  • Loading branch information
Picard4 authored Apr 29, 2024
2 parents 0bf809f + bcc43af commit f5aecc3
Show file tree
Hide file tree
Showing 7 changed files with 313 additions and 146 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@

public class LeaderboardActivity extends AppCompatActivity {

private int numberOfUsers = 10;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Expand Down Expand Up @@ -72,25 +70,26 @@ public void onPageScrollStateChanged(int state) {

backButton.setOnClickListener(v -> onBackPressed());

// The default number of ranks shown is 10.
// Please check the LeaderboardAdapter's fields if you wish to change the default.
tenButton.setBackgroundColor(optionSelectedColor);

tenButton.setOnClickListener(v -> {
numberOfUsers = 10;
leaderboardPagerAdapter.setNumberOfUsers(numberOfUsers);
leaderboardPagerAdapter.changeLargestNumberRankToDisplay(10);
findViewById(R.id.btnTen).setBackgroundColor(optionSelectedColor);
findViewById(R.id.btnTwentyFive).setBackgroundColor(optionAvailableColor);
findViewById(R.id.btnAll).setBackgroundColor(optionAvailableColor);
});

twentyFiveButton.setOnClickListener(v -> {
numberOfUsers = 25;
leaderboardPagerAdapter.setNumberOfUsers(numberOfUsers);
leaderboardPagerAdapter.changeLargestNumberRankToDisplay(25);
findViewById(R.id.btnTen).setBackgroundColor(optionAvailableColor);
findViewById(R.id.btnTwentyFive).setBackgroundColor(optionSelectedColor);
findViewById(R.id.btnAll).setBackgroundColor(optionAvailableColor);
});

allButton.setOnClickListener(v -> {
numberOfUsers = 0;
leaderboardPagerAdapter.setNumberOfUsers(numberOfUsers);
leaderboardPagerAdapter.changeLargestNumberRankToDisplay(0);
findViewById(R.id.btnTen).setBackgroundColor(optionAvailableColor);
findViewById(R.id.btnTwentyFive).setBackgroundColor(optionAvailableColor);
findViewById(R.id.btnAll).setBackgroundColor(optionSelectedColor);
Expand Down Expand Up @@ -129,13 +128,13 @@ public void onNothingSelected(AdapterView<?> parent) {
everyoneButton.setBackgroundColor(optionSelectedColor);

averageButton.setOnClickListener(v -> {
leaderboardPagerAdapter.setCurrentLeaderboardType(LeaderboardFragment.LeaderboardType.Average);
leaderboardPagerAdapter.setCurrentLeaderboardRankingListType(LeaderboardFragment.RankingListType.AVERAGE);
averageButton.setBackgroundColor(optionSelectedColor);
bestButton.setBackgroundColor(optionAvailableColor);
});

bestButton.setOnClickListener(v -> {
leaderboardPagerAdapter.setCurrentLeaderboardType(LeaderboardFragment.LeaderboardType.Best);
leaderboardPagerAdapter.setCurrentLeaderboardRankingListType(LeaderboardFragment.RankingListType.BEST);
averageButton.setBackgroundColor(optionAvailableColor);
bestButton.setBackgroundColor(optionSelectedColor);
});
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ protected List<Ranking> calculateLatestAverageRankingsData(List<LeaderboardPager
continue;

if (!statsMap.containsKey(trackUser.nickname)) {
statsMap.put(trackUser.nickname, new SummedStatTrackUser(trackUser));
SummedStatTrackUser nextSummedStatTrackUser = new SummedStatTrackUser(trackUser);
nextSummedStatTrackUser.setScoreSum(new Speed(nextSummedStatTrackUser.getPlaceHolderTrackUser().trackStatistics.getAverageMovingSpeed().speed_mps()));
statsMap.put(trackUser.nickname, nextSummedStatTrackUser);
}
else {
SummedStatTrackUser existingRecord = statsMap.get(trackUser.nickname);
existingRecord.getPlaceHolderTrackUser().trackStatistics.setMaxSpeed(
new Speed(existingRecord.getPlaceHolderTrackUser().trackStatistics.getAverageMovingSpeed().speed_mps()
+ trackUser.trackStatistics.getAverageMovingSpeed().speed_mps())
Speed oldSpeed = (Speed)existingRecord.getScoreSum();
existingRecord.setScoreSum(
new Speed(oldSpeed.speed_mps() + trackUser.trackStatistics.getAverageMovingSpeed().speed_mps())
);
existingRecord.incrementSumFactorCount();
}
Expand Down Expand Up @@ -100,7 +102,8 @@ private String getAverageMovingSpeedDisplay(Speed averageMovingSpeed) {
}

private Speed getAverageSpeedFromSummedStatTrackUser(SummedStatTrackUser summedStatTrackUser) {
return new Speed(summedStatTrackUser.getPlaceHolderTrackUser().trackStatistics.getAverageMovingSpeed().speed_mps() / summedStatTrackUser.getSumFactorCount());
Speed averageSpeed = (Speed)summedStatTrackUser.getScoreSum();
return new Speed(averageSpeed.speed_mps() / summedStatTrackUser.getSumFactorCount());
}

private class SortByAverageAverageMovingSpeed implements Comparator<SummedStatTrackUser> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ protected List<Ranking> calculateLatestAverageRankingsData(List<LeaderboardPager
continue;

if (!statsMap.containsKey(trackUser.nickname)) {
statsMap.put(trackUser.nickname, new SummedStatTrackUser(trackUser));
SummedStatTrackUser nextSummedStatTrackUser = new SummedStatTrackUser(trackUser);
nextSummedStatTrackUser.setScoreSum(new Distance(nextSummedStatTrackUser.getPlaceHolderTrackUser().trackStatistics.getTotalDistance().distance_m()));
statsMap.put(trackUser.nickname, nextSummedStatTrackUser);
}
else {
SummedStatTrackUser existingRecord = statsMap.get(trackUser.nickname);
existingRecord.getPlaceHolderTrackUser().trackStatistics.setTotalDistance(
new Distance(existingRecord.getPlaceHolderTrackUser().trackStatistics.getTotalDistance().distance_m()
+ trackUser.trackStatistics.getTotalDistance().distance_m())
Distance oldDistance = (Distance)existingRecord.getScoreSum();
existingRecord.setScoreSum(
new Distance(oldDistance.distance_m() + trackUser.trackStatistics.getTotalDistance().distance_m())
);
existingRecord.incrementSumFactorCount();
}
Expand Down Expand Up @@ -76,7 +78,8 @@ private String getDistanceDisplay(Distance distance) {
}

private Distance getAverageDistanceFromSummedStatTrackUser(SummedStatTrackUser summedStatTrackUser) {
return new Distance(summedStatTrackUser.getPlaceHolderTrackUser().trackStatistics.getTotalDistance().distance_m() / summedStatTrackUser.getSumFactorCount());
Distance distance = (Distance)summedStatTrackUser.getScoreSum();
return new Distance(distance.distance_m() / summedStatTrackUser.getSumFactorCount());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,30 @@
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.List;

import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.data.models.Ranking;

public class LeaderboardAdapter extends RecyclerView.Adapter<LeaderboardAdapter.ViewHolder> {
private List<Ranking> displayedRankingList;
private static int largestNumberRankToDisplay = 10;

public LeaderboardAdapter(List<Ranking> displayedRankingList) {
this.displayedRankingList = displayedRankingList;
}

/**
* Sets the largestNumberRankToDisplay, but does not change the leaderboard that is shown on-screen;
* you need to call setDisplayedRankingList(List<Ranking> rankingListToDisplay) for that.
* @param largestNumberRank The largest-number rank that can be displayed in the on-screen leaderboard.
*/
public static void setLargestNumberRankToDisplay(int largestNumberRank) {
largestNumberRankToDisplay = largestNumberRank;
}

@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Expand All @@ -40,17 +52,46 @@ public int getItemCount() {
return displayedRankingList.size();
}

public void setDisplayedRankingList(List<Ranking> displayedRankingList) {
// This if statement is just here to improve efficiency if the user switched LeaderboardFragments but not LeaderboardType
if (this.displayedRankingList == displayedRankingList)
/**
* Changes the list of Rankings that is shown on-screen to the rankingListToDisplay,
* or a filtered version of it if some rankings are restricted from being displayed.
* @param rankingListToDisplay The list of Rankings to be filtered based on the largest-numbered rank we want to show, and displayed in the GUI.
*/
public void setDisplayedRankingList(List<Ranking> rankingListToDisplay) {
List<Ranking> filteredRankingListToDisplay = displayOnlySetAmountOfRanks(rankingListToDisplay);

// This if statement is just here to improve efficiency if the user switched LeaderboardFragments but not anything else
if (this.displayedRankingList == filteredRankingListToDisplay)
return;

this.displayedRankingList = displayedRankingList;
this.displayedRankingList = filteredRankingListToDisplay;

// Since the rankingList could have been remade from the ground up, we have to call notifyDataSetChanged();
// Since the displayedRankingList could have been remade from the ground up, we have to call notifyDataSetChanged();
notifyDataSetChanged();
}

private List<Ranking> displayOnlySetAmountOfRanks(List<Ranking> rankingListToDisplay) {
// Display all the ranks if all ranks are needed or
// the largest-numbered rank is less than the largest-numbered rank we wish to display.
if (largestNumberRankToDisplay <= 0 ||
rankingListToDisplay.get(rankingListToDisplay.size() - 1).getRank() <= largestNumberRankToDisplay)
return rankingListToDisplay;

// The Top X restriction is based on the Rank, not the User's Ranking.
// If three Users are tied for 25th and we want the Top 25, the three 25th place Rankings should all be shown.
List<Ranking> newRankingListToDisplay = new ArrayList<>();
for (int i = 0; i < rankingListToDisplay.size(); i++) {
Ranking nextRanking = rankingListToDisplay.get(i);
if (nextRanking.getRank() > largestNumberRankToDisplay)
break;
newRankingListToDisplay.add(nextRanking);
}
return newRankingListToDisplay;
}

/**
* The class that Rankings are bound to so that they can be shown in the GUI.
*/
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView avatar;
TextView usernameText;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
import de.dennisguse.opentracks.data.models.Ranking;
import de.dennisguse.opentracks.ui.leaderboard.LeaderboardPagerAdapter;

/**
* The base class for every Leaderboard supported by OpenTracks.
*/
public abstract class LeaderboardFragment extends Fragment {

private static DecimalFormat scoreDecimalFormat;
Expand All @@ -26,16 +29,13 @@ public abstract class LeaderboardFragment extends Fragment {
private List<Ranking> averageRankingList;
private List<Ranking> bestRankingList;

private int displayAmount = 0;

public LeaderboardFragment() {
leaderboardAdapter = new LeaderboardAdapter(new ArrayList<>());

}

public enum LeaderboardType {
Average,
Best;
public enum RankingListType {
AVERAGE,
BEST;
}

@Nullable
Expand All @@ -50,54 +50,41 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
return view;
}

/**
* Reads the sent latestLeaderboardData to rank every user in the latestLeaderboardData by the average of their scores across their provided tracks
* that they are willing to share with the public.
* What exactly the "score" is depends on the child class that implements this method.
* @param latestLeaderboardData The leaderboard data that this LeaderboardFragment's Average Ranking list will be based on.
* @return A list of Average Rankings calculated from the sent latestLeaderboardData, in order from first to last.
*/
protected abstract List<Ranking> calculateLatestAverageRankingsData(List<LeaderboardPagerAdapter.PlaceHolderTrackUser> latestLeaderboardData);
protected abstract List<Ranking> calculateLatestBestRankingsData(List<LeaderboardPagerAdapter.PlaceHolderTrackUser> latestLeaderboardData);

public void setDisplayAmount(int newDisplayAmount){
this.displayAmount = newDisplayAmount;
}

public void displayOnlySetAmount() {
// Display all the ranks
if (this.displayAmount <= 0)
return;

int currentDisplayAmount = this.displayAmount;

// Average Ranking List
// In case there is less rankings then the requested amount
if (this.averageRankingList.size() < currentDisplayAmount)
currentDisplayAmount = this.averageRankingList.size();

List<Ranking> newAverageRankingList = new ArrayList<>();
for (int i = 0; i < currentDisplayAmount; i++) {
newAverageRankingList.add(this.averageRankingList.get(i));
}
this.averageRankingList = newAverageRankingList;

// Best Ranking List
// In case there is less rankings then the requested amount
currentDisplayAmount = this.displayAmount;
if (this.bestRankingList.size() < currentDisplayAmount)
currentDisplayAmount = this.bestRankingList.size();
/**
* Reads the sent latestLeaderboardData to rank every user in the latestLeaderboardData by their best score across their provided tracks
* that they are willing to share with the public.
* What exactly the "score" is depends on the child class that implements this method.
* @param latestLeaderboardData The leaderboard data that this LeaderboardFragment's Best Ranking list will be based on.
* @return A list of Best Rankings calculated from the sent latestLeaderboardData, in order from first to last.
*/
protected abstract List<Ranking> calculateLatestBestRankingsData(List<LeaderboardPagerAdapter.PlaceHolderTrackUser> latestLeaderboardData);

List<Ranking> newBestRankingList = new ArrayList<>();
for (int i = 0; i < currentDisplayAmount; i++) {
newBestRankingList.add(this.bestRankingList.get(i));
}
this.bestRankingList = newBestRankingList;
}
/**
* Updates every Ranking list stored in this LeaderboardFragment using the sent latestLeaderboardData.
* @param latestLeaderboardData The data that every Ranking list stored in this LeaderboardFragment will be based on.
*/
public void updateRankingLists(List<LeaderboardPagerAdapter.PlaceHolderTrackUser> latestLeaderboardData) {
this.averageRankingList = calculateLatestAverageRankingsData(latestLeaderboardData);
this.bestRankingList = calculateLatestBestRankingsData(latestLeaderboardData);

displayOnlySetAmount();
}

public void setDisplayedRankingList(LeaderboardType leaderboardType) {
if (leaderboardType == LeaderboardType.Average)
/**
* Changes the Ranking list that this LeaderboardFragment is displaying in the GUI.
* @param rankingListType The type of Ranking list that this LeaderboardFragment ought to display.
*/
public void setDisplayedRankingList(RankingListType rankingListType) {
if (rankingListType == RankingListType.AVERAGE)
leaderboardAdapter.setDisplayedRankingList(averageRankingList);
else if (leaderboardType == LeaderboardType.Best)
else if (rankingListType == RankingListType.BEST)
leaderboardAdapter.setDisplayedRankingList(bestRankingList);
}

Expand All @@ -107,15 +94,25 @@ protected static DecimalFormat getScoreDecimalFormat() {
return scoreDecimalFormat;
}

/**
* A class that assists with calculating average scores by allowing the statistic that is being
* tracked as a "score" to be summed outside of the PlaceHolderTrackUser.
*/
protected class SummedStatTrackUser {
private LeaderboardPagerAdapter.PlaceHolderTrackUser placeHolderTrackUser;
private int sumFactorCount;
private Object scoreSum;

public SummedStatTrackUser(LeaderboardPagerAdapter.PlaceHolderTrackUser placeHolderTrackUser) {
this.placeHolderTrackUser = placeHolderTrackUser;
sumFactorCount = 1;
}

public SummedStatTrackUser(LeaderboardPagerAdapter.PlaceHolderTrackUser placeHolderTrackUser, Object scoreSum) {
this(placeHolderTrackUser);
setScoreSum(scoreSum);
}

public LeaderboardPagerAdapter.PlaceHolderTrackUser getPlaceHolderTrackUser() {
return placeHolderTrackUser;
}
Expand All @@ -127,5 +124,13 @@ public int getSumFactorCount() {
public void incrementSumFactorCount() {
sumFactorCount++;
}

public Object getScoreSum() {
return scoreSum;
}

public void setScoreSum(Object scoreSum) {
this.scoreSum = scoreSum;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@ protected List<Ranking> calculateLatestAverageRankingsData(List<LeaderboardPager
if (!trackUser.socialAllow)
continue;

statsMap.computeIfAbsent(trackUser.nickname, k -> new SummedStatTrackUser(trackUser));
statsMap.computeIfAbsent(trackUser.nickname, k -> new SummedStatTrackUser(trackUser, trackUser.trackStatistics.getMovingTime().abs()));
SummedStatTrackUser existingRecord = statsMap.get(trackUser.nickname);
existingRecord.getPlaceHolderTrackUser().trackStatistics.setMovingTime(
existingRecord.getPlaceHolderTrackUser().trackStatistics.getMovingTime().plus(
trackUser.trackStatistics.getMovingTime()
)
Duration oldDuration = (Duration)existingRecord.getScoreSum();
existingRecord.setScoreSum(
oldDuration.plus(trackUser.trackStatistics.getMovingTime())
);
existingRecord.incrementSumFactorCount();
}
Expand All @@ -36,7 +35,8 @@ protected List<Ranking> calculateLatestAverageRankingsData(List<LeaderboardPager
int consecutiveTies = 0;
String lastScore = "";
for (SummedStatTrackUser summedStatTrackUser : latestSummedLeaderboardData) {
Duration averageMovingTime = summedStatTrackUser.getPlaceHolderTrackUser().trackStatistics.getMovingTime().dividedBy(summedStatTrackUser.getSumFactorCount());
Duration totalMovingTime = (Duration)summedStatTrackUser.getScoreSum();
Duration averageMovingTime = totalMovingTime.dividedBy(summedStatTrackUser.getSumFactorCount());
Ranking nextRanking = new Ranking(
++rank,
summedStatTrackUser.getPlaceHolderTrackUser().nickname,
Expand All @@ -58,8 +58,9 @@ protected List<Ranking> calculateLatestAverageRankingsData(List<LeaderboardPager
private class SortByAverageMovingTime implements Comparator<SummedStatTrackUser> {
@Override
public int compare(SummedStatTrackUser user1, SummedStatTrackUser user2) {
return user2.getPlaceHolderTrackUser().trackStatistics.getMovingTime().compareTo(
user1.getPlaceHolderTrackUser().trackStatistics.getMovingTime());
Duration user1MovingTime = (Duration) user1.getScoreSum();
Duration user2MovingTime = (Duration) user2.getScoreSum();
return user2MovingTime.compareTo(user1MovingTime);
}
}

Expand Down

0 comments on commit f5aecc3

Please sign in to comment.