Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

Expand Down Expand Up @@ -49,6 +48,8 @@ public class IssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
private final Activity mActivity;
private final Callback mCallback;

private List<String> starredIssueIds = new ArrayList<>();

public interface Callback {

void refreshIssues();
Expand Down Expand Up @@ -81,6 +82,11 @@ public void setAllIssues(List<Issue> issues, int errorType) {
}
}

public void setStarredIssues(List<String> issueIds) {
starredIssueIds = issueIds;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it might be easier to annotate mIssues with isStarred rather than having a second list of starredIssueIds? Or have a starredIssueIds be a Set<String> mStarredIssues for easy lookups.

notifyDataSetChanged();
}

public void setAddressError(int error) {
mAddressErrorType = error;
mContacts.clear();
Expand Down Expand Up @@ -124,7 +130,10 @@ public void setFilterAndSearch(String filterText, String searchText) {
} else if (TextUtils.equals(filterText,
mActivity.getResources().getString(R.string.top_issues_filter))) {
mIssues = filterActiveIssues();
} else {
} else if (TextUtils.equals(filterText, mActivity.getResources().getString(R.string.starred_issues_filter))) {
mIssues = filterStarredIssues();
}
else {
// Filter by the category string.
mIssues = filterIssuesByCategory(filterText);
}
Expand Down Expand Up @@ -177,6 +186,16 @@ private ArrayList<Issue> filterActiveIssues() {
return tempIssues;
}

private ArrayList<Issue> filterStarredIssues() {
ArrayList<Issue> tempIssues = new ArrayList<>();
for (Issue issue : mAllIssues) {
if (starredIssueIds.contains(issue.id)) {
tempIssues.add(issue);
}
}
return tempIssues;
}

private ArrayList<Issue> filterIssuesByCategory(String activeCategory) {
ArrayList<Issue> tempIssues = new ArrayList<>();
for (Issue issue : mAllIssues) {
Expand Down Expand Up @@ -232,6 +251,14 @@ public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int
IssueViewHolder vh = (IssueViewHolder) holder;
final Issue issue = mIssues.get(position);
vh.name.setText(issue.name);

if (starredIssueIds.contains(issue.id)) {
vh.name.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_star_yellow_24dp, 0);
} else {
// To undo previously set drawable in the event of an issue being unstarred
vh.name.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0 ,0);
}

vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public class IssueActivity extends AppCompatActivity {
public static final String KEY_ISSUE = "key_issue";
public static final String KEY_IS_LOW_ACCURACY = "key_is_low_accuracy";
public static final String KEY_DONATE_IS_ON = "key_donate_is_on";
public static final String KEY_IS_STARRED = "key_is_starred";

public static final int RESULT_OK = 1;
public static final int RESULT_SERVER_ERROR = 2;
Expand All @@ -80,6 +81,7 @@ public class IssueActivity extends AppCompatActivity {
private boolean mIsLowAccuracy = false;
private boolean mDonateIsOn = false;
private boolean mIsAnimating = false;
private boolean mIsStarred = false;

private ActivityIssueBinding binding;

Expand All @@ -96,12 +98,14 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
}
mIsLowAccuracy = getIntent().getBooleanExtra(KEY_IS_LOW_ACCURACY, false);
mDonateIsOn = getIntent().getBooleanExtra(KEY_DONATE_IS_ON, false);
mIsStarred = getIntent().getBooleanExtra(KEY_IS_STARRED, false);

setContentView(binding.getRoot());

if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(mIssue.name);
// getSupportActionBar().setTitle(mIssue.name);
getSupportActionBar().setDisplayShowTitleEnabled(false);
}

binding.issueName.setText(mIssue.name);
Expand Down Expand Up @@ -202,6 +206,7 @@ protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(KEY_ISSUE, mIssue);
outState.putBoolean(KEY_IS_LOW_ACCURACY, mIsLowAccuracy);
outState.putBoolean(KEY_IS_STARRED, mIsStarred);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we annotate mIssue with isStarred you wouldn't need to set/get this in the state.

}

