Skip to content

Commit

Permalink
Overhauled the Top X system described in Ticket 39.
Browse files Browse the repository at this point in the history
Filtering a Leaderboard by the Top X no longer calls a refresh; it also filters based on Rank rather than Ranking, meaning that if there are three users tied for 25th place and we want the top 25, all three 25th place Rankings will now be shown. Expanded the test data to make demoing easier.
  • Loading branch information
Picard4 committed Apr 28, 2024
1 parent e7a7b37 commit 660e616
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 69 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,26 +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.changeNumberOfDisplayedRanks(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.changeNumberOfDisplayedRanks(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.changeNumberOfDisplayedRanks(0);
findViewById(R.id.btnTen).setBackgroundColor(optionAvailableColor);
findViewById(R.id.btnTwentyFive).setBackgroundColor(optionAvailableColor);
findViewById(R.id.btnAll).setBackgroundColor(optionSelectedColor);
Expand Down Expand Up @@ -130,13 +128,13 @@ public void onNothingSelected(AdapterView<?> parent) {
everyoneButton.setBackgroundColor(optionSelectedColor);

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

bestButton.setOnClickListener(v -> {
leaderboardPagerAdapter.setCurrentLeaderboardType(LeaderboardFragment.LeaderboardType.Best);
leaderboardPagerAdapter.setCurrentLeaderboardType(LeaderboardFragment.LeaderboardType.BEST);
averageButton.setBackgroundColor(optionAvailableColor);
bestButton.setBackgroundColor(optionSelectedColor);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.ui.leaderboard.leaderboardFragment.AverageMovingSpeedLeaderboardFragment;
import de.dennisguse.opentracks.ui.leaderboard.leaderboardFragment.LeaderboardAdapter;
import de.dennisguse.opentracks.ui.leaderboard.leaderboardFragment.MaxSpeedLeaderboardFragment;
import de.dennisguse.opentracks.ui.leaderboard.leaderboardFragment.DistanceLeaderboardFragment;
import de.dennisguse.opentracks.ui.leaderboard.leaderboardFragment.LeaderboardFragment;
Expand All @@ -34,7 +35,7 @@ public LeaderboardPagerAdapter(FragmentManager fm) {
averageMovingSpeedLeaderboardFragment = new AverageMovingSpeedLeaderboardFragment();

currentLeaderboardFragment = movingTimeLeaderboardFragment;
currentLeaderboardType = LeaderboardFragment.LeaderboardType.Average;
currentLeaderboardType = LeaderboardFragment.LeaderboardType.AVERAGE;
refreshLeaderboardFragmentData();
}

Expand Down Expand Up @@ -122,13 +123,11 @@ public void refreshLeaderboardFragmentData() {
currentLeaderboardFragment.setDisplayedRankingList(currentLeaderboardType);
}

public void setNumberOfUsers(int numberOfUsers) {
movingTimeLeaderboardFragment.setDisplayAmount(numberOfUsers);
distanceLeaderboardFragment.setDisplayAmount(numberOfUsers);
maxSpeedLeaderboardFragment.setDisplayAmount(numberOfUsers);
averageMovingSpeedLeaderboardFragment.setDisplayAmount(numberOfUsers);
refreshLeaderboardFragmentData();
public void changeNumberOfDisplayedRanks(int numberOfUsers) {
LeaderboardAdapter.setNumberOfRanksToDisplay(numberOfUsers);
currentLeaderboardFragment.setDisplayedRankingList(currentLeaderboardType);
}

private List<PlaceHolderTrackUser> readLatestLeaderboardData() {
// This is where we get the data from the database for the runs that will be in the leaderboard.
List<PlaceHolderTrackUser> testData = new ArrayList();
Expand Down Expand Up @@ -157,7 +156,7 @@ private List<PlaceHolderTrackUser> readLatestLeaderboardData() {
stats.setMovingTime(Duration.ofHours(1));
testData.add(new PlaceHolderTrackUser("User Two", "Steamboat Springs", true, stats));

if (altTestData) {
if (!altTestData) {
stats = new TrackStatistics();
stats.setTotalDistance(new Distance(1000));
stats.setMaxSpeed(new Speed(20));
Expand All @@ -177,7 +176,7 @@ private List<PlaceHolderTrackUser> readLatestLeaderboardData() {
stats.setMovingTime(Duration.ofHours(6));
testData.add(new PlaceHolderTrackUser("User Four","Steamboat Springs", true, stats));

if (altTestData) {
if (!altTestData) {
stats = new TrackStatistics();
stats.setTotalDistance(new Distance(2500));
stats.setMaxSpeed(new Speed(55));
Expand All @@ -191,7 +190,7 @@ private List<PlaceHolderTrackUser> readLatestLeaderboardData() {
stats.setMovingTime(Duration.ofHours(4));
testData.add(new PlaceHolderTrackUser("User Five","North California CA", true, stats));

if (altTestData) {
if (!altTestData) {
stats = new TrackStatistics();
stats.setTotalDistance(new Distance(1000));
stats.setMaxSpeed(new Speed(50));
Expand Down Expand Up @@ -223,7 +222,7 @@ private List<PlaceHolderTrackUser> readLatestLeaderboardData() {
stats.setMovingTime(Duration.ofMinutes(30));
testData.add(new PlaceHolderTrackUser("User Nine", "North California CA", true, stats));

if (altTestData) {
if (!altTestData) {
stats = new TrackStatistics();
stats.setTotalDistance(new Distance(154));
stats.setMaxSpeed(new Speed(150));
Expand All @@ -241,6 +240,90 @@ private List<PlaceHolderTrackUser> readLatestLeaderboardData() {
stats.setMaxSpeed(new Speed(120));
stats.setMovingTime(Duration.ofMinutes(34));
testData.add(new PlaceHolderTrackUser("User Twelve","Steamboat Springs", true, stats));

stats = new TrackStatistics();
stats.setTotalDistance(new Distance(154));
stats.setMaxSpeed(new Speed(150));
stats.setMovingTime(Duration.ofMinutes(59));
testData.add(new PlaceHolderTrackUser("User Thirteen","Steamboat Springs", true, stats));

stats = new TrackStatistics();
stats.setTotalDistance(new Distance(134));
stats.setMaxSpeed(new Speed(130));
stats.setMovingTime(Duration.ofMinutes(59));
testData.add(new PlaceHolderTrackUser("User Fourteen","Steamboat Springs", true, stats));

stats = new TrackStatistics();
stats.setTotalDistance(new Distance(159));
stats.setMaxSpeed(new Speed(120));
stats.setMovingTime(Duration.ofMinutes(34));
testData.add(new PlaceHolderTrackUser("User Fifteen","Steamboat Springs", true, stats));

stats = new TrackStatistics();
stats.setTotalDistance(new Distance(154));
stats.setMaxSpeed(new Speed(150));
stats.setMovingTime(Duration.ofMinutes(59));
testData.add(new PlaceHolderTrackUser("User Sixteen","Steamboat Springs", true, stats));

stats = new TrackStatistics();
stats.setTotalDistance(new Distance(134));
stats.setMaxSpeed(new Speed(130));
stats.setMovingTime(Duration.ofMinutes(59));
testData.add(new PlaceHolderTrackUser("User Seventeen","Steamboat Springs", true, stats));

stats = new TrackStatistics();
stats.setTotalDistance(new Distance(159));
stats.setMaxSpeed(new Speed(120));
stats.setMovingTime(Duration.ofMinutes(34));
testData.add(new PlaceHolderTrackUser("User Eighteen","Steamboat Springs", true, stats));

stats = new TrackStatistics();
stats.setTotalDistance(new Distance(154));
stats.setMaxSpeed(new Speed(150));
stats.setMovingTime(Duration.ofMinutes(59));
testData.add(new PlaceHolderTrackUser("User Nineteen","Steamboat Springs", true, stats));

stats = new TrackStatistics();
stats.setTotalDistance(new Distance(134));
stats.setMaxSpeed(new Speed(130));
stats.setMovingTime(Duration.ofMinutes(59));
testData.add(new PlaceHolderTrackUser("User Twenty","Steamboat Springs", true, stats));

stats = new TrackStatistics();
stats.setTotalDistance(new Distance(159));
stats.setMaxSpeed(new Speed(120));
stats.setMovingTime(Duration.ofMinutes(34));
testData.add(new PlaceHolderTrackUser("User Twenty One","Steamboat Springs", true, stats));

stats = new TrackStatistics();
stats.setTotalDistance(new Distance(154));
stats.setMaxSpeed(new Speed(150));
stats.setMovingTime(Duration.ofMinutes(59));
testData.add(new PlaceHolderTrackUser("User Twenty Two","Steamboat Springs", true, stats));

stats = new TrackStatistics();
stats.setTotalDistance(new Distance(134));
stats.setMaxSpeed(new Speed(130));
stats.setMovingTime(Duration.ofMinutes(59));
testData.add(new PlaceHolderTrackUser("User Twenty Three","Steamboat Springs", true, stats));

stats = new TrackStatistics();
stats.setTotalDistance(new Distance(159));
stats.setMaxSpeed(new Speed(120));
stats.setMovingTime(Duration.ofMinutes(34));
testData.add(new PlaceHolderTrackUser("User Twenty Four","Steamboat Springs", true, stats));

stats = new TrackStatistics();
stats.setTotalDistance(new Distance(154));
stats.setMaxSpeed(new Speed(150));
stats.setMovingTime(Duration.ofMinutes(59));
testData.add(new PlaceHolderTrackUser("User Twenty Five","Steamboat Springs", true, stats));

stats = new TrackStatistics();
stats.setTotalDistance(new Distance(134));
stats.setMaxSpeed(new Speed(130));
stats.setMovingTime(Duration.ofMinutes(59));
testData.add(new PlaceHolderTrackUser("User Twenty Six","Steamboat Springs", true, stats));
}

stats = new TrackStatistics();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,25 @@
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 numberOfRanksToDisplay = 10;

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

public static void setNumberOfRanksToDisplay(int numberOfRanks) {
numberOfRanksToDisplay = numberOfRanks;
}

@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Expand All @@ -40,17 +47,36 @@ 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)
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 number of ranks we wish to display
if (numberOfRanksToDisplay <= 0 || rankingListToDisplay.get(rankingListToDisplay.size() - 1).getRank() <= numberOfRanksToDisplay)
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() > numberOfRanksToDisplay)
break;
newRankingListToDisplay.add(nextRanking);
}
return newRankingListToDisplay;
}

static class ViewHolder extends RecyclerView.ViewHolder {
ImageView avatar;
TextView usernameText;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,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;
AVERAGE,
BEST;
}

@Nullable
Expand All @@ -53,51 +50,15 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
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();

List<Ranking> newBestRankingList = new ArrayList<>();
for (int i = 0; i < currentDisplayAmount; i++) {
newBestRankingList.add(this.bestRankingList.get(i));
}
this.bestRankingList = newBestRankingList;
}
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)
if (leaderboardType == LeaderboardType.AVERAGE)
leaderboardAdapter.setDisplayedRankingList(averageRankingList);
else if (leaderboardType == LeaderboardType.Best)
else if (leaderboardType == LeaderboardType.BEST)
leaderboardAdapter.setDisplayedRankingList(bestRankingList);
}

Expand Down

0 comments on commit 660e616

Please sign in to comment.