diff --git a/5calls/app/src/androidTest/java/org/a5calls/android/a5calls/controller/MainActivityHappyPathTest.java b/5calls/app/src/androidTest/java/org/a5calls/android/a5calls/controller/MainActivityHappyPathTest.java index 6603197c..62faec3c 100644 --- a/5calls/app/src/androidTest/java/org/a5calls/android/a5calls/controller/MainActivityHappyPathTest.java +++ b/5calls/app/src/androidTest/java/org/a5calls/android/a5calls/controller/MainActivityHappyPathTest.java @@ -2,14 +2,18 @@ import android.content.Context; import android.view.View; + import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.volley.toolbox.HttpResponse; import com.google.android.material.appbar.CollapsingToolbarLayout; +import org.a5calls.android.a5calls.AppSingleton; import org.a5calls.android.a5calls.FakeJSONData; +import org.a5calls.android.a5calls.FiveCallsApplication; import org.a5calls.android.a5calls.R; import org.a5calls.android.a5calls.model.AccountManager; +import org.a5calls.android.a5calls.model.DatabaseHelper; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; @@ -30,6 +34,7 @@ import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withInputType; import static androidx.test.espresso.matcher.ViewMatchers.withText; + import androidx.core.view.GravityCompat; import androidx.drawerlayout.widget.DrawerLayout; import androidx.test.platform.app.InstrumentationRegistry; @@ -70,7 +75,7 @@ public void describeTo(Description description) { /** * Sets up mock responses for API calls */ - private void setupMockResponses(boolean isSplit, boolean hasLocation) { + private void setupMockResponses(boolean isSplit, boolean hasLocation) { // Set up the mock to handle all possible requests with appropriate responses mHttpStack.clearUrlPatternResponses(); @@ -120,8 +125,8 @@ public void testMainUILoadsCorrectly() throws JSONException { // Check that the collapsing toolbar is displayed and contains the location text onView(withId(R.id.collapsing_toolbar)) - .check(matches(isDisplayed())) - .check(matches(withCollapsingToolbarTitle(containsString("BOWLING GREEN")))); + .check(matches(isDisplayed())) + .check(matches(withCollapsingToolbarTitle(containsString("BOWLING GREEN")))); // Check that no location error was shown. onView(withText(R.string.low_accuracy_warning)).check(doesNotExist()); @@ -163,10 +168,122 @@ public void testMainUILoadsCorrectly_NoLocation() { // Verify that a "set your location" button is displayed. onView(withContentDescription(R.string.first_location_title)).check(matches(isDisplayed())); + // No calls to make displayed. + onView(withText("3 calls to make")).check(doesNotExist()); + onView(withText("2 calls to make")).check(doesNotExist()); + // Set the address again for the sake of the next test. AccountManager.Instance.setAddress(context, address); } + @Test + public void testMainUILoadsCorrectly_noLocation_placeholderShown() { + Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + // Clear the location. + String address = AccountManager.Instance.getAddress(context); + AccountManager.Instance.setAddress(context, ""); + setupMockResponses(/*isSplit=*/false, /*hasLocation=*/false); + setupMockRequestQueue(); + + launchMainActivity(1000); + + // Verify that the demo issue is displayed. + onView(withText(R.string.demo_issue_name)).check(matches(isDisplayed())); + // There should be a "1 call to make" note for the demo issue. + onView(withText(R.string.call_count_one)).check(matches(isDisplayed())); + + // Reset address. + AccountManager.Instance.setAddress(context, address); + } + + @Test + public void testMainUILoadCorrectly_oneCall_placeholderShown() { + Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + setupMockResponses(/*isSplit=*/false, /*hasLocation=*/true); + setupMockRequestQueue(); + DatabaseHelper databaseHelper = AppSingleton.getInstance(context).getDatabaseHelper(); + // Add one fake call. + databaseHelper.addCall("issueId", "issueName", "contactId", "contactName", "result", "location"); + + launchMainActivity(1000); + + // Verify that the demo issue is displayed. + onView(withText(R.string.demo_issue_name)).check(matches(isDisplayed())); + // There should be a "1 call to make" note for the demo issue. + onView(withText(R.string.call_count_one)).check(matches(isDisplayed())); + + // Reset the database. + databaseHelper.getWritableDatabase().delete("UserCallsDatabase", null, null); + } + + @Test + public void testMainUILoadCorrectly_twoCalls_placeholderNotShown() { + Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + setupMockResponses(/*isSplit=*/false, /*hasLocation=*/true); + setupMockRequestQueue(); + DatabaseHelper databaseHelper = AppSingleton.getInstance(context).getDatabaseHelper(); + // Add two fake calls. + databaseHelper.addCall("issueId", "issueName", "contactId", "contactName", "result", "location"); + databaseHelper.addCall("issueId", "issueName", "contactId", "contactName", "result", "location"); + + launchMainActivity(1000); + + // Verify that the demo issue is not displayed. + onView(withText(R.string.demo_issue_name)).check(doesNotExist()); + + // Reset the database. + databaseHelper.getWritableDatabase().delete("UserCallsDatabase", null, null); + } + + @Test + public void testMainUILoadCorrectly_fourCalls_placeholderPrefSet_placeholderShown() { + Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + setupMockResponses(/*isSplit=*/false, /*hasLocation=*/true); + setupMockRequestQueue(); + DatabaseHelper databaseHelper = AppSingleton.getInstance(context).getDatabaseHelper(); + // Add four fake calls. + databaseHelper.addCall("issueId", "issueName", "contactId", "contactName", "result", "location"); + databaseHelper.addCall("issueId", "issueName", "contactId", "contactName", "result", "location"); + databaseHelper.addCall("issueId", "issueName", "contactId", "contactName", "result", "location"); + databaseHelper.addCall("issueId", "issueName", "contactId", "contactName", "result", "location"); + // Pretend the user has turned on the placeholder anyway in settings. + AccountManager.Instance.setShowPlaceholderIssue(context, true); + + launchMainActivity(1000); + + // Verify that the demo issue is displayed with "one call to make". + onView(withText(R.string.demo_issue_name)).check(matches(isDisplayed())); + onView(withText(R.string.demo_previous_call_stats_one)).check(doesNotExist()); + onView(withText(R.string.call_count_one)).check(matches(isDisplayed())); + + // Reset the database. + databaseHelper.getWritableDatabase().delete("UserCallsDatabase", null, null); + AccountManager.Instance.setShowPlaceholderIssue(context, false); + } + + @Test + public void testMainUILoadCorrectly_placeholderAlreadyCalled_placeholderPrefSet_placeholderShown() { + Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); + setupMockResponses(/*isSplit=*/false, /*hasLocation=*/true); + setupMockRequestQueue(); + // The user has already done the placeholder call once. + AccountManager.Instance.setPlaceholderIssueCalled(context, true); + // Pretend the user has turned on the placeholder anyway in settings. + AccountManager.Instance.setShowPlaceholderIssue(context, true); + + launchMainActivity(1000); + + // Verify that the demo issue is displayed. + onView(withText(R.string.demo_issue_name)).check(matches(isDisplayed())); + // The "one pretend previous call" is shown. + onView(withText(R.string.demo_previous_call_stats_one)).check(matches(isDisplayed())); + + // Reset state + AccountManager.Instance.setPlaceholderIssueCalled(context, false); + AccountManager.Instance.setShowPlaceholderIssue(context, false); + } + + @Test public void testNavigationDrawerOpens() throws JSONException { setupMockResponses(/*isSplit=*/ false, /*hasLocation=*/true); diff --git a/5calls/app/src/main/java/org/a5calls/android/a5calls/adapter/IssuesAdapter.java b/5calls/app/src/main/java/org/a5calls/android/a5calls/adapter/IssuesAdapter.java index 92000307..5059d1e2 100644 --- a/5calls/app/src/main/java/org/a5calls/android/a5calls/adapter/IssuesAdapter.java +++ b/5calls/app/src/main/java/org/a5calls/android/a5calls/adapter/IssuesAdapter.java @@ -12,6 +12,7 @@ import org.a5calls.android.a5calls.AppSingleton; import org.a5calls.android.a5calls.R; +import org.a5calls.android.a5calls.model.AccountManager; import org.a5calls.android.a5calls.model.Category; import org.a5calls.android.a5calls.model.Contact; import org.a5calls.android.a5calls.model.DatabaseHelper; @@ -270,7 +271,8 @@ public void populateIssueContacts(Issue issue) { * This is normally done in onBindViewHolder, but is needed for deep linking * where we bypass the RecyclerView. */ - public static void populateIssueContacts(Issue issue, List contacts, boolean isSplitDistrict) { + public static void populateIssueContacts(Issue issue, List contacts, + boolean isSplitDistrict) { if (issue == null || issue.contactAreas.isEmpty()) { return; } @@ -335,6 +337,21 @@ public void onClick(View v) { } }); + if (issue.isPlaceholder) { + vh.numCalls.setVisibility(View.VISIBLE); + if (AccountManager.Instance.getPlaceholderIssueCalled(mActivity)) { + vh.numCalls.setVisibility(View.GONE); + vh.previousCallStats.setVisibility(View.VISIBLE); + vh.previousCallStats.setText(mActivity.getResources().getString( + R.string.demo_previous_call_stats_one)); + } else { + vh.numCalls.setText(mActivity.getResources().getString( + R.string.call_count_one)); + vh.previousCallStats.setVisibility(View.GONE); + } + return; + } + if (mAddressErrorType != NO_ERROR) { // If there was an address error, clear the number of calls to make. vh.numCalls.setText(""); @@ -527,16 +544,20 @@ public EmptySearchViewHolder(View itemView) { /** * Sorts a list of issues to prioritize those with meta values (state abbreviations) at the top, - * then sorts the remaining issues. Both groups maintain their internal sort order. + * then sorts the remaining issues. Both groups maintain their internal sort order. Placeholder + * issues are always put at the very top. */ @VisibleForTesting ArrayList sortIssuesWithMetaPriority(List issues) { + ArrayList placeholders = new ArrayList<>(); ArrayList withMeta = new ArrayList<>(); ArrayList withoutMeta = new ArrayList<>(); // Separate issues with and without meta values for (Issue issue : issues) { - if (!TextUtils.isEmpty(issue.meta)) { + if (issue.isPlaceholder) { + placeholders.add(issue); + } else if (!TextUtils.isEmpty(issue.meta)) { withMeta.add(issue); } else { withoutMeta.add(issue); @@ -544,11 +565,13 @@ ArrayList sortIssuesWithMetaPriority(List issues) { } // Sort each group independently by sort field (maintaining consistent order) + Collections.sort(placeholders, (a, b) -> Integer.compare(a.sort, b.sort)); Collections.sort(withMeta, (a, b) -> Integer.compare(a.sort, b.sort)); Collections.sort(withoutMeta, (a, b) -> Integer.compare(a.sort, b.sort)); // Combine: meta issues first, then regular issues ArrayList result = new ArrayList<>(); + result.addAll(placeholders); result.addAll(withMeta); result.addAll(withoutMeta); diff --git a/5calls/app/src/main/java/org/a5calls/android/a5calls/controller/IssueActivity.java b/5calls/app/src/main/java/org/a5calls/android/a5calls/controller/IssueActivity.java index 633b119e..82031e90 100644 --- a/5calls/app/src/main/java/org/a5calls/android/a5calls/controller/IssueActivity.java +++ b/5calls/app/src/main/java/org/a5calls/android/a5calls/controller/IssueActivity.java @@ -79,12 +79,14 @@ public class IssueActivity extends AppCompatActivity implements FiveCallsApi.Scr public static final int RESULT_OK = 1; public static final int RESULT_SERVER_ERROR = 2; + public static final int RESULT_DEMO_CALLED = 3; private static final String DONATE_URL = "https://secure.actblue.com/donate/5calls-donate?refcode=android&refcode2="; private static final int MIN_CALLS_TO_SHOW_CALL_STATS = 10; private boolean mShowServerError = false; + private boolean mShowPlaceholderCalled = false; private Issue mIssue; private String mAddress; @@ -115,6 +117,9 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { if (result.getResultCode() == RESULT_SERVER_ERROR) { mShowServerError = true; } + if (result.getResultCode() == RESULT_DEMO_CALLED) { + mShowPlaceholderCalled = true; + } }); FiveCallsApi api = AppSingleton.getInstance(this).getJsonController(); @@ -350,6 +355,10 @@ protected void onResume() { binding.noContactAreas.setVisibility(View.VISIBLE); return; } + if (mShowPlaceholderCalled) { + binding.placeholderDone.getRoot().setVisibility(View.VISIBLE); + AccountManager.Instance.setShowPlaceholderIssue(getApplicationContext(), false); + } showContactsUi(); } @@ -583,7 +592,7 @@ private void populateRepView(View repView, Contact contact, final int index, } else { contactReason.setVisibility(View.GONE); } - if (!contact.isPlaceholder) { + if (!contact.isPlaceholder || contact.area.equals(Contact.AREA_DEMO)) { if (!TextUtils.isEmpty(contact.photoURL)) { Glide.with(getApplicationContext()) .load(contact.photoURL) @@ -593,7 +602,7 @@ private void populateRepView(View repView, Contact contact, final int index, .into(repImage); } // Show a bit about whether they've been contacted yet today. - if (hasCalledToday) { + if (hasCalledToday || (mIssue.isPlaceholder && mShowPlaceholderCalled)) { contactChecked.setImageLevel(1); contactChecked.setContentDescription(getResources().getString( R.string.contact_done_img_description)); @@ -676,6 +685,9 @@ private void showIssueDetails() { @VisibleForTesting static String getIssueDetailsMessage(Context context, Issue issue) { StringBuilder result = new StringBuilder(); + if (issue.isPlaceholder) { + return context.getResources().getString(R.string.demo_issue_details_message); + } if (issue.categories.length > 0) { if (issue.categories.length == 1) { result.append(context.getResources().getString(R.string.issue_category_one)); diff --git a/5calls/app/src/main/java/org/a5calls/android/a5calls/controller/MainActivity.java b/5calls/app/src/main/java/org/a5calls/android/a5calls/controller/MainActivity.java index e5393023..3b807f39 100644 --- a/5calls/app/src/main/java/org/a5calls/android/a5calls/controller/MainActivity.java +++ b/5calls/app/src/main/java/org/a5calls/android/a5calls/controller/MainActivity.java @@ -73,6 +73,8 @@ public class MainActivity extends AppCompatActivity implements IssuesAdapter.Cal private static final String KEY_SHOW_LOW_ACCURACY_WARNING = "showLowAccuracyWarning"; private static final String DEEP_LINK_HOST = "5calls.org"; private static final String DEEP_LINK_PATH_ISSUE = "issue"; + private static final String DEMO_ISSUE_PERMALINK = "/issue/demoIssue"; + private static final int MAX_CALLS_FOR_DEMO = 1; private final AccountManager accountManager = AccountManager.Instance; private String mPendingDeepLinkPath = null; @@ -93,6 +95,7 @@ public class MainActivity extends AppCompatActivity implements IssuesAdapter.Cal private boolean mShowLowAccuracyWarning = true; private boolean mDonateIsOn = false; private FirebaseAuth mAuth = null; + private int mCallCount = 0; private ActivityMainBinding binding; @@ -461,6 +464,8 @@ public void onJsonError() { @Override public void onIssuesReceived(List issues) { populateFilterAdapterIfNeeded(issues); + + maybeAddPlaceholderIssue(issues); mIssuesAdapter.setAllIssues(issues, IssuesAdapter.NO_ERROR); mIssuesAdapter.setFilterAndSearch(mFilterText, mSearchText); binding.swipeContainer.setRefreshing(false); @@ -653,12 +658,12 @@ public void onNothingSelected(AdapterView adapterView) { } private void loadStats() { - int callCount = AppSingleton.getInstance(getApplicationContext()) + mCallCount = AppSingleton.getInstance(getApplicationContext()) .getDatabaseHelper().getCallsCount(); - if (callCount > 1) { + if (mCallCount > 1) { // Don't bother if it is less than 1. binding.actionBarSubtitle.setText(String.format( - getResources().getString(R.string.your_call_count_summary), callCount)); + getResources().getString(R.string.your_call_count_summary), mCallCount)); } } @@ -849,4 +854,28 @@ private void maybeHandlePendingDeepLink() { showSnackbar(R.string.issue_not_found, Snackbar.LENGTH_LONG); } } + + private void maybeAddPlaceholderIssue(List issues) { + // Option to force show the placeholder call in settings. + boolean forceShowPlaceholder = AccountManager.Instance.showPlaceholderIssue( + getApplicationContext()); + // If they've called more than N times, don't bother with the placeholder any more. + boolean showPlaceholderIfEarly = mCallCount <= MAX_CALLS_FOR_DEMO && + !accountManager.getPlaceholderIssueCalled(getApplicationContext()); + if (forceShowPlaceholder || showPlaceholderIfEarly) { + Contact demoContact = Contact.createPlaceholder("0", + getResources().getString(R.string.demo_rep_name), + getResources().getString(R.string.demo_rep_reason), + Contact.AREA_DEMO, + getResources().getString(R.string.demo_rep_phone)); + Issue demoIssue = Issue.createPlaceholder("0", + getResources().getString(R.string.demo_issue_name), + DEMO_ISSUE_PERMALINK, + getResources().getString(R.string.demo_issue_reason), + getResources().getString(R.string.demo_issue_script), true, 0, + Collections.singletonList(demoContact), + Collections.emptyList(), Collections.emptyList()); + issues.add(demoIssue); + } + } } diff --git a/5calls/app/src/main/java/org/a5calls/android/a5calls/controller/RepCallActivity.java b/5calls/app/src/main/java/org/a5calls/android/a5calls/controller/RepCallActivity.java index 31836b34..4069ff52 100644 --- a/5calls/app/src/main/java/org/a5calls/android/a5calls/controller/RepCallActivity.java +++ b/5calls/app/src/main/java/org/a5calls/android/a5calls/controller/RepCallActivity.java @@ -5,6 +5,7 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.graphics.Paint; import android.os.Bundle; import android.text.TextUtils; import android.text.method.LinkMovementMethod; @@ -154,8 +155,13 @@ public void onCallReported() { outcomeAdapter = new OutcomeAdapter(issueOutcomes, new OutcomeAdapter.Callback() { @Override public void onOutcomeClicked(Outcome outcome) { - reportEvent(outcome); - reportCall(outcome, address); + if (!mIssue.isPlaceholder) { + reportEvent(outcome); + reportCall(outcome, address); + } else { + AccountManager.Instance.setPlaceholderIssueCalled(getApplicationContext(), true); + returnToIssueWithDemoCalled(); + } } }); @@ -225,7 +231,7 @@ private void setupContactUi(int index, boolean expandLocalSection) { .into(binding.repImage); } - linkPhoneNumber(binding.phoneNumber, contact.phone); + linkPhoneNumber(binding.phoneNumber, contact.phone, contact.isPlaceholder); if (expandLocalSection) { binding.localOfficeButton.setVisibility(View.INVISIBLE); @@ -337,7 +343,7 @@ private void expandLocalOfficeSection(Contact contact) { TextView numberView = (TextView) localOfficeInfo.findViewById( R.id.field_office_number); numberView.setText(contact.field_offices[i].phone); - linkPhoneNumber(numberView, contact.field_offices[i].phone); + linkPhoneNumber(numberView, contact.field_offices[i].phone, contact.isPlaceholder); if (!TextUtils.isEmpty(contact.field_offices[i].city)) { ((TextView) localOfficeInfo.findViewById(R.id.field_office_city)).setText( "- " + contact.field_offices[i].city); @@ -381,6 +387,19 @@ private void returnToIssueWithServerError() { finish(); } + private void returnToIssueWithDemoCalled() { + if (isFinishing()) { + return; + } + Intent upIntent = NavUtils.getParentActivityIntent(this); + if (upIntent == null) { + return; + } + upIntent.putExtra(IssueActivity.KEY_ISSUE, mIssue); + setResult(IssueActivity.RESULT_DEMO_CALLED, upIntent); + finish(); + } + private int getSpanCount(Activity activity) { DisplayMetrics displayMetrics = new DisplayMetrics(); activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); @@ -390,11 +409,26 @@ private int getSpanCount(Activity activity) { return (int) (displayMetrics.widthPixels / minButtonWidth); } - private static void linkPhoneNumber(TextView textView, String phoneNumber) { + private void linkPhoneNumber(TextView textView, String phoneNumber, + boolean isPlaceholder) { textView.setText(phoneNumber); - Linkify.addLinks(textView, Patterns.PHONE, "tel:", - Linkify.sPhoneNumberMatchFilter, - Linkify.sPhoneNumberTransformFilter); + if (!isPlaceholder) { + Linkify.addLinks(textView, Patterns.PHONE, "tel:", + Linkify.sPhoneNumberMatchFilter, + Linkify.sPhoneNumberTransformFilter); + } else { + textView.setPaintFlags(textView.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); + textView.setOnClickListener(v -> { + new AlertDialog.Builder(RepCallActivity.this) + .setTitle(R.string.demo_phone_click_dialog_title) + .setMessage(R.string.demo_phone_click_dialog_description) + .setPositiveButton(android.R.string.ok, + (dialog, which) -> { + + }) + .show(); + }); + } } private void updateScriptDisplay() { diff --git a/5calls/app/src/main/java/org/a5calls/android/a5calls/controller/SettingsActivity.java b/5calls/app/src/main/java/org/a5calls/android/a5calls/controller/SettingsActivity.java index 6ff16ada..b4c75664 100644 --- a/5calls/app/src/main/java/org/a5calls/android/a5calls/controller/SettingsActivity.java +++ b/5calls/app/src/main/java/org/a5calls/android/a5calls/controller/SettingsActivity.java @@ -218,6 +218,10 @@ public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable S ListPreference notificationPref = (ListPreference) findPreference(AccountManager.KEY_NOTIFICATIONS); notificationPref.setValue(notificationSetting); + + boolean showPlaceholderIssue = accountManager.showPlaceholderIssue(getActivity()); + ((SwitchPreference) findPreference(AccountManager.KEY_SHOW_PLACEHOLDER_CALLED)) + .setChecked(showPlaceholderIssue); } @Override @@ -276,6 +280,9 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin } else if (TextUtils.equals(key, "prefsKeyScriptTextSize")) { String value = sharedPreferences.getString(AccountManager.KEY_SCRIPT_TEXT_SIZE_SP, getString(R.string.script_text_size_normal_sp)); AccountManager.Instance.setScriptTextSize(getActivity(), Float.parseFloat(value)); + } else if (TextUtils.equals(key, AccountManager.KEY_SHOW_PLACEHOLDER_CALLED)) { + boolean result = sharedPreferences.getBoolean(key, false); + AccountManager.Instance.setShowPlaceholderIssue(getActivity(), result); } } diff --git a/5calls/app/src/main/java/org/a5calls/android/a5calls/model/AccountManager.java b/5calls/app/src/main/java/org/a5calls/android/a5calls/model/AccountManager.java index 407af9b6..da6683b8 100644 --- a/5calls/app/src/main/java/org/a5calls/android/a5calls/model/AccountManager.java +++ b/5calls/app/src/main/java/org/a5calls/android/a5calls/model/AccountManager.java @@ -42,6 +42,8 @@ public enum AccountManager { public static final String KEY_SCRIPT_TEXT_SIZE_SP = "prefsKeyScriptTextSize"; private static final String KEY_USER_STATE = "prefsKeyUserState"; private static final String KEY_USER_DISTRICT = "prefsKeyUserDistrict"; + private static final String KEY_PLACEHOLDER_CALLED = "prefsKeyPlaceholderCalled"; + public static final String KEY_SHOW_PLACEHOLDER_CALLED = "prefsKeyShowPlaceholderIssue"; // Default to 11 am. public static final int DEFAULT_REMINDER_MINUTES = 60 * 11; @@ -231,6 +233,22 @@ public void setScriptTextSize(Context context, float value) { getSharedPrefs(context).edit().putFloat(KEY_SCRIPT_TEXT_SIZE_SP, value).apply(); } + public void setPlaceholderIssueCalled(Context context, boolean value) { + getSharedPrefs(context).edit().putBoolean(KEY_PLACEHOLDER_CALLED, value).apply(); + } + + public boolean getPlaceholderIssueCalled(Context context) { + return getSharedPrefs(context).getBoolean(KEY_PLACEHOLDER_CALLED, false); + } + + public void setShowPlaceholderIssue(Context context, boolean value) { + getSharedPrefs(context).edit().putBoolean(KEY_SHOW_PLACEHOLDER_CALLED, value).apply(); + } + + public boolean showPlaceholderIssue(Context context) { + return getSharedPrefs(context).getBoolean(KEY_SHOW_PLACEHOLDER_CALLED, false); + } + private SharedPreferences getSharedPrefs(Context context) { return context.getSharedPreferences(PREFS_FILE, Context.MODE_PRIVATE); } diff --git a/5calls/app/src/main/java/org/a5calls/android/a5calls/model/Contact.java b/5calls/app/src/main/java/org/a5calls/android/a5calls/model/Contact.java index cbd881ab..5f613bc7 100644 --- a/5calls/app/src/main/java/org/a5calls/android/a5calls/model/Contact.java +++ b/5calls/app/src/main/java/org/a5calls/android/a5calls/model/Contact.java @@ -20,6 +20,10 @@ public class Contact implements Parcelable { public static final String AREA_ATTORNEY_GENERAL = "AttorneyGeneral"; public static final String AREA_SECRETARY_OF_STATE = "SecretaryOfState"; + // Used to show the placeholder contact for the demonstration issue. + public static final String AREA_DEMO = "demo"; + + public String id; public String name; public String phone; @@ -49,16 +53,21 @@ protected Contact(Parcel in) { isPlaceholder = in.readInt() == 1; } - protected Contact(String id, String name, String reason, String area, boolean isPlaceholder) { + protected Contact(String id, String name, String reason, String phone, String area, boolean isPlaceholder) { this.id = id; this.name = name; this.reason = reason; + this.phone = phone; this.area = area; this.isPlaceholder = isPlaceholder; } public static Contact createPlaceholder(String id, String name, String reason, String area) { - return new Contact(id, name, reason, area, /* isPlaceholder= */ true); + return createPlaceholder(id, name, reason, area, /*phone=*/""); + } + + public static Contact createPlaceholder(String id, String name, String reason, String area, String phone) { + return new Contact(id, name, reason, phone, area, /* isPlaceholder= */ true); } public static final Creator CREATOR = new Creator() { diff --git a/5calls/app/src/main/java/org/a5calls/android/a5calls/model/Issue.java b/5calls/app/src/main/java/org/a5calls/android/a5calls/model/Issue.java index c0963d3c..950faf88 100644 --- a/5calls/app/src/main/java/org/a5calls/android/a5calls/model/Issue.java +++ b/5calls/app/src/main/java/org/a5calls/android/a5calls/model/Issue.java @@ -4,6 +4,7 @@ import android.os.Parcelable; import android.text.TextUtils; +import java.util.Collections; import org.a5calls.android.a5calls.util.StateMapping; import java.util.List; @@ -32,9 +33,34 @@ public class Issue implements Parcelable { public Category[] categories; public boolean isSplit; public IssueStats stats; + public boolean isPlaceholder = false; public List customizedScripts; + public static Issue createPlaceholder(String id, String name, String permalink, String reason, + String script, boolean active, int sort, List contacts, + List contactAreas, List outcomeModels) { + Issue issue = new Issue(); + issue.id = id; + issue.name = name; + issue.permalink = permalink; + issue.reason = reason; + issue.script = script; + issue.active = active; + issue.sort = sort; + issue.contacts = contacts; + issue.contactAreas = Collections.singletonList("demo"); + issue.outcomeModels = outcomeModels; + + issue.stats = new IssueStats(0); + issue.isPlaceholder = true; + return issue; + } + + private Issue() { + + } + protected Issue(Parcel in) { id = in.readString(); name = in.readString(); @@ -57,6 +83,7 @@ protected Issue(Parcel in) { categories = in.createTypedArray(Category.CREATOR); stats = IssueStats.CREATOR.createFromParcel(in); customizedScripts = in.createTypedArrayList(CustomizedContactScript.CREATOR); + isPlaceholder = in.readInt() != 0; } public static final Creator CREATOR = new Creator() { @@ -96,6 +123,7 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeTypedArray(categories, PARCELABLE_WRITE_RETURN_VALUE); stats.writeToParcel(dest, flags); dest.writeTypedList(customizedScripts); + dest.writeInt(isPlaceholder ? 1 : 0); } public String getScriptForContact(String contactId) { diff --git a/5calls/app/src/main/java/org/a5calls/android/a5calls/model/IssueStats.java b/5calls/app/src/main/java/org/a5calls/android/a5calls/model/IssueStats.java index 64605b24..8b6341d2 100644 --- a/5calls/app/src/main/java/org/a5calls/android/a5calls/model/IssueStats.java +++ b/5calls/app/src/main/java/org/a5calls/android/a5calls/model/IssueStats.java @@ -6,6 +6,10 @@ public class IssueStats implements Parcelable { public int calls; + public IssueStats(int calls) { + this.calls = calls; + } + protected IssueStats(Parcel in) { calls = in.readInt(); } diff --git a/5calls/app/src/main/res/layout/activity_issue.xml b/5calls/app/src/main/res/layout/activity_issue.xml index 08479d6e..b465d807 100644 --- a/5calls/app/src/main/res/layout/activity_issue.xml +++ b/5calls/app/src/main/res/layout/activity_issue.xml @@ -59,6 +59,11 @@ layout="@layout/issue_done_view" /> + +