Locator methods removed

This commit is contained in:
serso 2016-02-01 21:43:48 +01:00
parent 570221d691
commit 9c5652def0
34 changed files with 106 additions and 2225 deletions

View File

@ -101,24 +101,6 @@
</intent-filter>
</activity>
<activity
android:name=".plot.CalculatorPlotActivity"
android:hardwareAccelerated="false"
android:label="@string/c_plot_graph"
android:theme="@style/Cpp.Theme.Material" />
<activity
android:name=".plot.CalculatorPlotFunctionsActivity"
android:label="@string/cpp_plot_functions"
android:theme="@style/Cpp.Theme.Material.Dialog" />
<activity
android:name=".plot.CalculatorPlotFunctionSettingsActivity"
android:label="@string/cpp_plot_function_settings"
android:theme="@style/Cpp.Theme.Material.Dialog" />
<activity
android:name=".plot.CalculatorPlotRangeActivity"
android:label="@string/cpp_plot_range"
android:theme="@style/Cpp.Theme.Material.Dialog" />
<activity
android:name=".preferences.PurchaseDialogActivity"
android:label="@string/cpp_purchase_title"

View File

@ -26,9 +26,7 @@ import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
@ -36,39 +34,28 @@ import jscl.math.Generic;
import jscl.math.function.Constant;
import org.solovyev.android.Activities;
import org.solovyev.android.calculator.about.CalculatorAboutActivity;
import org.solovyev.android.calculator.errors.FixableError;
import org.solovyev.android.calculator.errors.FixableErrorsActivity;
import org.solovyev.android.calculator.functions.CppFunction;
import org.solovyev.android.calculator.functions.EditFunctionFragment;
import org.solovyev.android.calculator.functions.FunctionsActivity;
import org.solovyev.android.calculator.history.CalculatorHistoryActivity;
import org.solovyev.android.calculator.matrix.CalculatorMatrixActivity;
import org.solovyev.android.calculator.operators.OperatorsActivity;
import org.solovyev.android.calculator.plot.CalculatorPlotActivity;
import org.solovyev.android.calculator.plot.CalculatorPlotter;
import org.solovyev.android.calculator.preferences.PreferencesActivity;
import org.solovyev.android.calculator.variables.CppVariable;
import org.solovyev.android.calculator.variables.EditVariableFragment;
import org.solovyev.android.calculator.variables.VariablesActivity;
import org.solovyev.android.calculator.variables.VariablesFragment;
import org.solovyev.common.msg.Message;
import org.solovyev.common.msg.MessageType;
import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* User: serso
* Date: 11/2/11
* Time: 2:18 PM
*/
public final class CalculatorActivityLauncher implements CalculatorEventListener {
public final class ActivityLauncher implements CalculatorEventListener {
public CalculatorActivityLauncher() {
public ActivityLauncher() {
}
public static void showHistory(@Nonnull final Context context) {
@ -131,13 +118,6 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener
context.startActivity(intent);
}
public static void plotGraph(@Nonnull final Context context) {
final Intent intent = new Intent();
intent.setClass(context, CalculatorPlotActivity.class);
Activities.addIntentFlags(intent, false, context);
context.startActivity(intent);
}
public static void tryCreateVar(@Nonnull final Context context) {
final Display display = App.getDisplay();
final DisplayState state = display.getState();
@ -182,8 +162,8 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener
}
@Nonnull
private static CalculatorNotifier getNotifier() {
return Locator.getInstance().getNotifier();
private static Notifier getNotifier() {
return ((CalculatorApplication) App.getApplication()).notifier;
}
public static void tryPlot() {
@ -259,7 +239,7 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener
App.getUiThreadExecutor().execute(new Runnable() {
@Override
public void run() {
CalculatorActivityLauncher.tryCreateVar(context);
ActivityLauncher.tryCreateVar(context);
}
});
break;
@ -267,7 +247,7 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener
App.getUiThreadExecutor().execute(new Runnable() {
@Override
public void run() {
CalculatorActivityLauncher.tryCreateFunction(context);
ActivityLauncher.tryCreateFunction(context);
}
});
break;

View File

@ -62,12 +62,6 @@ public class AppModule {
return PreferenceManager.getDefaultSharedPreferences(application);
}
@Provides
@Singleton
Calculator provideCalculator(SharedPreferences preferences, Bus bus, @Named(THREAD_UI) Executor executor) {
return new Calculator(preferences, bus, executor);
}
@Provides
@Singleton
@Named(THREAD_INIT)

View File

@ -117,12 +117,14 @@ public abstract class BaseUi implements SharedPreferences.OnSharedPreferenceChan
@Inject
SharedPreferences preferences;
@Inject
Editor editor;
@Inject
History history;
@Inject
Keyboard keyboard;
@Inject
PreferredPreferences preferredPreferences;
protected void onCreate(@Nonnull Activity activity) {
((CalculatorApplication) activity.getApplication()).getComponent().inject(this);
@ -208,7 +210,7 @@ public abstract class BaseUi implements SharedPreferences.OnSharedPreferenceChan
angleUnitsButton = getButton(views, R.id.cpp_button_6);
if (angleUnitsButton != null) {
angleUnitsButton.setOnDragListener(newDragListener(new CalculatorButtons.AngleUnitsChanger(activity), activity));
angleUnitsButton.setOnDragListener(newDragListener(new CalculatorButtons.AngleUnitsChanger(activity, keyboard, preferredPreferences), activity));
}
final View eraseButton = getButton(views, R.id.cpp_button_erase);
@ -218,7 +220,7 @@ public abstract class BaseUi implements SharedPreferences.OnSharedPreferenceChan
clearButton = getButton(views, R.id.cpp_button_clear);
if (clearButton != null) {
clearButton.setOnDragListener(newDragListener(new CalculatorButtons.NumeralBasesChanger(activity), activity));
clearButton.setOnDragListener(newDragListener(new CalculatorButtons.NumeralBasesChanger(activity, preferredPreferences), activity));
}
final DragButton varsButton = getButton(views, R.id.cpp_button_vars);
@ -233,7 +235,7 @@ public abstract class BaseUi implements SharedPreferences.OnSharedPreferenceChan
final DragButton roundBracketsButton = getButton(views, R.id.cpp_button_round_brackets);
if (roundBracketsButton != null) {
roundBracketsButton.setOnDragListener(newDragListener(new CalculatorButtons.RoundBracketsDragProcessor(), activity));
roundBracketsButton.setOnDragListener(newDragListener(new CalculatorButtons.RoundBracketsDragProcessor(keyboard), activity));
}
if (layout == simple || layout == simple_mobile) {
@ -261,11 +263,11 @@ public abstract class BaseUi implements SharedPreferences.OnSharedPreferenceChan
CalculatorButtons.initMultiplicationButton(root);
NumeralBaseButtons.toggleNumericDigits(activity, preferences);
new ButtonOnClickListener().attachToViews(views);
new ButtonOnClickListener(keyboard).attachToViews(views);
}
private void setOnDragListeners(@Nonnull ViewsCache views, @Nonnull Context context) {
final DragListener dragListener = newDragListener(new DigitButtonDragProcessor(getKeyboard()), context);
final DragListener dragListener = newDragListener(new DigitButtonDragProcessor(keyboard), context);
final List<Integer> viewIds = getViewIds();
for (Integer viewId : viewIds) {
@ -291,16 +293,6 @@ public abstract class BaseUi implements SharedPreferences.OnSharedPreferenceChan
}
}
@Nonnull
private Calculator getCalculator() {
return Locator.getInstance().getCalculator();
}
@Nonnull
private Keyboard getKeyboard() {
return Locator.getInstance().getKeyboard();
}
@Nullable
private <V extends View> V getButton(@Nonnull ViewsCache views, int buttonId) {
//noinspection unchecked

View File

@ -11,6 +11,13 @@ import javax.annotation.Nonnull;
final class ButtonOnClickListener implements View.OnClickListener {
@Nonnull
private final Keyboard keyboard;
ButtonOnClickListener(@Nonnull Keyboard keyboard) {
this.keyboard = keyboard;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
@ -72,7 +79,7 @@ final class ButtonOnClickListener implements View.OnClickListener {
}
private void onClick(@Nonnull View v, @Nonnull String s) {
if (Locator.getInstance().getKeyboard().buttonPressed(s)) {
if (keyboard.buttonPressed(s)) {
v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
}
}

View File

@ -50,12 +50,16 @@ import org.solovyev.common.units.Conversions;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
@Singleton
public class Calculator implements CalculatorEventListener, SharedPreferences.OnSharedPreferenceChangeListener {
// one minute
@ -82,7 +86,11 @@ public class Calculator implements CalculatorEventListener, SharedPreferences.On
private volatile long lastPreferenceCheck = 0L;
public Calculator(@Nonnull SharedPreferences preferences, @Nonnull Bus bus, @Nonnull Executor eventExecutor) {
@Inject
PreferredPreferences preferredPreferences;
@Inject
public Calculator(@Nonnull SharedPreferences preferences, @Nonnull Bus bus, @Named(AppModule.THREAD_UI) @Nonnull Executor eventExecutor) {
this.preferences = preferences;
this.eventExecutor = eventExecutor;
bus.register(this);
@ -237,7 +245,6 @@ public class Calculator implements CalculatorEventListener, SharedPreferences.On
result.toString();
if (messageRegistry.hasMessage()) {
final ErrorReporter errorReporter = Locator.getInstance().getErrorReporter();
try {
final List<Message> messages = new ArrayList<Message>();
while (messageRegistry.hasMessage()) {
@ -281,7 +288,7 @@ public class Calculator implements CalculatorEventListener, SharedPreferences.On
if (currentTime - lastPreferenceCheck > PREFERENCE_CHECK_INTERVAL) {
lastPreferenceCheck = currentTime;
Locator.getInstance().getPreferenceService().check(false);
preferredPreferences.check(false);
}
}
@ -481,43 +488,43 @@ public class Calculator implements CalculatorEventListener, SharedPreferences.On
FixableErrorsActivity.show(App.getApplication(), (List<Message>) data);
break;
case show_history:
CalculatorActivityLauncher.showHistory(App.getApplication());
ActivityLauncher.showHistory(App.getApplication());
break;
case show_history_detached:
CalculatorActivityLauncher.showHistory(App.getApplication(), true);
ActivityLauncher.showHistory(App.getApplication(), true);
break;
case show_functions:
CalculatorActivityLauncher.showFunctions(App.getApplication());
ActivityLauncher.showFunctions(App.getApplication());
break;
case show_functions_detached:
CalculatorActivityLauncher.showFunctions(App.getApplication(), true);
ActivityLauncher.showFunctions(App.getApplication(), true);
break;
case show_operators:
CalculatorActivityLauncher.showOperators(App.getApplication());
ActivityLauncher.showOperators(App.getApplication());
break;
case show_operators_detached:
CalculatorActivityLauncher.showOperators(App.getApplication(), true);
ActivityLauncher.showOperators(App.getApplication(), true);
break;
case show_vars:
CalculatorActivityLauncher.showVars(App.getApplication());
ActivityLauncher.showVars(App.getApplication());
break;
case show_vars_detached:
CalculatorActivityLauncher.showVars(App.getApplication(), true);
ActivityLauncher.showVars(App.getApplication(), true);
break;
case show_settings:
CalculatorActivityLauncher.showSettings(App.getApplication());
ActivityLauncher.showSettings(App.getApplication());
break;
case show_settings_detached:
CalculatorActivityLauncher.showSettings(App.getApplication(), true);
ActivityLauncher.showSettings(App.getApplication(), true);
break;
case show_settings_widget:
CalculatorActivityLauncher.showWidgetSettings(App.getApplication(), true);
ActivityLauncher.showWidgetSettings(App.getApplication(), true);
break;
case show_like_dialog:
CalculatorActivityLauncher.likeButtonPressed(App.getApplication());
ActivityLauncher.likeButtonPressed(App.getApplication());
break;
case open_app:
CalculatorActivityLauncher.openApp(App.getApplication());
ActivityLauncher.openApp(App.getApplication());
break;
}
}

View File

@ -32,18 +32,11 @@ import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v7.app.ActionBar;
import android.text.method.LinkMovementMethod;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.Window;
import android.view.*;
import android.widget.TextView;
import org.solovyev.android.Activities;
import org.solovyev.android.Android;
import org.solovyev.android.Threads;
import org.solovyev.android.calculator.history.History;
import org.solovyev.android.calculator.plot.CalculatorPlotActivity;
import org.solovyev.android.calculator.wizard.CalculatorWizards;
import org.solovyev.android.fragments.FragmentUtils;
import org.solovyev.android.prefs.Preference;
@ -60,11 +53,9 @@ 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.release.ReleaseNotes.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;
import static org.solovyev.android.wizard.WizardUi.*;
public class CalculatorActivity extends BaseActivity implements SharedPreferences.OnSharedPreferenceChangeListener, CalculatorEventListener {
public class CalculatorActivity extends BaseActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
@Nonnull
public static final String TAG = CalculatorActivity.class.getSimpleName();
@ -169,7 +160,6 @@ public class CalculatorActivity extends BaseActivity implements SharedPreference
ui.addTab(this, CalculatorFragmentType.variables, null, R.id.main_second_pane);
ui.addTab(this, CalculatorFragmentType.functions, null, R.id.main_second_pane);
ui.addTab(this, CalculatorFragmentType.operators, null, R.id.main_second_pane);
ui.addTab(this, CalculatorPlotActivity.getPlotterFragmentType(), null, R.id.main_second_pane);
} else {
final ActionBar actionBar = getSupportActionBar();
if (Build.VERSION.SDK_INT <= GINGERBREAD_MR1 || (Build.VERSION.SDK_INT >= ICE_CREAM_SANDWICH && hasPermanentMenuKey())) {
@ -272,29 +262,4 @@ public class CalculatorActivity extends BaseActivity implements SharedPreference
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
}
@Override
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
switch (calculatorEventType) {
case plot_graph:
Threads.tryRunOnUiThread(this, new Runnable() {
@Override
public void run() {
if (isMultiPane()) {
final ActionBar.Tab selectedTab = getSupportActionBar().getSelectedTab();
if (selectedTab != null && CalculatorFragmentType.plotter.getFragmentTag().equals(selectedTab.getTag())) {
// do nothing - fragment shown and already registered for plot updates
} else {
// otherwise - open fragment
ui.selectTab(CalculatorActivity.this, CalculatorFragmentType.plotter);
}
} else {
// start new activity
CalculatorActivityLauncher.plotGraph(CalculatorActivity.this);
}
}
});
break;
}
}
}

View File

@ -94,6 +94,9 @@ public class CalculatorApplication extends android.app.Application implements Sh
@Inject
ErrorReporter errorReporter;
@Inject
Notifier notifier;
@Inject
PreferredPreferences preferredPreferences;
@ -124,14 +127,11 @@ public class CalculatorApplication extends android.app.Application implements Sh
Locator.getInstance().init(calculator,
engine,
new AndroidCalculatorNotifier(this),
errorReporter,
preferredPreferences,
keyboard,
new AndroidCalculatorPlotter(this, new CalculatorPlotterImpl(calculator))
);
listeners.add(new CalculatorActivityLauncher());
listeners.add(new ActivityLauncher());
for (CalculatorEventListener listener : listeners) {
calculator.addCalculatorEventListener(listener);
}
@ -189,7 +189,7 @@ public class CalculatorApplication extends android.app.Application implements Sh
if (Preferences.Onscreen.showAppIcon.getKey().equals(key)) {
boolean showAppIcon = Preferences.Onscreen.showAppIcon.getPreference(prefs);
Android.enableComponent(this, CalculatorOnscreenStartActivity.class, showAppIcon);
Locator.getInstance().getNotifier().showMessage(R.string.cpp_this_change_may_require_reboot, MessageType.info);
notifier.showMessage(R.string.cpp_this_change_may_require_reboot, MessageType.info);
}
}

View File

@ -103,20 +103,22 @@ public final class CalculatorButtons {
}
}
@Nonnull
private static Keyboard getKeyboard() {
return Locator.getInstance().getKeyboard();
}
static class RoundBracketsDragProcessor implements SimpleDragListener.DragProcessor {
@Nonnull
private final DigitButtonDragProcessor upDownProcessor = new DigitButtonDragProcessor(getKeyboard());
private final Keyboard keyboard;
@Nonnull
private final DigitButtonDragProcessor upDownProcessor;
RoundBracketsDragProcessor(@Nonnull Keyboard keyboard) {
this.keyboard = keyboard;
this.upDownProcessor = new DigitButtonDragProcessor(keyboard);
}
@Override
public boolean processDragEvent(@Nonnull DragDirection direction, @Nonnull DragButton button, @Nonnull PointF startPoint, @Nonnull MotionEvent motionEvent) {
if (direction == DragDirection.left) {
getKeyboard().roundBracketsButtonPressed();
keyboard.roundBracketsButtonPressed();
return true;
}
@ -154,10 +156,13 @@ public final class CalculatorButtons {
@Nonnull
private final Context context;
@Nonnull
private final PreferredPreferences preferredPreferences;
AngleUnitsChanger(@Nonnull Context context) {
AngleUnitsChanger(@Nonnull Context context, @Nonnull Keyboard keyboard, @Nonnull PreferredPreferences preferredPreferences) {
this.context = context;
this.processor = new DigitButtonDragProcessor(Locator.getInstance().getKeyboard());
this.preferredPreferences = preferredPreferences;
this.processor = new DigitButtonDragProcessor(keyboard);
}
@Override
@ -177,7 +182,7 @@ public final class CalculatorButtons {
final AngleUnit oldAngleUnits = Engine.Preferences.angleUnit.getPreference(preferences);
if (oldAngleUnits != angleUnits) {
Locator.getInstance().getPreferenceService().setAngleUnits(angleUnits);
preferredPreferences.setAngleUnits(angleUnits);
}
} catch (IllegalArgumentException e) {
Log.d(this.getClass().getName(), "Unsupported angle units: " + directionText);
@ -197,9 +202,12 @@ public final class CalculatorButtons {
@Nonnull
private final Context context;
@Nonnull
private final PreferredPreferences preferredPreferences;
NumeralBasesChanger(@Nonnull Context context) {
NumeralBasesChanger(@Nonnull Context context, @Nonnull PreferredPreferences preferredPreferences) {
this.context = context;
this.preferredPreferences = preferredPreferences;
}
@Override
@ -217,7 +225,7 @@ public final class CalculatorButtons {
final NumeralBase oldNumeralBase = Engine.Preferences.numeralBase.getPreference(preferences);
if (oldNumeralBase != numeralBase) {
Locator.getInstance().getPreferenceService().setNumeralBase(numeralBase);
preferredPreferences.setNumeralBase(numeralBase);
}
} catch (IllegalArgumentException e) {
Log.d(this.getClass().getName(), "Unsupported numeral base: " + directionText);

View File

@ -32,10 +32,6 @@ import org.solovyev.android.calculator.functions.FunctionsFragment;
import org.solovyev.android.calculator.operators.OperatorsFragment;
import org.solovyev.android.calculator.variables.VariablesFragment;
import org.solovyev.android.calculator.matrix.CalculatorMatrixEditFragment;
import org.solovyev.android.calculator.plot.CalculatorPlotFragment;
import org.solovyev.android.calculator.plot.CalculatorPlotFunctionSettingsActivity;
import org.solovyev.android.calculator.plot.CalculatorPlotFunctionsActivity;
import org.solovyev.android.calculator.plot.CalculatorPlotRangeActivity;
import org.solovyev.android.calculator.preferences.PurchaseDialogActivity;
import javax.annotation.Nonnull;
@ -55,10 +51,6 @@ public enum CalculatorFragmentType {
variables(VariablesFragment.class, R.layout.fragment_entities, R.string.c_vars),
functions(FunctionsFragment.class, R.layout.fragment_entities, R.string.c_functions),
operators(OperatorsFragment.class, R.layout.fragment_entities, R.string.c_operators),
plotter(CalculatorPlotFragment.class, R.layout.cpp_plotter_fragment, R.string.c_graph),
plotter_functions(CalculatorPlotFunctionsActivity.CalculatorPlotFunctionsFragment.class, R.layout.cpp_plot_functions_fragment, R.string.cpp_plot_functions),
plotter_function_settings(CalculatorPlotFunctionSettingsActivity.CalculatorPlotFunctionSettingsFragment.class, R.layout.cpp_plot_function_settings_fragment, R.string.cpp_plot_function_settings),
plotter_range(CalculatorPlotRangeActivity.CalculatorPlotRangeFragment.class, R.layout.cpp_plot_range_fragment, R.string.cpp_plot_range),
purchase_dialog(PurchaseDialogActivity.PurchaseDialogFragment.class, R.layout.cpp_purchase_dialog_fragment, R.string.cpp_purchase_title),

View File

@ -30,9 +30,6 @@ public interface CalculatorLocator {
void init(@Nonnull Calculator calculator,
@Nonnull Engine engine,
@Nonnull CalculatorNotifier notifier,
@Nonnull ErrorReporter errorReporter,
@Nonnull PreferredPreferences preferenceService,
@Nonnull Keyboard keyboard,
@Nonnull CalculatorPlotter plotter);
@ -45,15 +42,6 @@ public interface CalculatorLocator {
@Nonnull
Keyboard getKeyboard();
@Nonnull
CalculatorNotifier getNotifier();
@Nonnull
ErrorReporter getErrorReporter();
@Nonnull
CalculatorPlotter getPlotter();
@Nonnull
PreferredPreferences getPreferenceService();
}

View File

@ -42,14 +42,14 @@ enum CalculatorMenu implements LabeledMenuItem<MenuItem> {
settings(R.string.c_settings) {
@Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
CalculatorActivityLauncher.showSettings(context);
ActivityLauncher.showSettings(context);
}
},
history(R.string.c_history) {
@Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
CalculatorActivityLauncher.showHistory(context);
ActivityLauncher.showHistory(context);
}
},
@ -81,7 +81,7 @@ enum CalculatorMenu implements LabeledMenuItem<MenuItem> {
about(R.string.c_about) {
@Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
CalculatorActivityLauncher.showAbout(context);
ActivityLauncher.showAbout(context);
}
};

View File

@ -1,47 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator;
import org.solovyev.common.msg.Message;
import org.solovyev.common.msg.MessageType;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* User: serso
* Date: 9/22/12
* Time: 1:52 PM
*/
public interface CalculatorNotifier {
void showMessage(@Nonnull Message message);
void showMessage(@Nonnull Integer messageCode, @Nonnull MessageType messageType, @Nonnull List<Object> parameters);
void showMessage(@Nonnull Integer messageCode, @Nonnull MessageType messageType, @Nullable Object... parameters);
void showDebugMessage(@Nullable String tag, @Nonnull String message);
}

View File

@ -52,6 +52,8 @@ public class Display implements CalculatorEventListener, View.OnClickListener, V
Lazy<Keyboard> keyboard;
@Inject
Lazy<Clipboard> clipboard;
@Inject
Lazy<Notifier> notifier;
@Nullable
private DisplayView view;
@Nonnull
@ -71,7 +73,7 @@ public class Display implements CalculatorEventListener, View.OnClickListener, V
return;
}
clipboard.get().setText(state.text);
Locator.getInstance().getNotifier().showMessage(CalculatorMessage.newInfoMessage(CalculatorMessages.result_copied));
notifier.get().showMessage(CalculatorMessage.newInfoMessage(CalculatorMessages.result_copied));
}
public void clearView(@Nonnull DisplayView view) {

View File

@ -1,55 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator;
import org.solovyev.common.msg.Message;
import org.solovyev.common.msg.MessageType;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* User: serso
* Date: 9/22/12
* Time: 2:00 PM
*/
public class DummyCalculatorNotifier implements CalculatorNotifier {
@Override
public void showMessage(@Nonnull Message message) {
}
@Override
public void showMessage(@Nonnull Integer messageCode, @Nonnull MessageType messageType, @Nonnull List<Object> parameters) {
}
@Override
public void showMessage(@Nonnull Integer messageCode, @Nonnull MessageType messageType, @Nullable Object... parameters) {
}
@Override
public void showDebugMessage(@Nullable String tag, @Nonnull String message) {
}
}

View File

@ -37,7 +37,7 @@ public class EqualsDragProcessor implements SimpleDragListener.DragProcessor {
@Override
public boolean processDragEvent(@Nonnull DragDirection direction, @Nonnull DragButton button, @Nonnull PointF startPoint, @Nonnull MotionEvent motionEvent) {
if (direction == DragDirection.down) {
CalculatorActivityLauncher.tryPlot();
ActivityLauncher.tryPlot();
return true;
} else if (button instanceof DirectionDragButton) {
final String text = ((DirectionDragButton) button).getText(direction);

View File

@ -36,13 +36,6 @@ public class Locator implements CalculatorLocator {
private Calculator calculator;
@Nonnull
private Keyboard keyboard;
@Nonnull
private CalculatorNotifier calculatorNotifier = new DummyCalculatorNotifier();
@Nonnull
private ErrorReporter errorReporter = new SystemErrorReporter();
@Nonnull
private PreferredPreferences preferredPreferences;
@Nonnull
private CalculatorPlotter calculatorPlotter;
@ -57,17 +50,11 @@ public class Locator implements CalculatorLocator {
@Override
public void init(@Nonnull Calculator calculator,
@Nonnull Engine engine,
@Nonnull CalculatorNotifier notifier,
@Nonnull ErrorReporter errorReporter,
@Nonnull PreferredPreferences preferenceService,
@Nonnull Keyboard keyboard,
@Nonnull CalculatorPlotter plotter) {
this.calculator = calculator;
this.engine = engine;
this.calculatorNotifier = notifier;
this.errorReporter = errorReporter;
this.preferredPreferences = preferenceService;
this.calculatorPlotter = plotter;
this.keyboard = keyboard;
@ -91,31 +78,9 @@ public class Locator implements CalculatorLocator {
return keyboard;
}
public static void setKeyboard(@Nonnull Keyboard keyboard) {
instance.keyboard = keyboard;
}
@Override
@Nonnull
public CalculatorNotifier getNotifier() {
return calculatorNotifier;
}
@Override
@Nonnull
public ErrorReporter getErrorReporter() {
return errorReporter;
}
@Nonnull
@Override
public CalculatorPlotter getPlotter() {
return calculatorPlotter;
}
@Nonnull
@Override
public PreferredPreferences getPreferenceService() {
return this.preferredPreferences;
}
}

View File

@ -25,70 +25,45 @@ package org.solovyev.android.calculator;
import android.app.Application;
import android.os.Handler;
import android.widget.Toast;
import org.solovyev.android.Threads;
import org.solovyev.android.msg.AndroidMessage;
import org.solovyev.common.msg.Message;
import org.solovyev.common.msg.MessageType;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.List;
/**
* User: serso
* Date: 9/22/12
* Time: 2:00 PM
*/
public class AndroidCalculatorNotifier implements CalculatorNotifier {
@Singleton
public class Notifier {
@Inject
Application application;
@Inject
Handler handler;
@Nonnull
private final Application application;
@Nonnull
private final Handler uiHandler = new Handler();
private final boolean showDebugMessages;
public AndroidCalculatorNotifier(@Nonnull Application application) {
this(application, false);
@Inject
public Notifier() {
}
public AndroidCalculatorNotifier(@Nonnull Application application, boolean showDebugMessages) {
if (!Threads.isUiThread()) throw new AssertionError();
this.application = application;
this.showDebugMessages = showDebugMessages;
}
@Override
public void showMessage(@Nonnull Message message) {
showMessageInUiThread(message.getLocalizedMessage());
}
@Override
public void showMessage(@Nonnull Integer messageCode, @Nonnull MessageType messageType, @Nonnull List<Object> parameters) {
showMessage(new AndroidMessage(messageCode, messageType, application, parameters));
}
@Override
public void showMessage(@Nonnull Integer messageCode, @Nonnull MessageType messageType, @Nullable Object... parameters) {
showMessage(new AndroidMessage(messageCode, messageType, application, parameters));
}
@Override
public void showDebugMessage(@Nullable final String tag, @Nonnull final String message) {
if (showDebugMessages) {
showMessageInUiThread(tag == null ? message : tag + ": " + message);
}
}
private void showMessageInUiThread(@Nonnull final String message) {
if (Threads.isUiThread()) {
Toast.makeText(application, message, Toast.LENGTH_SHORT).show();
} else {
uiHandler.post(new Runnable() {
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(application, message, Toast.LENGTH_SHORT).show();
@ -96,5 +71,4 @@ public class AndroidCalculatorNotifier implements CalculatorNotifier {
});
}
}
}

View File

@ -50,6 +50,8 @@ public class PreferredPreferences {
Application application;
@Inject
SharedPreferences preferences;
@Inject
Notifier notifier;
@Inject
public PreferredPreferences() {
@ -103,7 +105,7 @@ public class PreferredPreferences {
public void setAngleUnits(@Nonnull AngleUnit angleUnit) {
Engine.Preferences.angleUnit.putPreference(preferences, angleUnit);
Locator.getInstance().getNotifier().showMessage(new AndroidMessage(R.string.c_angle_units_changed_to, MessageType.info, application, angleUnit.name()));
notifier.showMessage(new AndroidMessage(R.string.c_angle_units_changed_to, MessageType.info, application, angleUnit.name()));
}
public void setPreferredNumeralBase() {
@ -112,6 +114,6 @@ public class PreferredPreferences {
public void setNumeralBase(@Nonnull NumeralBase numeralBase) {
Engine.Preferences.numeralBase.putPreference(preferences, numeralBase);
Locator.getInstance().getNotifier().showMessage(new AndroidMessage(R.string.c_numeral_base_changed_to, MessageType.info, application, numeralBase.name()));
notifier.showMessage(new AndroidMessage(R.string.c_numeral_base_changed_to, MessageType.info, application, numeralBase.name()));
}
}

View File

@ -39,77 +39,31 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Locale;
/**
* User: serso
* Date: 11/21/12
* Time: 9:03 PM
*/
public class CalculatorOnscreenView {
/*
**********************************************************************
*
* CONSTANTS
*
**********************************************************************
*/
private static final String TAG = CalculatorOnscreenView.class.getSimpleName();
/*
**********************************************************************
*
* STATIC
*
**********************************************************************
*/
private static final Preference<CalculatorOnscreenViewState> viewStatePreference = new CalculatorOnscreenViewState.Preference("onscreen_view_state", CalculatorOnscreenViewState.createDefault());
/*
**********************************************************************
*
* FIELDS
*
**********************************************************************
*/
@Nonnull
private View root;
@Nonnull
private View content;
@Nonnull
private View header;
@Nonnull
private ImageView headerTitle;
private Drawable headerTitleDrawable;
@Nonnull
private EditorView editorView;
@Nonnull
private DisplayView displayView;
@Nonnull
private Context context;
@Nonnull
private CalculatorOnscreenViewState state = CalculatorOnscreenViewState.createDefault();
@Nullable
private OnscreenViewListener viewListener;
/*
**********************************************************************
*
* STATES
*
**********************************************************************
*/
private boolean minimized;
private boolean attached;
private boolean folded;

View File

@ -26,22 +26,15 @@ import android.content.SharedPreferences;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import org.solovyev.android.prefs.AbstractPreference;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* User: serso
* Date: 11/21/12
* Time: 10:55 PM
*/
public class CalculatorOnscreenViewState implements Parcelable {
private static final String TAG = CalculatorOnscreenViewState.class.getSimpleName();

View File

@ -1,440 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import org.solovyev.android.Android;
import org.solovyev.android.Threads;
import org.solovyev.android.calculator.*;
import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.preferences.PreferencesActivity;
import org.solovyev.android.menu.*;
import org.solovyev.common.JPredicate;
import org.solovyev.common.msg.MessageType;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import static org.solovyev.android.calculator.Engine.Preferences;
/**
* User: serso
* Date: 12/30/12
* Time: 3:09 PM
*/
public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment implements CalculatorEventListener, SharedPreferences.OnSharedPreferenceChangeListener {
/*
**********************************************************************
*
* CONSTANTS
*
**********************************************************************
*/
protected static final String TAG = "CalculatorPlotFragment";
/*
**********************************************************************
*
* FIELDS
*
**********************************************************************
*/
// thread which calculated data for graph view
@Nonnull
private final Executor plotExecutor = Executors.newSingleThreadExecutor();
@Nonnull
private final CalculatorEventHolder lastEventHolder = new CalculatorEventHolder(CalculatorUtils.createFirstEventDataId());
private int bgColor;
@Nonnull
private PlotData plotData = new PlotData(Collections.<PlotFunction>emptyList(), false, true, PlotBoundaries.newDefaultInstance());
@Nonnull
private ActivityMenu<Menu, MenuItem> fragmentMenu;
public AbstractCalculatorPlotFragment() {
super(new FragmentUi(R.layout.cpp_plot_fragment, R.string.c_graph, false));
}
public static void applyToPaint(@Nonnull PlotLineDef plotLineDef, @Nonnull Paint paint) {
paint.setColor(plotLineDef.getLineColor());
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(plotLineDef.getLineWidth());
final AndroidPlotLineStyle androidPlotLineStyle = AndroidPlotLineStyle.valueOf(plotLineDef.getLineStyle());
if (androidPlotLineStyle != null) {
androidPlotLineStyle.applyToPaint(paint);
}
}
@Override
public void onCreate(@Nullable Bundle in) {
super.onCreate(in);
if (isPaneFragment()) {
bgColor = getResources().getColor(App.getTheme().light ? R.color.cpp_pane_bg_light : R.color.cpp_pane_bg);
} else {
bgColor = getResources().getColor(App.getTheme().light ? R.color.cpp_main_bg_light : R.color.cpp_main_bg);
}
setHasOptionsMenu(true);
}
private void savePlotBoundaries() {
final PlotBoundaries plotBoundaries = getPlotBoundaries();
if (plotBoundaries != null) {
Locator.getInstance().getPlotter().savePlotBoundaries(plotBoundaries);
}
}
@Nullable
protected abstract PlotBoundaries getPlotBoundaries();
@Override
public void onResume() {
super.onResume();
PreferenceManager.getDefaultSharedPreferences(this.getActivity()).registerOnSharedPreferenceChangeListener(this);
plotData = Locator.getInstance().getPlotter().getPlotData();
updateChart(plotData, getActivity());
}
@Override
public void onPause() {
PreferenceManager.getDefaultSharedPreferences(this.getActivity()).unregisterOnSharedPreferenceChangeListener(this);
savePlotBoundaries();
super.onPause();
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (Preferences.angleUnit.getKey().equals(key)) {
updateChart(this.plotData, getActivity());
}
}
@Override
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable final Object data) {
switch (calculatorEventType) {
case plot_data_changed:
final CalculatorEventHolder.Result result = this.lastEventHolder.apply(calculatorEventData);
if (result.isNewAfter()) {
if (data == null) throw new AssertionError();
onNewPlotData((PlotData) data);
}
break;
}
}
private void onNewPlotData(@Nonnull final PlotData plotData) {
this.plotData = plotData;
updateChart(plotData, getActivity());
}
private void updateChart(@Nonnull final PlotData plotData, @Nullable final Activity activity) {
if (!(activity instanceof ActionBarActivity)) throw new AssertionError();
Threads.tryRunOnUiThread(activity, new Runnable() {
@Override
public void run() {
createChart(plotData);
final View view = getView();
if (view != null) {
createGraphicalView(view, plotData);
}
((ActionBarActivity) activity).supportInvalidateOptionsMenu();
}
});
}
protected abstract void onError();
protected abstract void createGraphicalView(@Nonnull View view, @Nonnull PlotData plotData);
/*
**********************************************************************
*
* GETTERS
*
**********************************************************************
*/
protected abstract void createChart(@Nonnull PlotData plotData);
public int getBgColor(boolean d3) {
// 3d plotter should always set a background color
// 2d plotter can leave with transparent background
return !d3 ? Color.TRANSPARENT : bgColor;
}
/*
**********************************************************************
*
* MENU
*
**********************************************************************
*/
@Nonnull
public Executor getPlotExecutor() {
return plotExecutor;
}
@Override
public void onCreateOptionsMenu(final Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
final List<IdentifiableMenuItem<MenuItem>> menuItems = new ArrayList<IdentifiableMenuItem<MenuItem>>();
menuItems.add(PlotMenu.preferences);
menuItems.add(PlotMenu.functions);
final IdentifiableMenuItem<MenuItem> plotRangeMenuItem = new IdentifiableMenuItem<MenuItem>() {
@Nonnull
@Override
public Integer getItemId() {
return R.id.menu_plot_range;
}
@Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
savePlotBoundaries();
context.startActivity(new Intent(context, CalculatorPlotRangeActivity.class));
}
};
menuItems.add(plotRangeMenuItem);
final IdentifiableMenuItem<MenuItem> plot3dMenuItem = new IdentifiableMenuItem<MenuItem>() {
@Nonnull
@Override
public Integer getItemId() {
return R.id.menu_plot_3d;
}
@Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
savePlotBoundaries();
Locator.getInstance().getPlotter().setPlot3d(true);
}
};
menuItems.add(plot3dMenuItem);
final IdentifiableMenuItem<MenuItem> plot2dMenuItem = new IdentifiableMenuItem<MenuItem>() {
@Nonnull
@Override
public Integer getItemId() {
return R.id.menu_plot_2d;
}
@Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
savePlotBoundaries();
Locator.getInstance().getPlotter().setPlot3d(false);
}
};
menuItems.add(plot2dMenuItem);
final IdentifiableMenuItem<MenuItem> fullscreenPlotMenuItem = new IdentifiableMenuItem<MenuItem>() {
@Nonnull
@Override
public Integer getItemId() {
return R.id.menu_plot_fullscreen;
}
@Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
savePlotBoundaries();
context.startActivity(new Intent(context, CalculatorPlotActivity.class));
}
};
menuItems.add(fullscreenPlotMenuItem);
final IdentifiableMenuItem<MenuItem> captureScreenshotMenuItem = new IdentifiableMenuItem<MenuItem>() {
@Nonnull
@Override
public Integer getItemId() {
return R.id.menu_plot_schreeshot;
}
@Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
captureScreehshot();
}
};
menuItems.add(captureScreenshotMenuItem);
final boolean plotRangeVisible = !plotData.isPlot3d();
final boolean plot3dVisible = !plotData.isPlot3d() && is3dPlotSupported();
final boolean plot2dVisible = plotData.isPlot3d() && Locator.getInstance().getPlotter().is2dPlotPossible();
final boolean captureScreenshotVisible = isScreenshotSupported();
final boolean fullscreenVisible = isPaneFragment();
fragmentMenu = ListActivityMenu.fromResource(R.menu.plot_menu, menuItems, AndroidMenuHelper.getInstance(), new JPredicate<AMenuItem<MenuItem>>() {
@Override
public boolean apply(@Nullable AMenuItem<MenuItem> menuItem) {
if (menuItem == plot3dMenuItem) {
return !plot3dVisible;
} else if (menuItem == plot2dMenuItem) {
return !plot2dVisible;
} else if (menuItem == captureScreenshotMenuItem) {
return !captureScreenshotVisible;
} else if (menuItem == plotRangeMenuItem) {
return !plotRangeVisible;
} else if (menuItem == fullscreenPlotMenuItem) {
return !fullscreenVisible;
}
return false;
}
});
final FragmentActivity activity = this.getActivity();
if (activity != null) {
fragmentMenu.onCreateOptionsMenu(activity, menu);
}
}
protected abstract boolean isScreenshotSupported();
@Nonnull
protected abstract Bitmap getScreehshot();
private void captureScreehshot() {
if (isScreenshotSupported()) {
final Bitmap screenshot = getScreehshot();
final String screenShotFileName = generateScreenshotFileName();
final File externalFilesDir = getActivity().getExternalFilesDir(getPicturesDirectory());
if (externalFilesDir != null) {
final String path = externalFilesDir.getPath();
Android.saveBitmap(screenshot, path, screenShotFileName);
Locator.getInstance().getNotifier().showMessage(R.string.cpp_plot_screenshot_saved, MessageType.info, path + "/" + screenShotFileName);
} else {
Locator.getInstance().getNotifier().showMessage(R.string.cpp_plot_unable_to_save_screenshot, MessageType.error);
}
}
}
private String getPicturesDirectory() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
return Environment.DIRECTORY_PICTURES;
} else {
return "Pictures";
}
}
private String generateScreenshotFileName() {
final Date now = new Date();
final String timestamp = new SimpleDateFormat("yyyy.MM.dd HH.mm.ss.S").format(now);
return "cpp-screenshot-" + timestamp + ".png";
}
protected abstract boolean is3dPlotSupported();
@Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
final FragmentActivity activity = this.getActivity();
if (activity != null) {
fragmentMenu.onPrepareOptionsMenu(activity, menu);
}
}
/*
**********************************************************************
*
* STATIC
*
**********************************************************************
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item) || fragmentMenu.onOptionsItemSelected(this.getActivity(), item);
}
private enum PlotMenu implements IdentifiableMenuItem<MenuItem> {
functions(R.id.menu_plot_functions) {
@Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
context.startActivity(new Intent(context, CalculatorPlotFunctionsActivity.class));
}
},
preferences(R.id.menu_plot_settings) {
@Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
PreferencesActivity.showPlotPreferences(context);
}
};
private final int itemId;
PlotMenu(int itemId) {
this.itemId = itemId;
}
@Nonnull
@Override
public Integer getItemId() {
return itemId;
}
}
}

View File

@ -1,708 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.DashPathEffect;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;
import android.widget.ZoomButtonsController;
import org.solovyev.common.math.Point2d;
import java.text.DecimalFormat;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;
public class CalculatorGraph2dView extends View implements GraphView {
public static final int TICK_SIZE_PXS = 3;
/*
**********************************************************************
*
* CONSTANTS
*
**********************************************************************
*/
private static final int NO_TOUCH = -1;
private static final float TICKS_COUNT = 15;
private static final float Y_TO_X_ADJUST_SCALE = 2f;
private static final DecimalFormat tickFormat = new DecimalFormat("##0.#####E0");
private static final int MAX_TICK_DIGITS = 4;
private static final String[] TICK_FORMATS = new String[MAX_TICK_DIGITS];
static {
for (int i = 0; i < MAX_TICK_DIGITS; i++) {
TICK_FORMATS[i] = "%." + i + "f";
}
}
/*
**********************************************************************
*
* FIELDS
*
**********************************************************************
*/
@Nonnull
private final Matrix matrix = new Matrix();
// paints
@Nonnull
private final Paint paint = new Paint();
@Nonnull
private final Paint textPaint = new Paint();
@Nonnull
private final GraphsData graphsData = new GraphsData(this);
@Nonnull
private final Graph2dDimensions dimensions = new Graph2dDimensions(this);
@Nonnull
private final GraphCalculator graphCalculator = new GraphCalculatorImpl();
@Nonnull
protected ZoomButtonsController zoomController = new ZoomButtonsController(this);
@Nonnull
private GraphViewHelper graphViewHelper = GraphViewHelper.newDefaultInstance();
private float lastTouchXPxs = NO_TOUCH;
private float lastTouchYPxs = NO_TOUCH;
@Nonnull
private TouchHandler touchHandler;
@Nonnull
private ZoomTracker zoomTracker = new ZoomTracker();
@Nonnull
private Scroller scroller;
private boolean drawn = false;
private boolean adjustYAxis = false;
/*
**********************************************************************
*
* CONSTRUCTORS
*
**********************************************************************
*/
public CalculatorGraph2dView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CalculatorGraph2dView(Context context) {
super(context);
init(context);
}
private static void graphToPath(@Nonnull GraphData graph, @Nonnull Path path) {
final int size = graph.getSize();
final float[] xs = graph.getXs();
final float[] ys = graph.getYs();
path.rewind();
boolean newCurve = true;
for (int i = 0; i < size; i++) {
final float y = ys[i];
final float x = xs[i];
if (Float.isNaN(y)) {
newCurve = true;
} else {
if (newCurve) {
path.moveTo(x, y);
newCurve = false;
} else {
path.lineTo(x, y);
}
}
}
}
@Nonnull
public static CharSequence formatTick(final float tickValue, final int tickDigits) {
String result = "0";
if (tickValue != 0f) {
if (tickDigits < MAX_TICK_DIGITS) {
result = String.format(TICK_FORMATS[tickDigits], tickValue);
} else {
// x.xxE-10 notation
result = tickFormat.format(tickValue);
}
}
return result;
}
/*
**********************************************************************
*
* METHODS
*
**********************************************************************
*/
public static int countTickDigits(float step) {
if (step >= 1) {
return 0;
} else {
int tickDigits = 0;
while (step < 1) {
step *= 10;
tickDigits++;
}
return tickDigits;
}
}
private static float getTickStep(float width) {
float f = 1;
while (width / f > TICKS_COUNT) {
f *= 10;
}
while (width / f < TICKS_COUNT / 10) {
f /= 10;
}
final float r = width / f;
if (r < TICKS_COUNT / 5) {
return f / 5;
} else if (r < TICKS_COUNT / 2) {
return f / 2;
} else {
return f;
}
}
private void init(Context context) {
touchHandler = new TouchHandler(this);
zoomController.setOnZoomListener(this);
scroller = new Scroller(context);
paint.setAntiAlias(false);
textPaint.setAntiAlias(true);
dimensions.setViewDimensions(this);
}
@Override
public void init(@Nonnull PlotViewDef plotViewDef) {
this.graphViewHelper = GraphViewHelper.newInstance(plotViewDef, Collections.<PlotFunction>emptyList());
}
@Nonnull
@Override
public List<PlotFunction> getPlotFunctions() {
return this.graphViewHelper.getPlotFunctions();
}
public void setPlotFunctions(@Nonnull List<PlotFunction> plotFunctions) {
for (PlotFunction plotFunction : plotFunctions) {
final int arity = plotFunction.getXyFunction().getArity();
if (arity != 0 && arity != 1) {
throw new IllegalArgumentException("Function must have arity 0 or 1 for 2d plot!");
}
}
this.graphViewHelper = this.graphViewHelper.copy(plotFunctions);
invalidateGraphs();
}
@Override
public void onDestroy() {
onPause();
}
@Nonnull
public Bitmap captureScreenshot() {
final Bitmap result = Bitmap.createBitmap(dimensions.getVWidthPxs(), dimensions.getVHeightPxs(), Bitmap.Config.RGB_565);
draw(new Canvas(result));
return result;
}
@Override
public void invalidateGraphs() {
graphsData.clear();
if (drawn) {
drawn = false;
invalidate();
}
}
@Override
public void setAdjustYAxis(boolean adjustYAxis) {
this.adjustYAxis = adjustYAxis;
}
public void onResume() {
}
public void onPause() {
}
public void onDetachedFromWindow() {
zoomController.setVisible(false);
super.onDetachedFromWindow();
}
protected void onSizeChanged(int w, int h, int ow, int oh) {
dimensions.setViewDimensions(w, h);
}
protected void onDraw(@Nonnull Canvas canvas) {
if (!graphViewHelper.getPlotFunctions().isEmpty()) {
if (scroller.computeScrollOffset()) {
final float xScale = dimensions.getXGraphToViewScale();
final float yScale = dimensions.getYGraphToViewScale();
dimensions.setXY(scroller.getCurrX() * xScale, scroller.getCurrY() * yScale);
if (!scroller.isFinished()) {
invalidate();
}
}
drawGraph(canvas);
}
}
/*
**********************************************************************
*
* TICKS
*
**********************************************************************
*/
private void drawGraph(@Nonnull Canvas canvas) {
drawn = true;
if (adjustYAxis) {
adjustYAxis();
adjustYAxis = false;
}
final float graphWidth = dimensions.getGWidth();
final float graphHeight = dimensions.getGHeight();
final float xMin = dimensions.getXMin();
final float xMax = dimensions.getXMax(xMin);
final float yMin = dimensions.getYMin();
final float yMax = dimensions.getYMax(yMin);
final float widthPxs = dimensions.getVWidthPxs();
final float heightPxs = dimensions.getVHeightPxs();
graphsData.checkBoundaries(graphHeight, yMin, yMax);
final TickDigits tickDigits = drawGridAndAxis(canvas);
{
// TOUCH POSITION
if (lastTouchXPxs != NO_TOUCH && lastTouchYPxs != NO_TOUCH) {
paint.setColor(graphViewHelper.getPlotViewDef().getGridColor());
canvas.drawLine(lastTouchXPxs, 0, lastTouchXPxs, heightPxs, paint);
canvas.drawLine(0, lastTouchYPxs, widthPxs, lastTouchYPxs, paint);
final Point2d lastTouch = dimensions.toGraphCoordinates(lastTouchXPxs, lastTouchYPxs);
final String touchLabel = "[" + formatTick(lastTouch.getX(), tickDigits.xTicks + 1) + ", " + formatTick(lastTouch.getY(), tickDigits.yTicks + 1) + "]";
canvas.drawText(touchLabel, 0, touchLabel.length(), lastTouchXPxs - 40, lastTouchYPxs - 40, textPaint);
}
}
final float xScale = dimensions.getXGraphToViewScale();
final float yScale = dimensions.getYGraphToViewScale();
matrix.reset();
matrix.preTranslate(-dimensions.getX0(), -dimensions.getY0());
matrix.postScale(1 / xScale, -1 / yScale);
matrix.postTranslate(widthPxs / 2, heightPxs / 2);
paint.setAntiAlias(false);
{
//GRAPH
final List<PlotFunction> plotFunctions = graphViewHelper.getPlotFunctions();
// create path once
final Path path = new Path();
for (int i = 0; i < plotFunctions.size(); i++) {
final PlotFunction plotFunction = plotFunctions.get(i);
final GraphData graph = graphsData.get(i);
graphCalculator.computeGraph(plotFunction.getXyFunction(), xMin, xMax, graph, graphsData, dimensions);
graphToPath(graph, path);
path.transform(matrix);
AbstractCalculatorPlotFragment.applyToPaint(plotFunction.getPlotLineDef(), paint);
canvas.drawPath(path, paint);
}
}
graphsData.setLastXMin(xMin);
graphsData.setLastXMax(xMax);
}
private void adjustYAxis() {
final float xMin = dimensions.getXMin();
final float xMax = dimensions.getXMax(xMin);
float yMax = -Float.MAX_VALUE;
float yMin = Float.MAX_VALUE;
graphsData.checkBoundaries(Float.MAX_VALUE, -Float.MAX_VALUE, Float.MAX_VALUE);
final List<PlotFunction> plotFunctions = graphViewHelper.getPlotFunctions();
for (int i = 0; i < plotFunctions.size(); i++) {
final PlotFunction plotFunction = plotFunctions.get(i);
final GraphData graph = graphsData.get(i);
graphCalculator.computeGraph(plotFunction.getXyFunction(), xMin, xMax, graph, graphsData, dimensions);
final float[] ys = graph.getYs();
for (int j = 0; j < graph.getSize(); j++) {
final float y = ys[j];
if (!Float.isNaN(y)) {
yMax = Math.max(yMax, y);
yMin = Math.min(yMin, y);
}
}
}
final float xDist = xMax - xMin;
yMax = Math.min(yMax, xDist);
yMin = Math.max(yMin, -xDist);
if (yMax - yMin > 0.00000001) {
final float yDist = yMax - yMin;
float maxYDist = Y_TO_X_ADJUST_SCALE * xDist;
if (yDist > maxYDist) {
// usually functions are symmetrical => just make a symmetry
yMax = yMax - yDist / 2 + maxYDist / 2;
yMin = yMin + yDist / 2 - maxYDist / 2;
}
dimensions.setYRange(yMin, yMax);
}
}
@Nonnull
private TickDigits drawGridAndAxis(@Nonnull Canvas canvas) {
final TickDigits result = new TickDigits();
final float xMin = dimensions.getXMin();
final float yMin = dimensions.getYMin();
final float yMax = dimensions.getYMax(yMin);
final float widthPxs = dimensions.getVWidthPxs();
final float heightPxs = dimensions.getVHeightPxs();
// set background
canvas.drawColor(graphViewHelper.getPlotViewDef().getBackgroundColor());
// prepare paint
paint.setStrokeWidth(0);
paint.setAntiAlias(false);
paint.setStyle(Paint.Style.STROKE);
final float xScale = dimensions.getXGraphToViewScale();
final float yScale = dimensions.getYGraphToViewScale();
float x0px = -xMin / xScale;
if (x0px < 25) {
x0px = 25;
} else if (x0px > widthPxs - 3) {
x0px = widthPxs - 3;
}
float y0px = yMax / yScale;
if (y0px < 3) {
y0px = 3;
} else if (y0px > heightPxs - 15) {
y0px = heightPxs - 15;
}
{
// GRID
paint.setPathEffect(new DashPathEffect(new float[]{5, 10}, 0));
paint.setColor(graphViewHelper.getPlotViewDef().getGridColor());
textPaint.setColor(graphViewHelper.getPlotViewDef().getAxisLabelsColor());
textPaint.setTextSize(12);
textPaint.setTextAlign(Paint.Align.CENTER);
{
final float tickStep = getTickStep(dimensions.getGWidth());
final int tickDigits = countTickDigits(tickStep);
result.xTicks = tickDigits;
// round xMin and init first tick
float tick = ((int) (xMin / tickStep)) * tickStep;
final float y2 = y0px + TICK_SIZE_PXS;
float stepPxs = tickStep / xScale;
for (float xPxs = (tick - xMin) / xScale; xPxs <= widthPxs; xPxs += stepPxs, tick += tickStep) {
// draw grid line
canvas.drawLine(xPxs, 0, xPxs, heightPxs, paint);
final CharSequence tickLabel = formatTick(tick, tickDigits);
// draw tick label
canvas.drawText(tickLabel, 0, tickLabel.length(), xPxs, y2 + 10, textPaint);
}
}
{
final float tickStep = getTickStep(dimensions.getGHeight());
final int tickDigits = countTickDigits(tickStep);
result.yTicks = tickDigits;
// round yMin and init first tick
float tick = ((int) (yMin / tickStep)) * tickStep;
final float x1 = x0px - TICK_SIZE_PXS;
final float stepPxs = tickStep / yScale;
textPaint.setTextAlign(Paint.Align.RIGHT);
for (float y = heightPxs - (tick - yMin) / yScale; y >= 0; y -= stepPxs, tick += tickStep) {
canvas.drawLine(0, y, widthPxs, y, paint);
final CharSequence tickLabel = formatTick(tick, tickDigits);
// draw tick label
canvas.drawText(tickLabel, 0, tickLabel.length(), x1, y + 4, textPaint);
}
}
paint.setPathEffect(null);
}
{
// AXIS
paint.setColor(graphViewHelper.getPlotViewDef().getAxisColor());
canvas.drawLine(x0px, 0, x0px, heightPxs, paint);
canvas.drawLine(0, y0px, widthPxs, y0px, paint);
}
return result;
}
/*
**********************************************************************
*
* BOUNDARIES
*
**********************************************************************
*/
// X
public float getXMin() {
return dimensions.getXMin();
}
public float getXMax() {
return dimensions.getXMax();
}
// Y
@Override
public float getYMin() {
return dimensions.getYMin();
}
@Override
public float getYMax() {
return dimensions.getYMax();
}
@Override
public void setXRange(float xMin, float xMax) {
this.dimensions.setXRange(xMin, xMax);
}
@Override
public void setYRange(float yMin, float yMax) {
this.dimensions.setYRange(yMin, yMax);
}
/*
**********************************************************************
*
* ZOOM
*
**********************************************************************
*/
private boolean canZoomIn() {
return true;
}
private boolean canZoomOut() {
return true;
}
public void onVisibilityChanged(boolean visible) {
}
public void onZoom(boolean zoomIn) {
if (zoomIn) {
if (canZoomIn()) {
dimensions.setGraphDimensions(dimensions.getGWidth() / 2, dimensions.getGHeight() / 2);
}
} else {
if (canZoomOut()) {
dimensions.setGraphDimensions(dimensions.getGWidth() * 2, dimensions.getGHeight() * 2);
}
}
zoomController.setZoomInEnabled(canZoomIn());
zoomController.setZoomOutEnabled(canZoomOut());
}
/*
**********************************************************************
*
* TOUCH
*
**********************************************************************
*/
@Override
public boolean onTouchEvent(@Nonnull MotionEvent event) {
boolean handled = touchHandler.handleTouchEvent(event);
if (!handled) {
handled = super.onTouchEvent(event);
}
return handled;
}
public void onTouchDown(float x, float y) {
zoomController.setVisible(true);
if (!scroller.isFinished()) {
scroller.abortAnimation();
}
lastTouchXPxs = x;
lastTouchYPxs = y;
}
public void onTouchMove(float x, float y) {
float deltaX = x - lastTouchXPxs;
float deltaY = y - lastTouchYPxs;
if (deltaX < -1 || deltaX > 1 || deltaY < -1 || deltaY > 1) {
scroll(-deltaX, deltaY);
lastTouchXPxs = x;
lastTouchYPxs = y;
invalidate();
}
}
public void onTouchUp(float x, float y) {
final float xScale = dimensions.getXGraphToViewScale();
final float yScale = dimensions.getYGraphToViewScale();
lastTouchXPxs = NO_TOUCH;
lastTouchYPxs = NO_TOUCH;
float sx = -touchHandler.getXVelocity();
float sy = touchHandler.getYVelocity();
final float asx = Math.abs(sx);
final float asy = Math.abs(sy);
if (asx < asy / 3) {
sx = 0;
} else if (asy < asx / 3) {
sy = 0;
}
scroller.fling(Math.round(dimensions.getX0() / xScale), Math.round(dimensions.getY0() / yScale), Math.round(sx), Math.round(sy), Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);
invalidate();
}
public void onTouchZoomDown(float x1, float y1, float x2, float y2) {
zoomTracker.start(dimensions.getGWidth(), dimensions.getGHeight(), x1, y1, x2, y2);
lastTouchXPxs = NO_TOUCH;
lastTouchYPxs = NO_TOUCH;
}
public void onTouchZoomMove(float x1, float y1, float x2, float y2) {
if (!zoomTracker.update(x1, y1, x2, y2)) {
return;
}
final float targetGWidth = zoomTracker.xValue;
final float targetGHeight = zoomTracker.yValue;
dimensions.setGraphDimensions(targetGWidth, targetGHeight);
}
private void scroll(float deltaX, float deltaY) {
final float xScale = dimensions.getXGraphToViewScale();
final float yScale = dimensions.getYGraphToViewScale();
float dx = deltaX * xScale;
float dy = deltaY * yScale;
dimensions.increaseXY(dx, dy);
}
private static final class TickDigits {
public int xTicks = 1;
public int yTicks = 1;
}
}

View File

@ -1,65 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import android.content.Intent;
import android.os.Bundle;
import org.solovyev.android.calculator.CalculatorFragmentType;
import org.solovyev.android.calculator.EmptyActivity;
import org.solovyev.android.calculator.R;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static android.support.v7.app.ActionBar.NAVIGATION_MODE_STANDARD;
/**
* User: serso
* Date: 9/30/12
* Time: 4:56 PM
*/
public class CalculatorPlotActivity extends EmptyActivity {
@Nonnull
public static CalculatorFragmentType getPlotterFragmentType() {
return CalculatorFragmentType.plotter;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Intent intent = getIntent();
final Bundle arguments;
if (intent != null) {
arguments = intent.getExtras();
} else {
arguments = null;
}
getSupportActionBar().setNavigationMode(NAVIGATION_MODE_STANDARD);
getUi().setFragment(this, getPlotterFragmentType(), arguments, R.id.main_layout);
}
}

View File

@ -1,148 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.R;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* User: serso
* Date: 12/30/12
* Time: 4:43 PM
*/
public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment {
@Nullable
private GraphView graphView;
@Nullable
@Override
protected PlotBoundaries getPlotBoundaries() {
if (graphView instanceof CalculatorGraph2dView) {
return PlotBoundaries.newInstance(graphView.getXMin(), graphView.getXMax(), graphView.getYMin(), graphView.getYMax());
} else {
return null;
}
}
@Override
protected void createGraphicalView(@Nonnull View root, @Nonnull PlotData plotData) {
// remove old
final ViewGroup graphContainer = (ViewGroup) root.findViewById(R.id.main_fragment_layout);
if (graphView instanceof View) {
graphView.onDestroy();
graphContainer.removeView((View) graphView);
}
final boolean d3 = plotData.isPlot3d();
if (d3) {
graphView = new CalculatorGraph3dView(getActivity());
} else {
graphView = new CalculatorGraph2dView(getActivity());
}
final int color = App.getTheme().getTextColorFor(getActivity()).normal;
graphView.init(PlotViewDef.newInstance(color, color, Color.DKGRAY, getBgColor(d3)));
final PlotBoundaries boundaries = plotData.getBoundaries();
graphView.setXRange(boundaries.getXMin(), boundaries.getXMax());
graphView.setYRange(boundaries.getYMin(), boundaries.getYMax());
graphView.setAdjustYAxis(plotData.isAdjustYAxis());
graphView.setPlotFunctions(plotData.getFunctions());
if (graphView instanceof View) {
graphContainer.addView((View) graphView);
}
}
@Override
protected void createChart(@Nonnull PlotData plotData) {
}
@Override
protected boolean isScreenshotSupported() {
return true;
}
@Nonnull
@Override
protected Bitmap getScreehshot() {
if (this.graphView == null) throw new AssertionError();
return this.graphView.captureScreenshot();
}
@Override
protected boolean is3dPlotSupported() {
return true;
}
@Override
public void onResume() {
super.onResume();
if (this.graphView != null) {
this.graphView.onResume();
}
}
@Override
protected void onError() {
final View root = getView();
if (root != null && graphView instanceof View) {
final ViewGroup graphContainer = (ViewGroup) root.findViewById(R.id.main_fragment_layout);
graphContainer.removeView((View) graphView);
}
this.graphView = null;
}
@Override
public void onPause() {
if (this.graphView != null) {
this.graphView.onPause();
}
super.onPause();
}
@Override
public void onDestroyView() {
if (this.graphView != null) {
this.graphView.onDestroy();
}
super.onDestroyView();
}
}

View File

@ -1,195 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.Spinner;
import org.solovyev.android.calculator.CalculatorFragment;
import org.solovyev.android.calculator.CalculatorFragmentType;
import org.solovyev.android.calculator.Locator;
import org.solovyev.android.calculator.R;
import org.solovyev.android.fragments.FragmentUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class CalculatorPlotFunctionSettingsActivity extends ActionBarActivity {
private static final String INPUT_FUNCTION_ID = "plot-function-id";
public static void startActivity(@Nonnull Context context, @Nonnull PlotFunction plotFunction) {
final Intent intent = new Intent(context, CalculatorPlotFunctionSettingsActivity.class);
intent.putExtra(INPUT_FUNCTION_ID, plotFunction.getXyFunction().getId());
context.startActivity(intent);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.cpp_plot_function_settings_dialog);
final Intent intent = getIntent();
if (intent != null) {
final String plotFunctionId = intent.getStringExtra(INPUT_FUNCTION_ID);
if (plotFunctionId != null) {
final Bundle parameters = new Bundle();
parameters.putString(INPUT_FUNCTION_ID, plotFunctionId);
FragmentUtils.createFragment(this, CalculatorPlotFunctionSettingsFragment.class, R.id.dialog_layout, "plot-function-settings", parameters);
} else {
finish();
}
} else {
finish();
}
}
public static class CalculatorPlotFunctionSettingsFragment extends CalculatorFragment {
/*
**********************************************************************
*
* STATIC
*
**********************************************************************
*/
@Nonnull
private final CalculatorPlotter plotter = Locator.getInstance().getPlotter();
@Nullable
private PlotFunction plotFunction;
public CalculatorPlotFunctionSettingsFragment() {
super(CalculatorFragmentType.plotter_function_settings);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final String functionId = getArguments().getString(INPUT_FUNCTION_ID);
if (functionId != null) {
plotFunction = Locator.getInstance().getPlotter().getFunctionById(functionId);
if (plotFunction != null) {
getActivity().setTitle(plotFunction.getXyFunction().getExpressionString());
}
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
@Override
public void onViewCreated(View root, Bundle savedInstanceState) {
super.onViewCreated(root, savedInstanceState);
final Spinner plotLineColorSpinner = (Spinner) root.findViewById(R.id.cpp_plot_function_line_color_spinner);
final Spinner plotLineColorTypeSpinner = (Spinner) root.findViewById(R.id.cpp_plot_function_line_color_type_spinner);
final Spinner plotLineStyleSpinner = (Spinner) root.findViewById(R.id.cpp_plot_function_line_style_spinner);
final SeekBar plotLineWidthSeekBar = (SeekBar) root.findViewById(R.id.cpp_plot_functions_line_width_seekbar);
final Button okButton = (Button) root.findViewById(R.id.cpp_apply_button);
plotLineWidthSeekBar.setMax(10);
if (plotFunction != null) {
plotLineWidthSeekBar.setProgress((int) plotFunction.getPlotLineDef().getLineWidth());
plotLineColorSpinner.setSelection(PlotLineColor.valueOf(plotFunction.getPlotLineDef().getLineColor()).ordinal());
plotLineColorTypeSpinner.setSelection(plotFunction.getPlotLineDef().getLineColorType().ordinal());
plotLineStyleSpinner.setSelection(plotFunction.getPlotLineDef().getLineStyle().ordinal());
okButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
PlotFunction plotFunction = CalculatorPlotFunctionSettingsFragment.this.plotFunction;
// color
final PlotLineColor newPlotLineColor = PlotLineColor.values()[plotLineColorSpinner.getSelectedItemPosition()];
int newLineColor = newPlotLineColor.getColor();
if (newLineColor != plotFunction.getPlotLineDef().getLineColor()) {
final PlotLineDef newPlotLineDef = PlotLineDef.changeLineColor(plotFunction.getPlotLineDef(), newLineColor);
plotFunction = PlotFunction.changePlotLineDef(plotFunction, newPlotLineDef);
}
// color type
final PlotLineColorType newPlotLineColorType = PlotLineColorType.values()[plotLineColorTypeSpinner.getSelectedItemPosition()];
if (newPlotLineColorType != CalculatorPlotFunctionSettingsFragment.this.plotFunction.getPlotLineDef().getLineColorType()) {
final PlotLineDef newPlotLineDef = PlotLineDef.changeLineColorType(plotFunction.getPlotLineDef(), newPlotLineColorType);
plotFunction = PlotFunction.changePlotLineDef(plotFunction, newPlotLineDef);
}
// line style
final PlotLineStyle newPlotLineStyle = PlotLineStyle.values()[plotLineStyleSpinner.getSelectedItemPosition()];
if (newPlotLineStyle != plotFunction.getPlotLineDef().getLineStyle()) {
final PlotLineDef newPlotLineDef = PlotLineDef.changeLineStyle(plotFunction.getPlotLineDef(), newPlotLineStyle);
plotFunction = PlotFunction.changePlotLineDef(plotFunction, newPlotLineDef);
}
// width
final int newPlotLineWidth = plotLineWidthSeekBar.getProgress();
if (((float) newPlotLineWidth) != plotFunction.getPlotLineDef().getLineWidth()) {
final PlotLineDef newPlotLineDef = PlotLineDef.changeLineWidth(plotFunction.getPlotLineDef(), newPlotLineWidth);
plotFunction = PlotFunction.changePlotLineDef(plotFunction, newPlotLineDef);
}
if (plotFunction != CalculatorPlotFunctionSettingsFragment.this.plotFunction) {
// if has been changed
if (plotter.updateFunction(plotFunction)) {
CalculatorPlotFunctionSettingsFragment.this.plotFunction = plotFunction;
}
}
final Activity activity = getActivity();
if (activity != null) {
activity.finish();
}
}
});
} else {
plotLineWidthSeekBar.setEnabled(false);
plotLineColorSpinner.setEnabled(false);
plotLineColorTypeSpinner.setEnabled(false);
plotLineStyleSpinner.setEnabled(false);
okButton.setEnabled(false);
}
}
}
}

View File

@ -1,79 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import org.solovyev.android.calculator.CalculatorFragmentType;
import org.solovyev.android.calculator.CalculatorListFragment;
import org.solovyev.android.calculator.Locator;
import org.solovyev.android.calculator.R;
import org.solovyev.android.fragments.FragmentUtils;
import org.solovyev.android.list.ListItemAdapter;
import java.util.List;
import javax.annotation.Nullable;
/**
* User: serso
* Date: 1/13/13
* Time: 5:05 PM
*/
public class CalculatorPlotFunctionsActivity extends ActionBarActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.cpp_dialog);
FragmentUtils.createFragment(this, CalculatorPlotFunctionsFragment.class, R.id.dialog_layout, "plot-functions");
}
public static class CalculatorPlotFunctionsFragment extends CalculatorListFragment {
public CalculatorPlotFunctionsFragment() {
super(CalculatorFragmentType.plotter_functions);
}
@Override
public void onResume() {
super.onResume();
final List<PlotFunctionListItem> items = Lists.transform(Locator.getInstance().getPlotter().getFunctions(), new Function<PlotFunction, PlotFunctionListItem>() {
@Override
public PlotFunctionListItem apply(@javax.annotation.Nullable PlotFunction input) {
if (input == null) throw new AssertionError();
return new PlotFunctionListItem(input);
}
});
ListItemAdapter.createAndAttach(this, items);
}
}
}

View File

@ -1,115 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.EditText;
import org.solovyev.android.calculator.CalculatorFragment;
import org.solovyev.android.calculator.CalculatorFragmentType;
import org.solovyev.android.calculator.Locator;
import org.solovyev.android.calculator.R;
import org.solovyev.android.fragments.FragmentUtils;
import org.solovyev.common.msg.MessageType;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* User: serso
* Date: 1/19/13
* Time: 5:14 PM
*/
public class CalculatorPlotRangeActivity extends ActionBarActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.cpp_dialog);
FragmentUtils.createFragment(this, CalculatorPlotRangeFragment.class, R.id.dialog_layout, "plot-range");
}
public static class CalculatorPlotRangeFragment extends CalculatorFragment {
public CalculatorPlotRangeFragment() {
super(CalculatorFragmentType.plotter_range);
}
@Override
public void onViewCreated(@Nonnull View root, Bundle savedInstanceState) {
super.onViewCreated(root, savedInstanceState);
final CalculatorPlotter plotter = Locator.getInstance().getPlotter();
final EditText xMinEditText = (EditText) root.findViewById(R.id.cpp_plot_range_x_min_editext);
final EditText xMaxEditText = (EditText) root.findViewById(R.id.cpp_plot_range_x_max_editext);
final EditText yMinEditText = (EditText) root.findViewById(R.id.cpp_plot_range_y_min_editext);
final EditText yMaxEditText = (EditText) root.findViewById(R.id.cpp_plot_range_y_max_editext);
final PlotData plotData = plotter.getPlotData();
final PlotBoundaries boundaries = plotData.getBoundaries();
xMinEditText.setText(String.valueOf(boundaries.getXMin()));
xMaxEditText.setText(String.valueOf(boundaries.getXMax()));
yMinEditText.setText(String.valueOf(boundaries.getYMin()));
yMaxEditText.setText(String.valueOf(boundaries.getYMax()));
root.findViewById(R.id.cpp_apply_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
final Float xMin = Float.valueOf(xMinEditText.getText().toString());
final Float xMax = Float.valueOf(xMaxEditText.getText().toString());
final Float yMin = Float.valueOf(yMinEditText.getText().toString());
final Float yMax = Float.valueOf(yMaxEditText.getText().toString());
if (xMin.equals(xMax)) {
throw new IllegalArgumentException();
}
if (yMin.equals(yMax)) {
throw new IllegalArgumentException();
}
plotter.setPlotBoundaries(PlotBoundaries.newInstance(xMin, xMax, yMin, yMax));
CalculatorPlotRangeFragment.this.getActivity().finish();
} catch (IllegalArgumentException e) {
if (e instanceof NumberFormatException) {
Locator.getInstance().getNotifier().showMessage(R.string.cpp_invalid_number, MessageType.error);
} else {
Locator.getInstance().getNotifier().showMessage(R.string.cpp_plot_boundaries_should_differ, MessageType.error);
}
}
}
});
}
}
}

View File

@ -145,7 +145,7 @@ public class PlotFunctionListItem implements ListItem {
settingsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CalculatorPlotFunctionSettingsActivity.startActivity(context, plotFunction);
// FIXME: 2016-02-01
}
});
}

View File

@ -40,11 +40,6 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Arrays;
/**
* User: serso
* Date: 4/22/12
* Time: 12:20 AM
*/
public class NumeralBaseConverterDialog {
@Nullable

View File

@ -37,7 +37,7 @@ import java.util.concurrent.Executor;
public class AbstractCalculatorTest {
protected void setUp() throws Exception {
Locator.getInstance().init(new Calculator(Mockito.mock(SharedPreferences.class), Mockito.mock(Bus.class), Mockito.mock(Executor.class)), CalculatorTestUtils.newCalculatorEngine(), Mockito.mock(CalculatorNotifier.class), new SystemErrorReporter(), Mockito.mock(PreferredPreferences.class), Mockito.mock(Keyboard.class), Mockito.mock(CalculatorPlotter.class));
Locator.getInstance().init(new Calculator(Mockito.mock(SharedPreferences.class), Mockito.mock(Bus.class), Mockito.mock(Executor.class)), CalculatorTestUtils.newCalculatorEngine(), Mockito.mock(Keyboard.class), Mockito.mock(CalculatorPlotter.class));
Locator.getInstance().getEngine().init(new Executor() {
@Override
public void execute(Runnable command) {

View File

@ -1,7 +1,6 @@
package org.solovyev.android.calculator;
import android.content.Intent;
import android.os.Build;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -9,14 +8,11 @@ import org.mockito.Mockito;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.annotation.Config;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.robolectric.RuntimeEnvironment.application;
import static org.solovyev.android.calculator.CalculatorButton.four;
import static org.solovyev.android.calculator.CalculatorReceiver.ACTION_BUTTON_ID_EXTRA;
import static org.solovyev.android.calculator.CalculatorReceiver.ACTION_BUTTON_PRESSED;
import static org.solovyev.android.calculator.CalculatorReceiver.newButtonClickedIntent;
import static org.solovyev.android.calculator.CalculatorReceiver.*;
@Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.LOLLIPOP)
@RunWith(RobolectricGradleTestRunner.class)
@ -24,7 +20,7 @@ public class CalculatorReceiverTest {
@Test
public void testShouldPressButtonOnIntent() throws Exception {
Locator.setKeyboard(mock(Keyboard.class));
//Locator.setKeyboard(mock(Keyboard.class));
final Intent intent = newButtonClickedIntent(application, four);
new CalculatorReceiver().onReceive(application, intent);
@ -35,7 +31,7 @@ public class CalculatorReceiverTest {
@Test
public void testShouldDoNothingIfButtonInvalid() throws Exception {
Locator.setKeyboard(mock(Keyboard.class));
//Locator.setKeyboard(mock(Keyboard.class));
final Intent intent = new Intent(application, CalculatorReceiver.class);
intent.setAction(ACTION_BUTTON_PRESSED);

View File

@ -59,7 +59,7 @@ public class CalculatorTestUtils {
public static void staticSetUp() throws Exception {
App.init(new CalculatorApplication(), new Languages(new RoboSharedPreferences(new HashMap<String, Map<String, Object>>(), "test", 0)));
Locator.getInstance().init(new Calculator(mock(SharedPreferences.class), mock(Bus.class), mock(Executor.class)), newCalculatorEngine(), mock(CalculatorNotifier.class), new SystemErrorReporter(), mock(PreferredPreferences.class), mock(Keyboard.class), mock(CalculatorPlotter.class));
Locator.getInstance().init(new Calculator(mock(SharedPreferences.class), mock(Bus.class), mock(Executor.class)), newCalculatorEngine(), mock(Keyboard.class), mock(CalculatorPlotter.class));
Locator.getInstance().getEngine().init(new Executor() {
@Override
public void execute(Runnable command) {
@ -74,7 +74,7 @@ public class CalculatorTestUtils {
}
public static void staticSetUp(@Nullable Context context) throws Exception {
Locator.getInstance().init(new Calculator(mock(SharedPreferences.class), mock(Bus.class), mock(Executor.class)), newCalculatorEngine(), mock(CalculatorNotifier.class), new SystemErrorReporter(), mock(PreferredPreferences.class), mock(Keyboard.class), mock(CalculatorPlotter.class));
Locator.getInstance().init(new Calculator(mock(SharedPreferences.class), mock(Bus.class), mock(Executor.class)), newCalculatorEngine(), mock(Keyboard.class), mock(CalculatorPlotter.class));
Locator.getInstance().getEngine().init(new Executor() {
@Override
public void execute(Runnable command) {

View File

@ -1,63 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.plot;
import org.junit.Test;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import static org.junit.Assert.assertEquals;
/**
* User: serso
* Date: 1/15/13
* Time: 9:58 PM
*/
public class CalculatorGraph2dViewTest {
@Test
public void testFormatTick() throws Exception {
assertEquals("23324", CalculatorGraph2dView.formatTick(23324.0f, 0));
final DecimalFormat format = (DecimalFormat) DecimalFormat.getInstance();
final DecimalFormatSymbols decimalFormatSymbols = format.getDecimalFormatSymbols();
if (',' == decimalFormatSymbols.getDecimalSeparator()) {
assertEquals("23324,1", CalculatorGraph2dView.formatTick(23324.1f, 1));
} else if ('.' == decimalFormatSymbols.getDecimalSeparator()) {
assertEquals("23324.1", CalculatorGraph2dView.formatTick(23324.1f, 1));
}
}
@Test
public void testCountTickDigits() throws Exception {
assertEquals(0, CalculatorGraph2dView.countTickDigits(1));
assertEquals(0, CalculatorGraph2dView.countTickDigits(10));
assertEquals(0, CalculatorGraph2dView.countTickDigits(100));
assertEquals(1, CalculatorGraph2dView.countTickDigits(0.9f));
assertEquals(1, CalculatorGraph2dView.countTickDigits(0.2f));
assertEquals(1, CalculatorGraph2dView.countTickDigits(0.1f));
assertEquals(2, CalculatorGraph2dView.countTickDigits(0.099f));
assertEquals(3, CalculatorGraph2dView.countTickDigits(0.009f));
}
}