diff --git a/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java b/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java index 91d01df8..939a0683 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java @@ -31,7 +31,6 @@ import android.os.Build; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v7.app.ActionBar; -import android.text.Html; import android.text.method.LinkMovementMethod; import android.util.Log; import android.view.*; @@ -40,7 +39,6 @@ import android.widget.TextView; import org.solovyev.android.Activities; import org.solovyev.android.Android; import org.solovyev.android.Threads; -import org.solovyev.android.calculator.about.CalculatorReleaseNotesFragment; import org.solovyev.android.calculator.plot.CalculatorPlotActivity; import org.solovyev.android.calculator.wizard.CalculatorWizards; import org.solovyev.android.fragments.FragmentUtils; @@ -49,7 +47,6 @@ import org.solovyev.android.wizard.Wizard; import org.solovyev.android.wizard.Wizards; import org.solovyev.common.Objects; import org.solovyev.common.history.HistoryAction; -import org.solovyev.common.text.Strings; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -58,7 +55,9 @@ import static android.os.Build.VERSION_CODES.GINGERBREAD_MR1; import static android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH; import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; import static org.solovyev.android.calculator.Preferences.Gui.preventScreenFromFading; +import static org.solovyev.android.calculator.about.CalculatorReleaseNotesFragment.hasReleaseNotes; import static org.solovyev.android.wizard.WizardUi.continueWizard; +import static org.solovyev.android.wizard.WizardUi.createLaunchIntent; import static org.solovyev.android.wizard.WizardUi.startWizard; public class CalculatorActivity extends BaseActivity implements SharedPreferences.OnSharedPreferenceChangeListener, CalculatorEventListener { @@ -164,15 +163,11 @@ public class CalculatorActivity extends BaseActivity implements SharedPreference } else { if (savedVersion < appVersion) { final boolean showReleaseNotes = Preferences.Gui.showReleaseNotes.getPreference(preferences); - if (showReleaseNotes) { - final String releaseNotes = CalculatorReleaseNotesFragment.getReleaseNotes(context, savedVersion + 1); - if (!Strings.isEmpty(releaseNotes)) { - final AlertDialog.Builder builder = new AlertDialog.Builder(context).setMessage(Html.fromHtml(releaseNotes)); - builder.setPositiveButton(android.R.string.ok, null); - builder.setTitle(R.string.c_release_notes); - builder.create().show(); - dialogShown = true; - } + if (showReleaseNotes && hasReleaseNotes(context, savedVersion + 1)) { + final Bundle bundle = new Bundle(); + bundle.putInt(CalculatorWizards.RELEASE_NOTES_VERSION, savedVersion); + context.startActivity(createLaunchIntent(wizards, CalculatorWizards.RELEASE_NOTES, context, bundle)); + dialogShown = true; } } } @@ -180,7 +175,7 @@ public class CalculatorActivity extends BaseActivity implements SharedPreference //Log.d(this.getClass().getName(), "Application was opened " + appOpenedCounter + " time!"); if (!dialogShown) { - if (appOpenedCounter != null && appOpenedCounter > 100) { + if (appOpenedCounter != null && appOpenedCounter > 30) { dialogShown = showSpecialWindow(preferences, Preferences.Gui.feedbackWindowShown, R.layout.feedback, R.id.feedbackText, context); } } diff --git a/android-app/src/main/java/org/solovyev/android/calculator/about/CalculatorReleaseNotesFragment.java b/android-app/src/main/java/org/solovyev/android/calculator/about/CalculatorReleaseNotesFragment.java index 1b5e8047..e97ff99f 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/about/CalculatorReleaseNotesFragment.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/about/CalculatorReleaseNotesFragment.java @@ -35,6 +35,8 @@ import org.solovyev.android.calculator.R; import org.solovyev.common.text.Strings; import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.List; import static org.solovyev.android.Android.getAppVersionCode; @@ -61,11 +63,11 @@ public class CalculatorReleaseNotesFragment extends CalculatorFragment { @Nonnull public static String getReleaseNotes(@Nonnull Context context) { - return getReleaseNotes(context, 0); + return getReleaseNotesString(context, 0); } @Nonnull - public static String getReleaseNotes(@Nonnull Context context, int minVersion) { + public static String getReleaseNotesString(@Nonnull Context context, int minVersion) { final StringBuilder result = new StringBuilder(); final String releaseNotesForTitle = context.getString(R.string.c_release_notes_for_title); @@ -78,7 +80,6 @@ public class CalculatorReleaseNotesFragment extends CalculatorFragment { final String versionName = getVersionName(textHelper, versionCode); String releaseNotesForVersion = textHelper.getText(makeReleaseNotesResourceId(versionCode)); if (!Strings.isEmpty(releaseNotesForVersion)) { - if (releaseNotesForVersion == null) throw new AssertionError(); if (!first) { result.append("

"); } else { @@ -94,7 +95,38 @@ public class CalculatorReleaseNotesFragment extends CalculatorFragment { } @Nonnull - private static String getVersionName(@Nonnull TextHelper textHelper, int versionCode) { + public static List getReleaseNotesVersions(@Nonnull Context context, int minVersion) { + final List releaseNotes = new ArrayList<>(); + + final int currentVersionCode = getAppVersionCode(context); + final TextHelper textHelper = new TextHelper(context.getResources(), CalculatorApplication.class.getPackage().getName()); + + for (int versionCode = currentVersionCode; versionCode >= minVersion; versionCode--) { + final String releaseNotesForVersion = textHelper.getText(makeReleaseNotesResourceId(versionCode)); + if (!Strings.isEmpty(releaseNotesForVersion)) { + releaseNotes.add(versionCode); + } + } + + return releaseNotes; + } + + public static boolean hasReleaseNotes(@Nonnull Context context, int minVersion) { + final int currentVersionCode = getAppVersionCode(context); + final TextHelper textHelper = new TextHelper(context.getResources(), CalculatorApplication.class.getPackage().getName()); + + for (int versionCode = currentVersionCode; versionCode >= minVersion; versionCode--) { + String releaseNotesForVersion = textHelper.getText(makeReleaseNotesResourceId(versionCode)); + if (!Strings.isEmpty(releaseNotesForVersion)) { + return true; + } + } + + return false; + } + + @Nonnull + public static String getVersionName(@Nonnull TextHelper textHelper, int versionCode) { final String versionName = textHelper.getText(makeVersionResourceId(versionCode)); if (versionName != null) { return versionName; @@ -103,7 +135,7 @@ public class CalculatorReleaseNotesFragment extends CalculatorFragment { } } - private static String makeReleaseNotesResourceId(int versionCode) { + public static String makeReleaseNotesResourceId(int versionCode) { return "c_release_notes_for_" + versionCode; } diff --git a/android-app/src/main/java/org/solovyev/android/calculator/about/TextHelper.java b/android-app/src/main/java/org/solovyev/android/calculator/about/TextHelper.java index 97d2bbcf..7569565a 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/about/TextHelper.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/about/TextHelper.java @@ -49,6 +49,9 @@ public class TextHelper { public String getText(@Nonnull String stringName) { final int stringId = this.resources.getIdentifier(stringName, "string", this.packageName); try { + if (stringId == 0) { + return null; + } return resources.getString(stringId); } catch (Resources.NotFoundException e) { return null; diff --git a/android-app/src/main/java/org/solovyev/android/calculator/release/ReleaseNoteFragment.java b/android-app/src/main/java/org/solovyev/android/calculator/release/ReleaseNoteFragment.java new file mode 100644 index 00000000..42aecdda --- /dev/null +++ b/android-app/src/main/java/org/solovyev/android/calculator/release/ReleaseNoteFragment.java @@ -0,0 +1,56 @@ +package org.solovyev.android.calculator.release; + +import android.os.Bundle; +import android.text.Html; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import com.google.common.base.Strings; +import org.solovyev.android.calculator.CalculatorApplication; +import org.solovyev.android.calculator.R; +import org.solovyev.android.calculator.about.CalculatorReleaseNotesFragment; +import org.solovyev.android.calculator.about.TextHelper; +import org.solovyev.android.calculator.wizard.WizardFragment; + +import javax.annotation.Nonnull; + +public class ReleaseNoteFragment extends WizardFragment { + @Nonnull + public static final String ARG_VERSION = "version"; + + private int version; + + @Override + protected int getViewResId() { + return R.layout.cpp_release_note_step; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + version = getArguments().getInt(ARG_VERSION, 0); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + final View view = super.onCreateView(inflater, container, savedInstanceState); + final TextView title = (TextView) view.findViewById(R.id.release_note_title); + final TextHelper textHelper = new TextHelper(getActivity().getResources(), CalculatorApplication.class.getPackage().getName()); + title.setText(getString(R.string.cpp_new_in_version, getReleaseNoteVersion(textHelper))); + final TextView message = (TextView) view.findViewById(R.id.release_note_message); + message.setText(Html.fromHtml(getReleaseNote(textHelper))); + return view; + } + + @Nonnull + private String getReleaseNoteVersion(@Nonnull TextHelper textHelper) { + return CalculatorReleaseNotesFragment.getVersionName(textHelper, version); + } + + @Nonnull + private String getReleaseNote(@Nonnull TextHelper textHelper) { + final String resourceId = CalculatorReleaseNotesFragment.makeReleaseNotesResourceId(version); + return Strings.nullToEmpty(textHelper.getText(resourceId)).replace("\n", "
"); + } +} diff --git a/android-app/src/main/java/org/solovyev/android/calculator/release/ReleaseNoteStep.java b/android-app/src/main/java/org/solovyev/android/calculator/release/ReleaseNoteStep.java new file mode 100644 index 00000000..3aa050e4 --- /dev/null +++ b/android-app/src/main/java/org/solovyev/android/calculator/release/ReleaseNoteStep.java @@ -0,0 +1,86 @@ +package org.solovyev.android.calculator.release; + +import android.os.Bundle; +import android.support.v4.app.Fragment; +import org.solovyev.android.wizard.WizardStep; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class ReleaseNoteStep implements WizardStep { + private final int version; + + public ReleaseNoteStep(int version) { + this.version = version; + } + + public ReleaseNoteStep(@Nonnull Bundle arguments) { + this(arguments.getInt(ReleaseNoteFragment.ARG_VERSION, 0)); + } + + @Nonnull + @Override + public String getFragmentTag() { + return getName(); + } + + @Nonnull + @Override + public Class getFragmentClass() { + return ReleaseNoteFragment.class; + } + + @Nullable + @Override + public Bundle getFragmentArgs() { + final Bundle bundle = new Bundle(); + bundle.putInt(ReleaseNoteFragment.ARG_VERSION, version); + return bundle; + } + + @Override + public int getTitleResId() { + return 0; + } + + @Override + public int getNextButtonTitleResId() { + return 0; + } + + @Override + public boolean onNext(@Nonnull Fragment fragment) { + return false; + } + + @Override + public boolean onPrev(@Nonnull Fragment fragment) { + return false; + } + + @Override + public boolean isVisible() { + return false; + } + + @Nonnull + @Override + public String getName() { + return "release-note-" + version; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final ReleaseNoteStep that = (ReleaseNoteStep) o; + return version == that.version; + + } + + @Override + public int hashCode() { + return version; + } +} diff --git a/android-app/src/main/java/org/solovyev/android/calculator/wizard/CalculatorWizards.java b/android-app/src/main/java/org/solovyev/android/calculator/wizard/CalculatorWizards.java index 2983ccc6..35880ab9 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/wizard/CalculatorWizards.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/wizard/CalculatorWizards.java @@ -2,6 +2,9 @@ package org.solovyev.android.calculator.wizard; import android.app.Activity; import android.content.Context; +import android.os.Bundle; +import org.solovyev.android.calculator.about.CalculatorReleaseNotesFragment; +import org.solovyev.android.calculator.release.ReleaseNoteStep; import org.solovyev.android.wizard.*; import javax.annotation.Nonnull; @@ -15,6 +18,8 @@ import static org.solovyev.android.calculator.wizard.CalculatorWizardStep.welcom public class CalculatorWizards implements Wizards { public static final String FIRST_TIME_WIZARD = "first-wizard"; + public static final String RELEASE_NOTES = "release-notes"; + public static final String RELEASE_NOTES_VERSION = "version"; public static final String DEFAULT_WIZARD_FLOW = "app-wizard"; @Nonnull @@ -32,20 +37,28 @@ public class CalculatorWizards implements Wizards { @Nonnull @Override - public Wizard getWizard(@Nullable String name) { + public Wizard getWizard(@Nullable String name, @Nullable Bundle arguments) { if (name == null) { - return getWizard(FIRST_TIME_WIZARD); + return getWizard(FIRST_TIME_WIZARD, arguments); } if (FIRST_TIME_WIZARD.equals(name)) { return newBaseWizard(FIRST_TIME_WIZARD, newFirstTimeWizardFlow()); } else if (DEFAULT_WIZARD_FLOW.equals(name)) { return newBaseWizard(DEFAULT_WIZARD_FLOW, newDefaultWizardFlow()); + } else if (RELEASE_NOTES.equals(name)) { + return newBaseWizard(RELEASE_NOTES, newReleaseNotesWizardFlow(context, arguments)); } else { throw new IllegalArgumentException("Wizard flow " + name + " is not supported"); } } + @Nonnull + @Override + public Wizard getWizard(@Nullable String name) throws IllegalArgumentException { + return getWizard(name, null); + } + @Nonnull private BaseWizard newBaseWizard(@Nonnull String name, @Nonnull WizardFlow flow) { return new BaseWizard(name, context, flow); @@ -62,6 +75,21 @@ public class CalculatorWizards implements Wizards { return new ListWizardFlow(wizardSteps); } + @Nonnull + static WizardFlow newReleaseNotesWizardFlow(@Nonnull Context context, @Nullable Bundle arguments) { + final List wizardSteps = new ArrayList(); + final int startVersion = arguments != null ? arguments.getInt(RELEASE_NOTES_VERSION, 0) : 0; + List versions = CalculatorReleaseNotesFragment.getReleaseNotesVersions(context, startVersion); + final int size = versions.size(); + if (size > 7) { + versions = versions.subList(0, 7); + } + for (Integer version : versions) { + wizardSteps.add(new ReleaseNoteStep(version)); + } + return new ListWizardFlow(wizardSteps); + } + @Nonnull static WizardFlow newFirstTimeWizardFlow() { final List wizardSteps = new ArrayList(); @@ -72,4 +100,5 @@ public class CalculatorWizards implements Wizards { } return new ListWizardFlow(wizardSteps); } + } diff --git a/android-app/src/main/java/org/solovyev/android/calculator/wizard/WizardActivity.java b/android-app/src/main/java/org/solovyev/android/calculator/wizard/WizardActivity.java index 1eea567f..5a3c9f1c 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/wizard/WizardActivity.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/wizard/WizardActivity.java @@ -102,7 +102,8 @@ public class WizardActivity extends BaseActivity implements WizardsAware { } public void finishWizardAbruptly() { - finishWizardAbruptly(false); + final boolean confirmed = wizardUi.getWizard().getName().equals(CalculatorWizards.RELEASE_NOTES); + finishWizardAbruptly(confirmed); } public void finishWizardAbruptly(boolean confirmed) { diff --git a/android-app/src/main/java/org/solovyev/android/calculator/wizard/WizardFragment.java b/android-app/src/main/java/org/solovyev/android/calculator/wizard/WizardFragment.java index 99841d0e..52063ac7 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/wizard/WizardFragment.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/wizard/WizardFragment.java @@ -9,6 +9,8 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import org.solovyev.android.calculator.R; +import org.solovyev.android.calculator.release.ReleaseNoteFragment; +import org.solovyev.android.calculator.release.ReleaseNoteStep; import org.solovyev.android.wizard.Wizard; import org.solovyev.android.wizard.WizardFlow; import org.solovyev.android.wizard.WizardStep; @@ -34,7 +36,11 @@ public abstract class WizardFragment extends Fragment implements View.OnClickLis } @Nonnull - private CalculatorWizardStep findStepByClassName() { + private WizardStep findStepByClassName() { + if (this instanceof ReleaseNoteFragment) { + return new ReleaseNoteStep(getArguments()); + } + for (CalculatorWizardStep step : CalculatorWizardStep.values()) { if (step.getFragmentClass().equals(getClass())) { return step; diff --git a/android-app/src/main/java/org/solovyev/android/wizard/WizardUi.java b/android-app/src/main/java/org/solovyev/android/wizard/WizardUi.java index 0702ccef..120fbe8c 100644 --- a/android-app/src/main/java/org/solovyev/android/wizard/WizardUi.java +++ b/android-app/src/main/java/org/solovyev/android/wizard/WizardUi.java @@ -12,6 +12,7 @@ import javax.annotation.Nullable; public class WizardUi { private static final String FLOW = "flow"; + private static final String ARGUMENTS = "arguments"; private static final String STEP = "step"; protected WizardStep step; @@ -44,7 +45,8 @@ public class WizardUi { stepName = savedInstanceState.getString(STEP); } - wizard = wizardsAware.getWizards().getWizard(wizardName); + final Bundle arguments = intent.getBundleExtra(ARGUMENTS); + wizard = wizardsAware.getWizards().getWizard(wizardName, arguments); if (stepName != null) { step = wizard.getFlow().getStepByName(stepName); @@ -131,10 +133,16 @@ public class WizardUi { } @Nonnull - private static Intent createLaunchIntent(@Nonnull Wizards wizards, @Nullable String name, @Nonnull Context context) { + public static Intent createLaunchIntent(@Nonnull Wizards wizards, @Nullable String name, @Nonnull Context context) { + return createLaunchIntent(wizards, name, context, null); + } + + @Nonnull + public static Intent createLaunchIntent(@Nonnull Wizards wizards, @Nullable String name, @Nonnull Context context, @Nullable Bundle arguments) { final Intent intent = new Intent(context, wizards.getActivityClassName()); intent.putExtra(FLOW, name); intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); + intent.putExtra(ARGUMENTS, arguments); return intent; } } diff --git a/android-app/src/main/java/org/solovyev/android/wizard/Wizards.java b/android-app/src/main/java/org/solovyev/android/wizard/Wizards.java index 23d6deb8..fe401242 100644 --- a/android-app/src/main/java/org/solovyev/android/wizard/Wizards.java +++ b/android-app/src/main/java/org/solovyev/android/wizard/Wizards.java @@ -1,6 +1,7 @@ package org.solovyev.android.wizard; import android.app.Activity; +import android.os.Bundle; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -10,6 +11,9 @@ public interface Wizards { @Nonnull Class getActivityClassName(); + @Nonnull + public Wizard getWizard(@Nullable String name, @Nullable Bundle arguments) throws IllegalArgumentException; + @Nonnull public Wizard getWizard(@Nullable String name) throws IllegalArgumentException; } diff --git a/android-app/src/main/res/layout/cpp_release_note_step.xml b/android-app/src/main/res/layout/cpp_release_note_step.xml new file mode 100644 index 00000000..504b0ee6 --- /dev/null +++ b/android-app/src/main/res/layout/cpp_release_note_step.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + diff --git a/android-app/src/main/res/values/strings.xml b/android-app/src/main/res/values/strings.xml index 895a93fa..85481516 100644 --- a/android-app/src/main/res/values/strings.xml +++ b/android-app/src/main/res/values/strings.xml @@ -15,4 +15,5 @@ The app is set up and ready to use. Skip Finish + New in %1$s version \ No newline at end of file