@Override
Expand Down Expand Up @@ -272,6 +277,16 @@ public void onClick(View view) {
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_issue, menu);

MenuItem starItem = menu.findItem(R.id.menu_star);
if (mIsStarred) {
starItem.setIcon(R.drawable.ic_star_white_24dp);
starItem.setTitle(R.string.action_unstar_issue);
} else {
starItem.setIcon(R.drawable.ic_star_outline_white_24dp);
starItem.setTitle(R.string.action_star_issue);
}

return true;
}

Expand All @@ -285,6 +300,17 @@ public boolean onOptionsItemSelected(MenuItem item) {
sendShare();
return true;
}
if (item.getItemId() == R.id.menu_star) {
DatabaseHelper db = AppSingleton.getInstance(getApplicationContext()).getDatabaseHelper();
if (mIsStarred) {
db.removeStarredIssue(mIssue.id);
mIsStarred = false;
} else {
db.addStarredIssue(mIssue.id);
mIsStarred = true;
}
invalidateOptionsMenu();
}
if (item.getItemId() == R.id.menu_details) {
showIssueDetails();
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static android.view.View.VISIBLE;

Expand Down Expand Up @@ -86,6 +87,7 @@ public class MainActivity extends AppCompatActivity implements IssuesAdapter.Cal
private boolean mShowLowAccuracyWarning = true;
private boolean mDonateIsOn = false;
private FirebaseAuth mAuth = null;
private List<String> starredIssues;

private ActivityMainBinding binding;

Expand Down Expand Up @@ -207,7 +209,7 @@ public void onError() {
binding.searchText.setText(mSearchText);
}
} else {
// Safe to use index as the top two filters are hard-coded strings.
// Safe to use index as the top three filters are hard-coded strings.
mFilterText = mFilterAdapter.getItem(0);
}
binding.searchText.setOnClickListener(new View.OnClickListener() {
Expand Down Expand Up @@ -279,6 +281,7 @@ public void onGlobalLayout() {
});

loadStats();
loadStarredIssues();

mAddress = accountManager.getAddress(this);
mLatitude = accountManager.getLat(this);
Expand Down Expand Up @@ -352,6 +355,7 @@ public void startIssueActivity(Context context, Issue issue) {
issueIntent.putExtra(RepCallActivity.KEY_LOCATION_NAME, mLocationName);
issueIntent.putExtra(IssueActivity.KEY_IS_LOW_ACCURACY, mIsLowAccuracy);
issueIntent.putExtra(IssueActivity.KEY_DONATE_IS_ON, mDonateIsOn);
issueIntent.putExtra(IssueActivity.KEY_IS_STARRED, starredIssues.contains(issue.id));
startActivityForResult(issueIntent, ISSUE_DETAIL_REQUEST);
}

Expand Down Expand Up @@ -428,6 +432,12 @@ public void onIssuesReceived(List<Issue> issues) {
mIssuesAdapter.setAllIssues(issues, IssuesAdapter.NO_ERROR);
mIssuesAdapter.setFilterAndSearch(mFilterText, mSearchText);
binding.swipeContainer.setRefreshing(false);

List<String> ids = new ArrayList<>();
for (Issue i : issues) {
ids.add(i.id);
}
AppSingleton.getInstance(getApplicationContext()).getDatabaseHelper().trimStarredIssues(ids);
}
};

Expand Down Expand Up @@ -555,7 +565,7 @@ private void updateOnBackPressedCallbackEnabled() {
}

private void populateFilterAdapterIfNeeded(List<Issue> issues) {
if (mFilterAdapter.getCount() > 2) {
if (mFilterAdapter.getCount() > 3) {
// Already populated. Don't try again.
// This assumes that the categories won't change much during the course of a session.
return;
Expand Down Expand Up @@ -609,6 +619,13 @@ private void loadStats() {
}
}

private void loadStarredIssues() {
starredIssues = AppSingleton.getInstance(getApplicationContext())
.getDatabaseHelper().getStarredIssues();
Log.d(TAG, starredIssues.toString());
mIssuesAdapter.setStarredIssues(starredIssues);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the DBHelper file, I suggested:

Can we instead say getStarredIssues(List ids) and have the DB lookup just look through the starred ones?

I suggest that getting starred issues from an existing list might also be handy because it means we won't have to call notifyDataSetChanged, instead we can just update our mIssues and notifyItemChanged for each issue that is starred.

In other words, this class will do a lot less work and we'll won't need to redraw the issues list a second time.

}

private void showStats() {
Intent intent = new Intent(this, StatsActivity.class);
startActivity(intent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "DatabaseHelper";

private static final int DATABASE_VERSION = 3;
private static final int DATABASE_VERSION = 4;
@VisibleForTesting
protected static final String CALLS_TABLE_NAME = "UserCallsDatabase";
@VisibleForTesting
protected static final String ISSUES_TABLE_NAME = "UserIssuesTable";
@VisibleForTesting
protected static final String CONTACTS_TABLE_NAME = "UserContactsTable";
@VisibleForTesting
protected static final String STARRED_ISSUES_TABLE_NAME = "StarredIssuesTable";

// Can be used to control time in tests.
private TimeProvider mTimeProvider;
Expand Down Expand Up @@ -82,6 +84,15 @@ public static class ContactColumns {
"CREATE TABLE " + CONTACTS_TABLE_NAME + " (" + ContactColumns.CONTACT_ID + " STRING, " +
ContactColumns.CONTACT_NAME + " STRING);";

private static class StarredIssuesColumns {
public static String ID = "issueid";
public static String TIMESTAMP = "timestamp";
}

private static final String STARRED_ISSUES_TABLE_CREATE =
"CREATE TABLE " + STARRED_ISSUES_TABLE_NAME + " (" + StarredIssuesColumns.ID + " STRING, "
+ StarredIssuesColumns.TIMESTAMP + " INTEGER);";

public DatabaseHelper(Context context) {
this(context, new DefaultTimeProvider());
}
Expand All @@ -96,6 +107,7 @@ public void onCreate(SQLiteDatabase db) {
db.execSQL(CALLS_TABLE_CREATE);
db.execSQL(ISSUES_TABLE_CREATE);
db.execSQL(CONTACTS_TABLE_CREATE);
db.execSQL(STARRED_ISSUES_TABLE_CREATE);
}

@Override
Expand Down Expand Up @@ -124,6 +136,10 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
new String[]{Outcome.Status.VM.toString()});
currentDbVersion = 3;
}

if (oldVersion < 4 && currentDbVersion < newVersion) {
db.execSQL(STARRED_ISSUES_TABLE_CREATE);
}
}

/**
Expand Down Expand Up @@ -164,6 +180,21 @@ private void addContact(String contactId, String contactName) {
SQLiteDatabase.CONFLICT_IGNORE);
}

public void addStarredIssue(String issueId) {
ContentValues values = new ContentValues();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add a test that adding the same issue twice doesn't cause trouble.

values.put(StarredIssuesColumns.ID, issueId);
values.put(StarredIssuesColumns.TIMESTAMP, mTimeProvider.currentTimeMillis());
getWritableDatabase().insert(STARRED_ISSUES_TABLE_NAME, null, values);
}

public void removeStarredIssue(String issueId) {
getWritableDatabase().delete(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add a test that there's no issue if we remove an issue that's not in in the starred issues DB.

STARRED_ISSUES_TABLE_NAME,
StarredIssuesColumns.ID + " = ?",
List.of(issueId).toArray(new String[0])
);
}

public String getIssueName(String issueId) {
Cursor c = getReadableDatabase().rawQuery("SELECT " + IssuesColumns.ISSUE_NAME + " FROM " +
ISSUES_TABLE_NAME + " WHERE " + IssuesColumns.ISSUE_ID + " = '" + issueId + "'",
Expand Down Expand Up @@ -333,6 +364,37 @@ public List<Pair<String, Integer>> getCallCountsByIssue() {
return result;
}

public List<String> getStarredIssues() {
Cursor c = getReadableDatabase().rawQuery(
"SELECT " + StarredIssuesColumns.ID + " FROM " + STARRED_ISSUES_TABLE_NAME
+ " ORDER BY " + StarredIssuesColumns.TIMESTAMP, null);
List<String> result = new ArrayList<>();
while (c.moveToNext()) {
result.add(c.getString(0));
}
c.close();
return result;
}

// Delete any starred issues not present in the provided list of issue ids to prevent the
// table from filling up with issues that don't exist any more so the app doesn't have to look
// through as many items when seeing if the issue needs to be marked as starred
public int trimStarredIssues(List<String> ids) {
StringBuilder placeholders = new StringBuilder();
for (int i = 0; i < ids.size(); i++) {
placeholders.append("?");
if (i < ids.size() - 1) {
placeholders.append(", ");
}
}

String whereClause = StarredIssuesColumns.ID + " NOT IN ("
+ placeholders + ")";
String[] whereArgs = ids.toArray(new String[0]);

return getWritableDatabase().delete(STARRED_ISSUES_TABLE_NAME, whereClause, whereArgs);
}

@VisibleForTesting
public static String sanitizeContactId(String contactId) {
// TODO this only works on single quotes and not double quotes. Triple quotes are still
Expand All @@ -342,4 +404,6 @@ public static String sanitizeContactId(String contactId) {
}
return contactId;
}


}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be able to add the star as a svg without having to add all these png assets in different directories -- it'll keep the app binary size from increasing as much and reduce overhead for us if we change it in the future. You can download the star from here: https://fonts.google.com/icons?selected=Material+Symbols+Outlined:star:FILL@0;wght@400;GRAD@0;opsz@24&icon.size=24&icon.color=%23e8eaed

To fill it I think you can make an XML using that SVG and then set the android:fillColor.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This icon isn't high enough contrast. Can we make the star one of the app colors, like dark blue or red or bright blue instead?

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 8 additions & 2 deletions 5calls/app/src/main/res/menu/menu_issue.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@
<item
android:id="@+id/menu_details"
android:title="@string/details_btn"
app:showAsAction="ifRoom"
app:showAsAction="always"
android:icon="@drawable/info_24dp"
/>
<item
android:id="@+id/menu_star"
android:title="@string/action_star_issue"
app:showAsAction="always"
android:icon="@drawable/ic_star_outline_white_24dp"
/>
<item
android:id="@+id/menu_share"
android:title="@string/menu_share"
app:showAsAction="ifRoom"
app:showAsAction="always"
android:icon="@drawable/ic_share_white_24dp"
/>
</menu>
9 changes: 9 additions & 0 deletions 5calls/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -477,9 +477,13 @@
<!-- Filter for showing all issues [CHAR_LIMIT=50] -->
<string name="all_issues_filter">All issues</string>

<!-- Filter for showing starred issue [CHAR_LIMIT=50] -->
<string name="starred_issues_filter">Starred issues</string>

<string-array name="default_filters">
<item>@string/top_issues_filter</item>
<item>@string/all_issues_filter</item>
<item>@string/starred_issues_filter</item>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we hide and/or disable this unless the user has at least 1 starred issue in the current list?

</string-array>

<!-- Title of a section in settings about notifications [CHAR_LIMIT=50] -->
Expand Down Expand Up @@ -635,4 +639,9 @@
<!-- The categories an issue belongs to, when there are more than one. -->
<string name="issue_category_many">Categories: </string>

<!-- Action bar icon tooltip for starring an issue -->
<string name="action_star_issue">Star Issue</string>

<!-- Action bar icon tooltip for un-starring an issue -->
<string name="action_unstar_issue">Unstar Issue</string>
</resources>
Loading