Code reformatted

This commit is contained in:
serso 2016-01-04 12:39:25 +01:00
parent 11bdcae2a8
commit 4eeeb1277e
794 changed files with 35363 additions and 35284 deletions

View File

@ -28,11 +28,11 @@ import org.solovyev.android.calculator.units.CalculatorNumeralBase;
import org.solovyev.common.units.Unit; import org.solovyev.common.units.Unit;
import org.solovyev.common.units.UnitConverter; import org.solovyev.common.units.UnitConverter;
import javax.annotation.Nonnull;
import java.util.Date; import java.util.Date;
import java.util.Random; import java.util.Random;
import javax.annotation.Nonnull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
/** /**
@ -42,56 +42,56 @@ import static org.junit.Assert.assertTrue;
*/ */
public class AndroidNumeralBaseTest { public class AndroidNumeralBaseTest {
@Nonnull @Nonnull
private final UnitConverter<String> c = CalculatorNumeralBase.getConverter(); private final UnitConverter<String> c = CalculatorNumeralBase.getConverter();
@Test @Test
public void testIsSupported() throws Exception { public void testIsSupported() throws Exception {
assertTrue(c.isSupported(CalculatorNumeralBase.bin, CalculatorNumeralBase.dec)); assertTrue(c.isSupported(CalculatorNumeralBase.bin, CalculatorNumeralBase.dec));
} }
@Test @Test
public void testConvertFromDec() throws Exception { public void testConvertFromDec() throws Exception {
Assert.assertEquals("101", c.convert(CalculatorNumeralBase.dec.createUnit("5"), CalculatorNumeralBase.bin).getValue()); Assert.assertEquals("101", c.convert(CalculatorNumeralBase.dec.createUnit("5"), CalculatorNumeralBase.bin).getValue());
Assert.assertEquals("1", c.convert(CalculatorNumeralBase.dec.createUnit("1"), CalculatorNumeralBase.bin).getValue()); Assert.assertEquals("1", c.convert(CalculatorNumeralBase.dec.createUnit("1"), CalculatorNumeralBase.bin).getValue());
Assert.assertEquals("0", c.convert(CalculatorNumeralBase.dec.createUnit("0"), CalculatorNumeralBase.bin).getValue()); Assert.assertEquals("0", c.convert(CalculatorNumeralBase.dec.createUnit("0"), CalculatorNumeralBase.bin).getValue());
Assert.assertEquals("1111100111", c.convert(CalculatorNumeralBase.dec.createUnit("999"), CalculatorNumeralBase.bin).getValue()); Assert.assertEquals("1111100111", c.convert(CalculatorNumeralBase.dec.createUnit("999"), CalculatorNumeralBase.bin).getValue());
Assert.assertEquals("A23", c.convert(CalculatorNumeralBase.dec.createUnit("2595"), CalculatorNumeralBase.hex).getValue()); Assert.assertEquals("A23", c.convert(CalculatorNumeralBase.dec.createUnit("2595"), CalculatorNumeralBase.hex).getValue());
Assert.assertEquals("AEE", c.convert(CalculatorNumeralBase.dec.createUnit("2798"), CalculatorNumeralBase.hex).getValue()); Assert.assertEquals("AEE", c.convert(CalculatorNumeralBase.dec.createUnit("2798"), CalculatorNumeralBase.hex).getValue());
Assert.assertEquals("15", c.convert(CalculatorNumeralBase.dec.createUnit("21"), CalculatorNumeralBase.hex).getValue()); Assert.assertEquals("15", c.convert(CalculatorNumeralBase.dec.createUnit("21"), CalculatorNumeralBase.hex).getValue());
Assert.assertEquals("0", c.convert(CalculatorNumeralBase.dec.createUnit("0"), CalculatorNumeralBase.hex).getValue()); Assert.assertEquals("0", c.convert(CalculatorNumeralBase.dec.createUnit("0"), CalculatorNumeralBase.hex).getValue());
Assert.assertEquals("3E7", c.convert(CalculatorNumeralBase.dec.createUnit("999"), CalculatorNumeralBase.hex).getValue()); Assert.assertEquals("3E7", c.convert(CalculatorNumeralBase.dec.createUnit("999"), CalculatorNumeralBase.hex).getValue());
Assert.assertEquals("76", c.convert(CalculatorNumeralBase.dec.createUnit("62"), CalculatorNumeralBase.oct).getValue()); Assert.assertEquals("76", c.convert(CalculatorNumeralBase.dec.createUnit("62"), CalculatorNumeralBase.oct).getValue());
Assert.assertEquals("12", c.convert(CalculatorNumeralBase.dec.createUnit("10"), CalculatorNumeralBase.oct).getValue()); Assert.assertEquals("12", c.convert(CalculatorNumeralBase.dec.createUnit("10"), CalculatorNumeralBase.oct).getValue());
Assert.assertEquals("15", c.convert(CalculatorNumeralBase.dec.createUnit("13"), CalculatorNumeralBase.oct).getValue()); Assert.assertEquals("15", c.convert(CalculatorNumeralBase.dec.createUnit("13"), CalculatorNumeralBase.oct).getValue());
Assert.assertEquals("0", c.convert(CalculatorNumeralBase.dec.createUnit("0"), CalculatorNumeralBase.oct).getValue()); Assert.assertEquals("0", c.convert(CalculatorNumeralBase.dec.createUnit("0"), CalculatorNumeralBase.oct).getValue());
Assert.assertEquals("10445", c.convert(CalculatorNumeralBase.dec.createUnit("4389"), CalculatorNumeralBase.oct).getValue()); Assert.assertEquals("10445", c.convert(CalculatorNumeralBase.dec.createUnit("4389"), CalculatorNumeralBase.oct).getValue());
} }
@Test @Test
public void testRandomConvert() throws Exception { public void testRandomConvert() throws Exception {
final Random random = new Random(new Date().getTime()); final Random random = new Random(new Date().getTime());
for (int i = 0; i < 100000; i++) { for (int i = 0; i < 100000; i++) {
final String value = String.valueOf(random.nextInt()); final String value = String.valueOf(random.nextInt());
Assert.assertEquals(value, convertChain(value, CalculatorNumeralBase.dec, CalculatorNumeralBase.oct, CalculatorNumeralBase.oct, CalculatorNumeralBase.bin, CalculatorNumeralBase.dec)); Assert.assertEquals(value, convertChain(value, CalculatorNumeralBase.dec, CalculatorNumeralBase.oct, CalculatorNumeralBase.oct, CalculatorNumeralBase.bin, CalculatorNumeralBase.dec));
Assert.assertEquals(value, convertChain(value, CalculatorNumeralBase.dec, CalculatorNumeralBase.bin, CalculatorNumeralBase.hex, CalculatorNumeralBase.dec, CalculatorNumeralBase.dec)); Assert.assertEquals(value, convertChain(value, CalculatorNumeralBase.dec, CalculatorNumeralBase.bin, CalculatorNumeralBase.hex, CalculatorNumeralBase.dec, CalculatorNumeralBase.dec));
Assert.assertEquals(value, convertChain(value, CalculatorNumeralBase.dec, CalculatorNumeralBase.dec, CalculatorNumeralBase.hex, CalculatorNumeralBase.oct, CalculatorNumeralBase.dec)); Assert.assertEquals(value, convertChain(value, CalculatorNumeralBase.dec, CalculatorNumeralBase.dec, CalculatorNumeralBase.hex, CalculatorNumeralBase.oct, CalculatorNumeralBase.dec));
Assert.assertEquals(value, convertChain(value, CalculatorNumeralBase.dec, CalculatorNumeralBase.hex, CalculatorNumeralBase.bin, CalculatorNumeralBase.oct, CalculatorNumeralBase.dec)); Assert.assertEquals(value, convertChain(value, CalculatorNumeralBase.dec, CalculatorNumeralBase.hex, CalculatorNumeralBase.bin, CalculatorNumeralBase.oct, CalculatorNumeralBase.dec));
} }
} }
@Nonnull @Nonnull
private String convertChain(@Nonnull String value, @Nonnull CalculatorNumeralBase baseAndroid, @Nonnull CalculatorNumeralBase... typeAndroids) { private String convertChain(@Nonnull String value, @Nonnull CalculatorNumeralBase baseAndroid, @Nonnull CalculatorNumeralBase... typeAndroids) {
Unit<String> unit = baseAndroid.createUnit(value); Unit<String> unit = baseAndroid.createUnit(value);
for (CalculatorNumeralBase typeAndroid : typeAndroids) { for (CalculatorNumeralBase typeAndroid : typeAndroids) {
unit = CalculatorNumeralBase.getConverter().convert(unit, typeAndroid); unit = CalculatorNumeralBase.getConverter().convert(unit, typeAndroid);
} }
return unit.getValue(); return unit.getValue();
} }
} }

View File

@ -7,21 +7,21 @@ import org.robolectric.annotation.Config;
import org.robolectric.res.Fs; import org.robolectric.res.Fs;
public class CalculatorTestRunner extends RobolectricTestRunner { public class CalculatorTestRunner extends RobolectricTestRunner {
private static final int MAX_SDK_SUPPORTED_BY_ROBOLECTRIC = 18; private static final int MAX_SDK_SUPPORTED_BY_ROBOLECTRIC = 18;
public CalculatorTestRunner(Class<?> testClass) throws InitializationError { public CalculatorTestRunner(Class<?> testClass) throws InitializationError {
super(testClass); super(testClass);
} }
@Override @Override
protected AndroidManifest getAppManifest(Config config) { protected AndroidManifest getAppManifest(Config config) {
final String manifestFilePath = "android-app/src/main/AndroidManifest.xml"; final String manifestFilePath = "android-app/src/main/AndroidManifest.xml";
final String resourcesFilePath = "android-app/src/main/res"; final String resourcesFilePath = "android-app/src/main/res";
return new AndroidManifest(Fs.fileFromPath(manifestFilePath), Fs.fileFromPath(resourcesFilePath)) { return new AndroidManifest(Fs.fileFromPath(manifestFilePath), Fs.fileFromPath(resourcesFilePath)) {
@Override @Override
public int getTargetSdkVersion() { public int getTargetSdkVersion() {
return MAX_SDK_SUPPORTED_BY_ROBOLECTRIC; return MAX_SDK_SUPPORTED_BY_ROBOLECTRIC;
} }
}; };
} }
} }

View File

@ -44,68 +44,68 @@ import java.util.concurrent.atomic.AtomicBoolean;
@RunWith(value = CalculatorTestRunner.class) @RunWith(value = CalculatorTestRunner.class)
public class AndroidCalculatorEditorViewTest { public class AndroidCalculatorEditorViewTest {
@BeforeClass @BeforeClass
public static void staticSetUp() throws Exception { public static void staticSetUp() throws Exception {
/*CalculatorTestUtils.staticSetUp(null);*/ /*CalculatorTestUtils.staticSetUp(null);*/
} }
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
/* CalculatorActivity context = new CalculatorActivity(); /* CalculatorActivity context = new CalculatorActivity();
CalculatorTestUtils.initViews(context);*/ CalculatorTestUtils.initViews(context);*/
} }
@Test @Test
public void testCreation() throws Exception { public void testCreation() throws Exception {
new AndroidCalculatorEditorView(CalculatorApplication.getInstance()); new AndroidCalculatorEditorView(CalculatorApplication.getInstance());
} }
@Test @Test
public void testAsyncWork() throws Exception { public void testAsyncWork() throws Exception {
final int threadNum = 10; final int threadNum = 10;
final int count = 10; final int count = 10;
final int maxTextLength = 100; final int maxTextLength = 100;
final Random random = new Random(new Date().getTime()); final Random random = new Random(new Date().getTime());
final CountDownLatch startLatchLatch = new CountDownLatch(threadNum); final CountDownLatch startLatchLatch = new CountDownLatch(threadNum);
final CountDownLatch finishLatch = new CountDownLatch(threadNum * count); final CountDownLatch finishLatch = new CountDownLatch(threadNum * count);
final AtomicBoolean error = new AtomicBoolean(false); final AtomicBoolean error = new AtomicBoolean(false);
for (int i = 0; i < threadNum; i++) { for (int i = 0; i < threadNum; i++) {
new Thread(new Runnable() { new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
try { try {
startLatchLatch.await(); startLatchLatch.await();
} catch (InterruptedException e) { } catch (InterruptedException e) {
System.out.println(e); System.out.println(e);
error.set(true); error.set(true);
for (int j = 0; j < count; j++) { for (int j = 0; j < count; j++) {
finishLatch.countDown(); finishLatch.countDown();
} }
return; return;
} }
for (int j = 0; j < count; j++) { for (int j = 0; j < count; j++) {
try { try {
int textLength = random.nextInt(maxTextLength); int textLength = random.nextInt(maxTextLength);
Locator.getInstance().getEditor().insert(Strings.generateRandomString(textLength), textLength); Locator.getInstance().getEditor().insert(Strings.generateRandomString(textLength), textLength);
} catch (Throwable e) { } catch (Throwable e) {
System.out.println(e); System.out.println(e);
error.set(true); error.set(true);
} finally { } finally {
finishLatch.countDown(); finishLatch.countDown();
} }
} }
} }
}).start(); }).start();
startLatchLatch.countDown(); startLatchLatch.countDown();
} }
if (finishLatch.await(60, TimeUnit.SECONDS)) { if (finishLatch.await(60, TimeUnit.SECONDS)) {
Assert.assertFalse(error.get()); Assert.assertFalse(error.get());
} else { } else {
Assert.fail("Too long execution!"); Assert.fail("Too long execution!");
} }
} }
} }

View File

@ -4,6 +4,7 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import org.hamcrest.BaseMatcher; import org.hamcrest.BaseMatcher;
import org.hamcrest.Description; import org.hamcrest.Description;
import org.junit.Before; import org.junit.Before;
@ -21,48 +22,50 @@ import static org.mockito.Mockito.verify;
import static org.robolectric.Robolectric.application; import static org.robolectric.Robolectric.application;
import static org.solovyev.android.calculator.CalculatorBroadcaster.ACTION_DISPLAY_STATE_CHANGED; import static org.solovyev.android.calculator.CalculatorBroadcaster.ACTION_DISPLAY_STATE_CHANGED;
import static org.solovyev.android.calculator.CalculatorBroadcaster.ACTION_EDITOR_STATE_CHANGED; import static org.solovyev.android.calculator.CalculatorBroadcaster.ACTION_EDITOR_STATE_CHANGED;
import static org.solovyev.android.calculator.CalculatorEventType.*; import static org.solovyev.android.calculator.CalculatorEventType.display_state_changed;
import static org.solovyev.android.calculator.CalculatorEventType.editor_state_changed;
import static org.solovyev.android.calculator.CalculatorEventType.editor_state_changed_light;
@Config(manifest = Config.NONE) @Config(manifest = Config.NONE)
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class CalculatorBroadcasterTest { public class CalculatorBroadcasterTest {
@Nonnull @Nonnull
private CalculatorBroadcaster broadcaster; private CalculatorBroadcaster broadcaster;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
broadcaster = new CalculatorBroadcaster(application, preferences); broadcaster = new CalculatorBroadcaster(application, preferences);
} }
@Test @Test
public void testShouldSendEditorStateChangedIntent() throws Exception { public void testShouldSendEditorStateChangedIntent() throws Exception {
assertIntentSent(editor_state_changed, ACTION_EDITOR_STATE_CHANGED); assertIntentSent(editor_state_changed, ACTION_EDITOR_STATE_CHANGED);
} }
@Test @Test
public void testShouldSendEditorStateChangedLiteIntent() throws Exception { public void testShouldSendEditorStateChangedLiteIntent() throws Exception {
assertIntentSent(editor_state_changed_light, ACTION_EDITOR_STATE_CHANGED); assertIntentSent(editor_state_changed_light, ACTION_EDITOR_STATE_CHANGED);
} }
@Test @Test
public void testShouldSendDisplayStateChangedIntent() throws Exception { public void testShouldSendDisplayStateChangedIntent() throws Exception {
assertIntentSent(display_state_changed, ACTION_DISPLAY_STATE_CHANGED); assertIntentSent(display_state_changed, ACTION_DISPLAY_STATE_CHANGED);
} }
private void assertIntentSent(@Nonnull CalculatorEventType eventType, final String expectedAction) { private void assertIntentSent(@Nonnull CalculatorEventType eventType, final String expectedAction) {
final BroadcastReceiver receiver = Mockito.mock(BroadcastReceiver.class); final BroadcastReceiver receiver = Mockito.mock(BroadcastReceiver.class);
application.registerReceiver(receiver, new IntentFilter(expectedAction)); application.registerReceiver(receiver, new IntentFilter(expectedAction));
broadcaster.onCalculatorEvent(CalculatorEventDataImpl.newInstance(1L, 1L), eventType, null); broadcaster.onCalculatorEvent(CalculatorEventDataImpl.newInstance(1L, 1L), eventType, null);
verify(receiver, times(1)).onReceive(Mockito.<Context>any(), argThat(new BaseMatcher<Intent>() { verify(receiver, times(1)).onReceive(Mockito.<Context>any(), argThat(new BaseMatcher<Intent>() {
@Override @Override
public boolean matches(Object o) { public boolean matches(Object o) {
return ((Intent) o).getAction().equals(expectedAction); return ((Intent) o).getAction().equals(expectedAction);
} }
@Override @Override
public void describeTo(Description description) { public void describeTo(Description description) {
} }
})); }));
} }
} }

View File

@ -1,41 +1,46 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.content.Intent; import android.content.Intent;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.robolectric.Robolectric.application; import static org.robolectric.Robolectric.application;
import static org.solovyev.android.calculator.CalculatorButton.four; import static org.solovyev.android.calculator.CalculatorButton.four;
import static org.solovyev.android.calculator.CalculatorReceiver.*; 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;
@Config(manifest = Config.NONE) @Config(manifest = Config.NONE)
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class CalculatorReceiverTest { public class CalculatorReceiverTest {
@Test @Test
public void testShouldPressButtonOnIntent() throws Exception { public void testShouldPressButtonOnIntent() throws Exception {
Locator.setKeyboard(mock(CalculatorKeyboard.class)); Locator.setKeyboard(mock(CalculatorKeyboard.class));
final Intent intent = newButtonClickedIntent(application, four); final Intent intent = newButtonClickedIntent(application, four);
new CalculatorReceiver().onReceive(application, intent); new CalculatorReceiver().onReceive(application, intent);
verify(Locator.getInstance().getKeyboard(), times(1)).buttonPressed(Mockito.anyString()); verify(Locator.getInstance().getKeyboard(), times(1)).buttonPressed(Mockito.anyString());
verify(Locator.getInstance().getKeyboard(), times(1)).buttonPressed("4"); verify(Locator.getInstance().getKeyboard(), times(1)).buttonPressed("4");
} }
@Test @Test
public void testShouldDoNothingIfButtonInvalid() throws Exception { public void testShouldDoNothingIfButtonInvalid() throws Exception {
Locator.setKeyboard(mock(CalculatorKeyboard.class)); Locator.setKeyboard(mock(CalculatorKeyboard.class));
final Intent intent = new Intent(application, CalculatorReceiver.class); final Intent intent = new Intent(application, CalculatorReceiver.class);
intent.setAction(ACTION_BUTTON_PRESSED); intent.setAction(ACTION_BUTTON_PRESSED);
intent.putExtra(ACTION_BUTTON_ID_EXTRA, "test!@"); intent.putExtra(ACTION_BUTTON_ID_EXTRA, "test!@");
new CalculatorReceiver().onReceive(application, intent); new CalculatorReceiver().onReceive(application, intent);
verify(Locator.getInstance().getKeyboard(), times(0)).buttonPressed(Mockito.anyString()); verify(Locator.getInstance().getKeyboard(), times(0)).buttonPressed(Mockito.anyString());
} }
} }

View File

@ -23,7 +23,6 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.content.Context; import android.content.Context;
import jscl.JsclMathEngine;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.solovyev.android.calculator.history.CalculatorHistory; import org.solovyev.android.calculator.history.CalculatorHistory;
@ -32,6 +31,8 @@ import org.solovyev.android.calculator.plot.CalculatorPlotter;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import jscl.JsclMathEngine;
/** /**
* User: serso * User: serso
* Date: 10/7/12 * Date: 10/7/12
@ -39,41 +40,41 @@ import javax.annotation.Nullable;
*/ */
public class CalculatorTestUtils { public class CalculatorTestUtils {
public static void staticSetUp(@Nullable Context context) throws Exception { public static void staticSetUp(@Nullable Context context) throws Exception {
Locator.getInstance().init(new CalculatorImpl(), newCalculatorEngine(), Mockito.mock(CalculatorClipboard.class), Mockito.mock(CalculatorNotifier.class), Mockito.mock(CalculatorHistory.class), new SystemOutCalculatorLogger(), Mockito.mock(CalculatorPreferenceService.class), Mockito.mock(CalculatorKeyboard.class), Mockito.mock(CalculatorPlotter.class), null); Locator.getInstance().init(new CalculatorImpl(), newCalculatorEngine(), Mockito.mock(CalculatorClipboard.class), Mockito.mock(CalculatorNotifier.class), Mockito.mock(CalculatorHistory.class), new SystemOutCalculatorLogger(), Mockito.mock(CalculatorPreferenceService.class), Mockito.mock(CalculatorKeyboard.class), Mockito.mock(CalculatorPlotter.class), null);
Locator.getInstance().getEngine().init(); Locator.getInstance().getEngine().init();
if (context != null) { if (context != null) {
initViews(context); initViews(context);
} }
} }
public static void initViews(@Nonnull Context context) { public static void initViews(@Nonnull Context context) {
final AndroidCalculatorEditorView editor = new AndroidCalculatorEditorView(context); final AndroidCalculatorEditorView editor = new AndroidCalculatorEditorView(context);
editor.init(); editor.init();
Locator.getInstance().getEditor().setView(editor); Locator.getInstance().getEditor().setView(editor);
final AndroidCalculatorDisplayView display = new AndroidCalculatorDisplayView(context); final AndroidCalculatorDisplayView display = new AndroidCalculatorDisplayView(context);
display.init(context); display.init(context);
Locator.getInstance().getDisplay().setView(display); Locator.getInstance().getDisplay().setView(display);
} }
public static void staticSetUp() throws Exception { public static void staticSetUp() throws Exception {
staticSetUp(null); staticSetUp(null);
} }
@Nonnull @Nonnull
static CalculatorEngineImpl newCalculatorEngine() { static CalculatorEngineImpl newCalculatorEngine() {
final MathEntityDao mathEntityDao = Mockito.mock(MathEntityDao.class); final MathEntityDao mathEntityDao = Mockito.mock(MathEntityDao.class);
final JsclMathEngine jsclEngine = JsclMathEngine.getInstance(); final JsclMathEngine jsclEngine = JsclMathEngine.getInstance();
final CalculatorVarsRegistry varsRegistry = new CalculatorVarsRegistry(jsclEngine.getConstantsRegistry(), mathEntityDao); final CalculatorVarsRegistry varsRegistry = new CalculatorVarsRegistry(jsclEngine.getConstantsRegistry(), mathEntityDao);
final CalculatorFunctionsMathRegistry functionsRegistry = new CalculatorFunctionsMathRegistry(jsclEngine.getFunctionsRegistry(), mathEntityDao); final CalculatorFunctionsMathRegistry functionsRegistry = new CalculatorFunctionsMathRegistry(jsclEngine.getFunctionsRegistry(), mathEntityDao);
final CalculatorOperatorsMathRegistry operatorsRegistry = new CalculatorOperatorsMathRegistry(jsclEngine.getOperatorsRegistry(), mathEntityDao); final CalculatorOperatorsMathRegistry operatorsRegistry = new CalculatorOperatorsMathRegistry(jsclEngine.getOperatorsRegistry(), mathEntityDao);
final CalculatorPostfixFunctionsRegistry postfixFunctionsRegistry = new CalculatorPostfixFunctionsRegistry(jsclEngine.getPostfixFunctionsRegistry(), mathEntityDao); final CalculatorPostfixFunctionsRegistry postfixFunctionsRegistry = new CalculatorPostfixFunctionsRegistry(jsclEngine.getPostfixFunctionsRegistry(), mathEntityDao);
return new CalculatorEngineImpl(jsclEngine, varsRegistry, functionsRegistry, operatorsRegistry, postfixFunctionsRegistry, null); return new CalculatorEngineImpl(jsclEngine, varsRegistry, functionsRegistry, operatorsRegistry, postfixFunctionsRegistry, null);
} }
} }

View File

@ -23,8 +23,6 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.graphics.Color; import android.graphics.Color;
import jscl.MathEngine;
import jscl.NumeralBase;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -34,6 +32,9 @@ import org.solovyev.android.calculator.view.TextHighlighter;
import java.util.Date; import java.util.Date;
import java.util.Random; import java.util.Random;
import jscl.MathEngine;
import jscl.NumeralBase;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@ -45,152 +46,152 @@ import static org.junit.Assert.assertTrue;
*/ */
public class TextHighlighterTest { public class TextHighlighterTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
CalculatorTestUtils.staticSetUp(); CalculatorTestUtils.staticSetUp();
} }
@Test @Test
public void testProcess() throws Exception { public void testProcess() throws Exception {
TextProcessor<?, String> textHighlighter = new TextHighlighter(Color.TRANSPARENT, false); TextProcessor<?, String> textHighlighter = new TextHighlighter(Color.TRANSPARENT, false);
final Random random = new Random(new Date().getTime()); final Random random = new Random(new Date().getTime());
for (int i = 0; i < 1000; i++) { for (int i = 0; i < 1000; i++) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
for (int j = 0; j < 1000; j++) { for (int j = 0; j < 1000; j++) {
sb.append(random.nextBoolean() ? "(" : ")"); sb.append(random.nextBoolean() ? "(" : ")");
} }
try { try {
textHighlighter.process(sb.toString()); textHighlighter.process(sb.toString());
} catch (Exception e) { } catch (Exception e) {
System.out.println(sb.toString()); System.out.println(sb.toString());
throw e; throw e;
} }
} }
assertEquals("<font color=\"#000000\"></font>)(((())())", textHighlighter.process(")(((())())").toString()); assertEquals("<font color=\"#000000\"></font>)(((())())", textHighlighter.process(")(((())())").toString());
assertEquals(")", textHighlighter.process(")").toString()); assertEquals(")", textHighlighter.process(")").toString());
assertEquals(")()(", textHighlighter.process(")()(").toString()); assertEquals(")()(", textHighlighter.process(")()(").toString());
textHighlighter = new TextHighlighter(0, true); textHighlighter = new TextHighlighter(0, true);
assertEquals("1 000 000", textHighlighter.process("1000000").toString()); assertEquals("1 000 000", textHighlighter.process("1000000").toString());
assertEquals("1 000 000", textHighlighter.process("1000000").toString()); assertEquals("1 000 000", textHighlighter.process("1000000").toString());
assertEquals("0.1E3", textHighlighter.process("0.1E3").toString()); assertEquals("0.1E3", textHighlighter.process("0.1E3").toString());
assertEquals("1E3", textHighlighter.process("1E3").toString()); assertEquals("1E3", textHighlighter.process("1E3").toString());
assertEquals("2<b>0x:</b>", textHighlighter.process("20x:").toString()); assertEquals("2<b>0x:</b>", textHighlighter.process("20x:").toString());
assertEquals("20g", textHighlighter.process("20g").toString()); assertEquals("20g", textHighlighter.process("20g").toString());
assertEquals("22g", textHighlighter.process("22g").toString()); assertEquals("22g", textHighlighter.process("22g").toString());
assertEquals("20ю", textHighlighter.process("20ю").toString()); assertEquals("20ю", textHighlighter.process("20ю").toString());
assertEquals("20ъ", textHighlighter.process("20ъ").toString()); assertEquals("20ъ", textHighlighter.process("20ъ").toString());
assertEquals("3!!", textHighlighter.process("3!!").toString()); assertEquals("3!!", textHighlighter.process("3!!").toString());
assertEquals("2", textHighlighter.process("2").toString()); assertEquals("2", textHighlighter.process("2").toString());
assertEquals("21", textHighlighter.process("21").toString()); assertEquals("21", textHighlighter.process("21").toString());
assertEquals("214", textHighlighter.process("214").toString()); assertEquals("214", textHighlighter.process("214").toString());
assertEquals("2 145", textHighlighter.process("2 145").toString()); assertEquals("2 145", textHighlighter.process("2 145").toString());
assertEquals("1 000 000E3", textHighlighter.process("1000000E3").toString()); assertEquals("1 000 000E3", textHighlighter.process("1000000E3").toString());
assertEquals("-1 000 000E3", textHighlighter.process("-1000000E3").toString()); assertEquals("-1 000 000E3", textHighlighter.process("-1000000E3").toString());
assertEquals("-1 000 000E-3", textHighlighter.process("-1000000E-3").toString()); assertEquals("-1 000 000E-3", textHighlighter.process("-1000000E-3").toString());
assertEquals("-1 000 000E-30000", textHighlighter.process("-1000000E-30000").toString()); assertEquals("-1 000 000E-30000", textHighlighter.process("-1000000E-30000").toString());
textHighlighter = new TextHighlighter(0, false); textHighlighter = new TextHighlighter(0, false);
textHighlighter.process("cannot calculate 3^10^10 !!!\n" + textHighlighter.process("cannot calculate 3^10^10 !!!\n" +
" unable to enter 0. FIXED\n" + " unable to enter 0. FIXED\n" +
" empty display in Xperia Rayo\n" + " empty display in Xperia Rayo\n" +
" check привиденная FIXED\n" + " check привиденная FIXED\n" +
" set display result only if text in editor was not changed FIXED\n" + " set display result only if text in editor was not changed FIXED\n" +
" shift M text to the left\n" + " shift M text to the left\n" +
" do not show SYNTAX ERROR always (may be show send clock?q) FIXED\n" + " do not show SYNTAX ERROR always (may be show send clock?q) FIXED\n" +
" ln(8)*log(8) => ln(8)*og(8) FIXED\n" + " ln(8)*log(8) => ln(8)*og(8) FIXED\n" +
" copy/paste ln(8)*log(8)\n" + " copy/paste ln(8)*log(8)\n" +
" 6!^2 ERROR"); " 6!^2 ERROR");
assertEquals("<font color=\"#000000\"><i>sin</i>(</font><font color=\"#ffff9a\">2</font><font color=\"#000000\">)</font>", textHighlighter.process("sin(2)").toString()); assertEquals("<font color=\"#000000\"><i>sin</i>(</font><font color=\"#ffff9a\">2</font><font color=\"#000000\">)</font>", textHighlighter.process("sin(2)").toString());
assertEquals("<font color=\"#000000\"><i>atanh</i>(</font><font color=\"#ffff9a\">2</font><font color=\"#000000\">)</font>", textHighlighter.process("atanh(2)").toString()); assertEquals("<font color=\"#000000\"><i>atanh</i>(</font><font color=\"#ffff9a\">2</font><font color=\"#000000\">)</font>", textHighlighter.process("atanh(2)").toString());
assertEquals("<b>0x:</b>E", textHighlighter.process("0x:E").toString()); assertEquals("<b>0x:</b>E", textHighlighter.process("0x:E").toString());
assertEquals("<b>0x:</b>6F", textHighlighter.process("0x:6F").toString()); assertEquals("<b>0x:</b>6F", textHighlighter.process("0x:6F").toString());
assertEquals("<b>0x:</b>6F.", textHighlighter.process("0x:6F.").toString()); assertEquals("<b>0x:</b>6F.", textHighlighter.process("0x:6F.").toString());
assertEquals("<b>0x:</b>6F.2", textHighlighter.process("0x:6F.2").toString()); assertEquals("<b>0x:</b>6F.2", textHighlighter.process("0x:6F.2").toString());
assertEquals("<b>0x:</b>6F.B", textHighlighter.process("0x:6F.B").toString()); assertEquals("<b>0x:</b>6F.B", textHighlighter.process("0x:6F.B").toString());
assertEquals("<b>0x:</b>006F.B", textHighlighter.process("0x:006F.B").toString()); assertEquals("<b>0x:</b>006F.B", textHighlighter.process("0x:006F.B").toString());
assertEquals("<b>0x:</b>0", textHighlighter.process("0x:0").toString()); assertEquals("<b>0x:</b>0", textHighlighter.process("0x:0").toString());
assertEquals("<b>0x:</b>FF33233FFE", textHighlighter.process("0x:FF33233FFE").toString()); assertEquals("<b>0x:</b>FF33233FFE", textHighlighter.process("0x:FF33233FFE").toString());
assertEquals("<b>0x:</b>FF33 233 FFE", textHighlighter.process("0x:FF33 233 FFE").toString()); assertEquals("<b>0x:</b>FF33 233 FFE", textHighlighter.process("0x:FF33 233 FFE").toString());
final MathEngine me = Locator.getInstance().getEngine().getMathEngine0(); final MathEngine me = Locator.getInstance().getEngine().getMathEngine0();
try { try {
me.setNumeralBase(NumeralBase.hex); me.setNumeralBase(NumeralBase.hex);
assertEquals("E", textHighlighter.process("E").toString()); assertEquals("E", textHighlighter.process("E").toString());
assertEquals(".E", textHighlighter.process(".E").toString()); assertEquals(".E", textHighlighter.process(".E").toString());
assertEquals("E+", textHighlighter.process("E+").toString()); assertEquals("E+", textHighlighter.process("E+").toString());
assertEquals("E.", textHighlighter.process("E.").toString()); assertEquals("E.", textHighlighter.process("E.").toString());
assertEquals(".E.", textHighlighter.process(".E.").toString()); assertEquals(".E.", textHighlighter.process(".E.").toString());
assertEquals("6F", textHighlighter.process("6F").toString()); assertEquals("6F", textHighlighter.process("6F").toString());
assertEquals("6F", textHighlighter.process("6F").toString()); assertEquals("6F", textHighlighter.process("6F").toString());
assertEquals("6F.", textHighlighter.process("6F.").toString()); assertEquals("6F.", textHighlighter.process("6F.").toString());
assertEquals("6F.2", textHighlighter.process("6F.2").toString()); assertEquals("6F.2", textHighlighter.process("6F.2").toString());
assertEquals("6F.B", textHighlighter.process("6F.B").toString()); assertEquals("6F.B", textHighlighter.process("6F.B").toString());
assertEquals("006F.B", textHighlighter.process("006F.B").toString()); assertEquals("006F.B", textHighlighter.process("006F.B").toString());
} finally { } finally {
me.setNumeralBase(NumeralBase.dec); me.setNumeralBase(NumeralBase.dec);
} }
assertEquals("<b>0b:</b>110101", textHighlighter.process("0b:110101").toString()); assertEquals("<b>0b:</b>110101", textHighlighter.process("0b:110101").toString());
assertEquals("<b>0b:</b>110101.", textHighlighter.process("0b:110101.").toString()); assertEquals("<b>0b:</b>110101.", textHighlighter.process("0b:110101.").toString());
assertEquals("<b>0b:</b>110101.101", textHighlighter.process("0b:110101.101").toString()); assertEquals("<b>0b:</b>110101.101", textHighlighter.process("0b:110101.101").toString());
assertEquals("<b>0b:</b>11010100.1", textHighlighter.process("0b:11010100.1").toString()); assertEquals("<b>0b:</b>11010100.1", textHighlighter.process("0b:11010100.1").toString());
assertEquals("<b>0b:</b>110101.0", textHighlighter.process("0b:110101.0").toString()); assertEquals("<b>0b:</b>110101.0", textHighlighter.process("0b:110101.0").toString());
assertEquals("<b>0b:</b>0", textHighlighter.process("0b:0").toString()); assertEquals("<b>0b:</b>0", textHighlighter.process("0b:0").toString());
assertEquals("<b>0b:</b>1010100101111010101001", textHighlighter.process("0b:1010100101111010101001").toString()); assertEquals("<b>0b:</b>1010100101111010101001", textHighlighter.process("0b:1010100101111010101001").toString());
assertEquals("<b>0b:</b>101 010 01 0 111 1 0 10101001", textHighlighter.process("0b:101 010 01 0 111 1 0 10101001").toString()); assertEquals("<b>0b:</b>101 010 01 0 111 1 0 10101001", textHighlighter.process("0b:101 010 01 0 111 1 0 10101001").toString());
try { try {
me.setNumeralBase(NumeralBase.bin); me.setNumeralBase(NumeralBase.bin);
assertEquals("110101", textHighlighter.process("110101").toString()); assertEquals("110101", textHighlighter.process("110101").toString());
assertEquals("110101.", textHighlighter.process("110101.").toString()); assertEquals("110101.", textHighlighter.process("110101.").toString());
assertEquals("110101.101", textHighlighter.process("110101.101").toString()); assertEquals("110101.101", textHighlighter.process("110101.101").toString());
assertEquals("11010100.1", textHighlighter.process("11010100.1").toString()); assertEquals("11010100.1", textHighlighter.process("11010100.1").toString());
assertEquals("110101.0", textHighlighter.process("110101.0").toString()); assertEquals("110101.0", textHighlighter.process("110101.0").toString());
assertEquals("0", textHighlighter.process("0").toString()); assertEquals("0", textHighlighter.process("0").toString());
assertEquals("1010100101111010101001", textHighlighter.process("1010100101111010101001").toString()); assertEquals("1010100101111010101001", textHighlighter.process("1010100101111010101001").toString());
assertEquals("101 010 01 0 111 1 0 10101001", textHighlighter.process("101 010 01 0 111 1 0 10101001").toString()); assertEquals("101 010 01 0 111 1 0 10101001", textHighlighter.process("101 010 01 0 111 1 0 10101001").toString());
} finally { } finally {
me.setNumeralBase(NumeralBase.dec); me.setNumeralBase(NumeralBase.dec);
} }
} }
@Test @Test
public void testTime() throws Exception { public void testTime() throws Exception {
final TextProcessor<?, String> textHighlighter = new TextHighlighter(Color.WHITE, false); final TextProcessor<?, String> textHighlighter = new TextHighlighter(Color.WHITE, false);
final int count = 1000; final int count = 1000;
final String subExpression = "cos(acos(t8ln(t5t85tln(8ln(5t55tln(5))))))+tln(88cos(tln(t)))+t√(ln(t))"; final String subExpression = "cos(acos(t8ln(t5t85tln(8ln(5t55tln(5))))))+tln(88cos(tln(t)))+t√(ln(t))";
final StringBuilder expression = new StringBuilder(subExpression.length() * count); final StringBuilder expression = new StringBuilder(subExpression.length() * count);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
expression.append(subExpression); expression.append(subExpression);
expression.append("+"); expression.append("+");
} }
expression.append(subExpression); expression.append(subExpression);
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
textHighlighter.process(expression.toString()); textHighlighter.process(expression.toString());
long endTime = System.currentTimeMillis(); long endTime = System.currentTimeMillis();
System.out.println("Total time, ms: " + (endTime - startTime)); System.out.println("Total time, ms: " + (endTime - startTime));
} }
@Test @Test
public void testDarkColor() throws Exception { public void testDarkColor() throws Exception {
final TextProcessor<?, String> textHighlighter = new TextHighlighter(Color.BLACK, false); final TextProcessor<?, String> textHighlighter = new TextHighlighter(Color.BLACK, false);
assertEquals("", textHighlighter.process("sin(2cos(3))")); assertEquals("", textHighlighter.process("sin(2cos(3))"));
} }
@Test @Test
public void testIsDark() throws Exception { public void testIsDark() throws Exception {
assertFalse(TextHighlighter.isDark(Color.WHITE)); assertFalse(TextHighlighter.isDark(Color.WHITE));
assertFalse(TextHighlighter.isDark(Color.LTGRAY)); assertFalse(TextHighlighter.isDark(Color.LTGRAY));
assertTrue(TextHighlighter.isDark(Color.DKGRAY)); assertTrue(TextHighlighter.isDark(Color.DKGRAY));
assertTrue(TextHighlighter.isDark(Color.BLACK)); assertTrue(TextHighlighter.isDark(Color.BLACK));
} }
} }

View File

@ -47,163 +47,161 @@ import static org.junit.Assert.assertEquals;
*/ */
public class HistoryUtilsTest { public class HistoryUtilsTest {
@Test private static final String emptyHistory = "<history>\n" +
public void testFromXml() throws Exception { " <historyItems class=\"java.util.ArrayList\"/>\n" +
"</history>";
private static final String toXml1 = "<history>\n" +
" <historyItems class=\"java.util.ArrayList\">\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>3</cursorPosition>\n" +
" <text>1+1</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>0</cursorPosition>\n" +
" <text>Error</text>\n" +
" </editorState>\n" +
" <jsclOperation>simplify</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" </historyItems>\n" +
"</history>";
private static final String toXml2 = "<history>\n" +
" <historyItems class=\"java.util.ArrayList\">\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>3</cursorPosition>\n" +
" <text>1+1</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>0</cursorPosition>\n" +
" <text>Error</text>\n" +
" </editorState>\n" +
" <jsclOperation>simplify</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>2</cursorPosition>\n" +
" <text>5/6</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>3</cursorPosition>\n" +
" <text>5/6</text>\n" +
" </editorState>\n" +
" <jsclOperation>numeric</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>1</cursorPosition>\n" +
" <text></text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>0</cursorPosition>\n" +
" <text>Error</text>\n" +
" </editorState>\n" +
" <jsclOperation>elementary</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>0</cursorPosition>\n" +
" <text>4+5/35sin(41)+dfdsfsdfs</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>1</cursorPosition>\n" +
" <text>4+5/35sin(41)+dfdsfsdfs</text>\n" +
" </editorState>\n" +
" <jsclOperation>numeric</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" </historyItems>\n" +
"</history>";
} @Test
public void testFromXml() throws Exception {
private static final String emptyHistory = "<history>\n" + }
" <historyItems class=\"java.util.ArrayList\"/>\n" +
"</history>";
private static final String toXml1 = "<history>\n" + @Test
" <historyItems class=\"java.util.ArrayList\">\n" + public void testToXml() throws Exception {
" <calculatorHistoryState>\n" + final Date date = new Date(100000000);
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>3</cursorPosition>\n" +
" <text>1+1</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>0</cursorPosition>\n" +
" <text>Error</text>\n" +
" </editorState>\n" +
" <jsclOperation>simplify</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" </historyItems>\n" +
"</history>";
private static final String toXml2 = "<history>\n" + HistoryHelper<CalculatorHistoryState> history = SimpleHistoryHelper.newInstance();
" <historyItems class=\"java.util.ArrayList\">\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>3</cursorPosition>\n" +
" <text>1+1</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>0</cursorPosition>\n" +
" <text>Error</text>\n" +
" </editorState>\n" +
" <jsclOperation>simplify</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>2</cursorPosition>\n" +
" <text>5/6</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>3</cursorPosition>\n" +
" <text>5/6</text>\n" +
" </editorState>\n" +
" <jsclOperation>numeric</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>1</cursorPosition>\n" +
" <text></text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>0</cursorPosition>\n" +
" <text>Error</text>\n" +
" </editorState>\n" +
" <jsclOperation>elementary</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" <calculatorHistoryState>\n" +
" <time>100000000</time>\n" +
" <editorState>\n" +
" <cursorPosition>0</cursorPosition>\n" +
" <text>4+5/35sin(41)+dfdsfsdfs</text>\n" +
" </editorState>\n" +
" <displayState>\n" +
" <editorState>\n" +
" <cursorPosition>1</cursorPosition>\n" +
" <text>4+5/35sin(41)+dfdsfsdfs</text>\n" +
" </editorState>\n" +
" <jsclOperation>numeric</jsclOperation>\n" +
" </displayState>\n" +
" </calculatorHistoryState>\n" +
" </historyItems>\n" +
"</history>";
@Test CalculatorDisplayViewState calculatorDisplay = CalculatorDisplayViewStateImpl.newErrorState(JsclOperation.simplify, "Error");
public void testToXml() throws Exception {
final Date date = new Date(100000000);
HistoryHelper<CalculatorHistoryState> history = SimpleHistoryHelper.newInstance(); CalculatorEditorViewState calculatorEditor = CalculatorEditorViewStateImpl.newInstance("1+1", 3);
CalculatorDisplayViewState calculatorDisplay = CalculatorDisplayViewStateImpl.newErrorState(JsclOperation.simplify, "Error"); CalculatorHistoryState state = CalculatorHistoryState.newInstance(calculatorEditor, calculatorDisplay);
state.setTime(date.getTime());
history.addState(state);
CalculatorEditorViewState calculatorEditor = CalculatorEditorViewStateImpl.newInstance("1+1", 3); assertEquals(emptyHistory, HistoryUtils.toXml(history.getStates()));
CalculatorHistoryState state = CalculatorHistoryState.newInstance(calculatorEditor, calculatorDisplay);
state.setTime(date.getTime());
history.addState(state);
assertEquals(emptyHistory, HistoryUtils.toXml(history.getStates()));
state.setSaved(true); state.setSaved(true);
assertEquals(toXml1, HistoryUtils.toXml(history.getStates())); assertEquals(toXml1, HistoryUtils.toXml(history.getStates()));
calculatorDisplay = CalculatorDisplayViewStateImpl.newValidState(JsclOperation.numeric, null, "5/6", 3); calculatorDisplay = CalculatorDisplayViewStateImpl.newValidState(JsclOperation.numeric, null, "5/6", 3);
calculatorEditor = CalculatorEditorViewStateImpl.newInstance("5/6", 2); calculatorEditor = CalculatorEditorViewStateImpl.newInstance("5/6", 2);
state = CalculatorHistoryState.newInstance(calculatorEditor, calculatorDisplay); state = CalculatorHistoryState.newInstance(calculatorEditor, calculatorDisplay);
state.setSaved(true); state.setSaved(true);
state.setTime(date.getTime()); state.setTime(date.getTime());
history.addState(state); history.addState(state);
calculatorDisplay = CalculatorDisplayViewStateImpl.newErrorState(JsclOperation.elementary, "Error"); calculatorDisplay = CalculatorDisplayViewStateImpl.newErrorState(JsclOperation.elementary, "Error");
calculatorEditor = CalculatorEditorViewStateImpl.newInstance("", 1); calculatorEditor = CalculatorEditorViewStateImpl.newInstance("", 1);
state = CalculatorHistoryState.newInstance(calculatorEditor, calculatorDisplay); state = CalculatorHistoryState.newInstance(calculatorEditor, calculatorDisplay);
state.setSaved(true); state.setSaved(true);
state.setTime(date.getTime()); state.setTime(date.getTime());
history.addState(state); history.addState(state);
calculatorDisplay = CalculatorDisplayViewStateImpl.newValidState(JsclOperation.numeric, null, "4+5/35sin(41)+dfdsfsdfs", 1); calculatorDisplay = CalculatorDisplayViewStateImpl.newValidState(JsclOperation.numeric, null, "4+5/35sin(41)+dfdsfsdfs", 1);
calculatorEditor = CalculatorEditorViewStateImpl.newInstance("4+5/35sin(41)+dfdsfsdfs", 0); calculatorEditor = CalculatorEditorViewStateImpl.newInstance("4+5/35sin(41)+dfdsfsdfs", 0);
state = CalculatorHistoryState.newInstance(calculatorEditor, calculatorDisplay); state = CalculatorHistoryState.newInstance(calculatorEditor, calculatorDisplay);
state.setSaved(true); state.setSaved(true);
state.setTime(date.getTime()); state.setTime(date.getTime());
history.addState(state); history.addState(state);
String xml = HistoryUtils.toXml(history.getStates()); String xml = HistoryUtils.toXml(history.getStates());
assertEquals(toXml2, xml); assertEquals(toXml2, xml);
final List<CalculatorHistoryState> fromXml = new ArrayList<CalculatorHistoryState>(); final List<CalculatorHistoryState> fromXml = new ArrayList<CalculatorHistoryState>();
final HistoryHelper<CalculatorHistoryState> historyFromXml = SimpleHistoryHelper.newInstance(); final HistoryHelper<CalculatorHistoryState> historyFromXml = SimpleHistoryHelper.newInstance();
HistoryUtils.fromXml(xml, fromXml); HistoryUtils.fromXml(xml, fromXml);
for (CalculatorHistoryState historyState : fromXml) { for (CalculatorHistoryState historyState : fromXml) {
historyFromXml.addState(historyState); historyFromXml.addState(historyState);
} }
assertEquals(history.getStates().size(), historyFromXml.getStates().size()); assertEquals(history.getStates().size(), historyFromXml.getStates().size());
for (CalculatorHistoryState historyState : history.getStates()) { for (CalculatorHistoryState historyState : history.getStates()) {
historyState.setId(0); historyState.setId(0);
historyState.setSaved(true); historyState.setSaved(true);
} }
for (CalculatorHistoryState historyState : historyFromXml.getStates()) { for (CalculatorHistoryState historyState : historyFromXml.getStates()) {
historyState.setId(0); historyState.setId(0);
historyState.setSaved(true); historyState.setSaved(true);
} }
Assert.assertTrue(Objects.areEqual(history.getStates(), historyFromXml.getStates(), new CollectionEqualizer<CalculatorHistoryState>(null))); Assert.assertTrue(Objects.areEqual(history.getStates(), historyFromXml.getStates(), new CollectionEqualizer<CalculatorHistoryState>(null)));
} }
} }

View File

@ -22,14 +22,14 @@
package org.solovyev.android.calculator.model; package org.solovyev.android.calculator.model;
import jscl.math.function.IConstant;
import org.junit.Test; import org.junit.Test;
import org.simpleframework.xml.Serializer; import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister; import org.simpleframework.xml.core.Persister;
import java.io.StringWriter; import java.io.StringWriter;
import jscl.math.function.IConstant;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
/** /**
@ -39,48 +39,48 @@ import static org.junit.Assert.assertEquals;
*/ */
public class VarTest { public class VarTest {
private static final String xml = "<vars>\n" + private static final String xml = "<vars>\n" +
" <vars class=\"java.util.ArrayList\">\n" + " <vars class=\"java.util.ArrayList\">\n" +
" <var>\n" + " <var>\n" +
" <name>e</name>\n" + " <name>e</name>\n" +
" <value>2.718281828459045</value>\n" + " <value>2.718281828459045</value>\n" +
" <system>true</system>\n" + " <system>true</system>\n" +
" <description>description</description>\n" + " <description>description</description>\n" +
" </var>\n" + " </var>\n" +
" <var>\n" + " <var>\n" +
" <name>;</name>\n" + " <name>;</name>\n" +
" <value>3.0</value>\n" + " <value>3.0</value>\n" +
" <system>true</system>\n" + " <system>true</system>\n" +
" </var>\n" + " </var>\n" +
" </vars>\n" + " </vars>\n" +
"</vars>"; "</vars>";
@Test @Test
public void testXml() throws Exception { public void testXml() throws Exception {
final Vars vars = new Vars(); final Vars vars = new Vars();
Var first = new Var.Builder("e", Math.E).setDescription("description").setSystem(true).create(); Var first = new Var.Builder("e", Math.E).setDescription("description").setSystem(true).create();
vars.getEntities().add(first); vars.getEntities().add(first);
Var second = new Var.Builder(";", 3d).setSystem(true).create(); Var second = new Var.Builder(";", 3d).setSystem(true).create();
vars.getEntities().add(second); vars.getEntities().add(second);
final StringWriter sw = new StringWriter(); final StringWriter sw = new StringWriter();
final Serializer serializer = new Persister(); final Serializer serializer = new Persister();
serializer.write(vars, sw); serializer.write(vars, sw);
assertEquals(xml, sw.toString()); assertEquals(xml, sw.toString());
final Vars result = serializer.read(Vars.class, xml); final Vars result = serializer.read(Vars.class, xml);
final IConstant actualFirst = result.getEntities().get(0); final IConstant actualFirst = result.getEntities().get(0);
final IConstant actualSecond = result.getEntities().get(1); final IConstant actualSecond = result.getEntities().get(1);
areEqual(first, actualFirst); areEqual(first, actualFirst);
areEqual(second, actualSecond); areEqual(second, actualSecond);
} }
private void areEqual(IConstant expected, IConstant actual) { private void areEqual(IConstant expected, IConstant actual) {
assertEquals(expected.getName(), actual.getName()); assertEquals(expected.getName(), actual.getName());
assertEquals(expected.getDescription(), actual.getDescription()); assertEquals(expected.getDescription(), actual.getDescription());
assertEquals(expected.getValue(), actual.getValue()); assertEquals(expected.getValue(), actual.getValue());
} }
} }

View File

@ -36,28 +36,28 @@ import static org.junit.Assert.assertEquals;
*/ */
public class CalculatorGraph2dViewTest { public class CalculatorGraph2dViewTest {
@Test @Test
public void testFormatTick() throws Exception { public void testFormatTick() throws Exception {
assertEquals("23324", CalculatorGraph2dView.formatTick(23324.0f, 0)); assertEquals("23324", CalculatorGraph2dView.formatTick(23324.0f, 0));
final DecimalFormat format = (DecimalFormat) DecimalFormat.getInstance(); final DecimalFormat format = (DecimalFormat) DecimalFormat.getInstance();
final DecimalFormatSymbols decimalFormatSymbols = format.getDecimalFormatSymbols(); final DecimalFormatSymbols decimalFormatSymbols = format.getDecimalFormatSymbols();
if (',' == decimalFormatSymbols.getDecimalSeparator()) { if (',' == decimalFormatSymbols.getDecimalSeparator()) {
assertEquals("23324,1", CalculatorGraph2dView.formatTick(23324.1f, 1)); assertEquals("23324,1", CalculatorGraph2dView.formatTick(23324.1f, 1));
} else if ('.' == decimalFormatSymbols.getDecimalSeparator()) { } else if ('.' == decimalFormatSymbols.getDecimalSeparator()) {
assertEquals("23324.1", CalculatorGraph2dView.formatTick(23324.1f, 1)); assertEquals("23324.1", CalculatorGraph2dView.formatTick(23324.1f, 1));
} }
} }
@Test @Test
public void testCountTickDigits() throws Exception { public void testCountTickDigits() throws Exception {
assertEquals(0, CalculatorGraph2dView.countTickDigits(1)); assertEquals(0, CalculatorGraph2dView.countTickDigits(1));
assertEquals(0, CalculatorGraph2dView.countTickDigits(10)); assertEquals(0, CalculatorGraph2dView.countTickDigits(10));
assertEquals(0, CalculatorGraph2dView.countTickDigits(100)); assertEquals(0, CalculatorGraph2dView.countTickDigits(100));
assertEquals(1, CalculatorGraph2dView.countTickDigits(0.9f)); assertEquals(1, CalculatorGraph2dView.countTickDigits(0.9f));
assertEquals(1, CalculatorGraph2dView.countTickDigits(0.2f)); assertEquals(1, CalculatorGraph2dView.countTickDigits(0.2f));
assertEquals(1, CalculatorGraph2dView.countTickDigits(0.1f)); assertEquals(1, CalculatorGraph2dView.countTickDigits(0.1f));
assertEquals(2, CalculatorGraph2dView.countTickDigits(0.099f)); assertEquals(2, CalculatorGraph2dView.countTickDigits(0.099f));
assertEquals(3, CalculatorGraph2dView.countTickDigits(0.009f)); assertEquals(3, CalculatorGraph2dView.countTickDigits(0.009f));
} }
} }

View File

@ -1,6 +1,7 @@
package org.solovyev.android.calculator.view; package org.solovyev.android.calculator.view;
import android.app.Activity; import android.app.Activity;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -12,8 +13,14 @@ import org.robolectric.shadows.ShadowActivity;
import java.util.ArrayList; import java.util.ArrayList;
import static jscl.AngleUnit.*; import static jscl.AngleUnit.deg;
import static org.junit.Assert.*; import static jscl.AngleUnit.grad;
import static jscl.AngleUnit.rad;
import static jscl.AngleUnit.turns;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.solovyev.android.calculator.CalculatorTestUtils.staticSetUp; import static org.solovyev.android.calculator.CalculatorTestUtils.staticSetUp;
@ -21,46 +28,46 @@ import static org.solovyev.android.calculator.CalculatorTestUtils.staticSetUp;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class AngleUnitsButtonTest { public class AngleUnitsButtonTest {
private AngleUnitsButton button; private AngleUnitsButton button;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
staticSetUp(); staticSetUp();
final Activity context = Robolectric.buildActivity(Activity.class).create().get(); final Activity context = Robolectric.buildActivity(Activity.class).create().get();
final ShadowActivity activity = Robolectric.shadowOf(context); final ShadowActivity activity = Robolectric.shadowOf(context);
button = new AngleUnitsButton(context, activity.createAttributeSet(new ArrayList<Attribute>(), AngleUnitsButton.class)); button = new AngleUnitsButton(context, activity.createAttributeSet(new ArrayList<Attribute>(), AngleUnitsButton.class));
} }
@Test @Test
public void testShouldReturnDifferentColorsForDifferentAngleUnits() throws Exception { public void testShouldReturnDifferentColorsForDifferentAngleUnits() throws Exception {
button.setAngleUnit(deg); button.setAngleUnit(deg);
assertEquals(button.getDirectionTextColor(deg.name()), button.getDirectionTextColor(deg.name())); assertEquals(button.getDirectionTextColor(deg.name()), button.getDirectionTextColor(deg.name()));
assertEquals(button.getDirectionTextColor(grad.name()), button.getDirectionTextColor(rad.name())); assertEquals(button.getDirectionTextColor(grad.name()), button.getDirectionTextColor(rad.name()));
assertNotSame(button.getDirectionTextColor(deg.name()), button.getDirectionTextColor(rad.name())); assertNotSame(button.getDirectionTextColor(deg.name()), button.getDirectionTextColor(rad.name()));
assertNotSame(button.getDirectionTextColor(deg.name()), button.getDirectionTextColor(grad.name())); assertNotSame(button.getDirectionTextColor(deg.name()), button.getDirectionTextColor(grad.name()));
assertNotSame(button.getDirectionTextColor(deg.name()), button.getDirectionTextColor(turns.name())); assertNotSame(button.getDirectionTextColor(deg.name()), button.getDirectionTextColor(turns.name()));
} }
@Test @Test
public void testIsCurrentAngleUnits() throws Exception { public void testIsCurrentAngleUnits() throws Exception {
button.setAngleUnit(rad); button.setAngleUnit(rad);
assertTrue(button.isCurrentAngleUnits(rad.name())); assertTrue(button.isCurrentAngleUnits(rad.name()));
assertFalse(button.isCurrentAngleUnits(deg.name())); assertFalse(button.isCurrentAngleUnits(deg.name()));
assertFalse(button.isCurrentAngleUnits(grad.name())); assertFalse(button.isCurrentAngleUnits(grad.name()));
} }
@Test @Test
public void testInvalidateShouldBeCalledOnlyWhenChangeIsDone() throws Exception { public void testInvalidateShouldBeCalledOnlyWhenChangeIsDone() throws Exception {
button.setAngleUnit(rad); button.setAngleUnit(rad);
button = Mockito.spy(button); button = Mockito.spy(button);
button.setAngleUnit(deg); button.setAngleUnit(deg);
verify(button, times(1)).invalidate(); verify(button, times(1)).invalidate();
button.setAngleUnit(deg); button.setAngleUnit(deg);
verify(button, times(1)).invalidate(); verify(button, times(1)).invalidate();
} }
} }

View File

@ -1,6 +1,7 @@
package org.solovyev.android.calculator.view; package org.solovyev.android.calculator.view;
import android.app.Activity; import android.app.Activity;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -12,8 +13,14 @@ import org.robolectric.shadows.ShadowActivity;
import java.util.ArrayList; import java.util.ArrayList;
import static jscl.NumeralBase.*; import static jscl.NumeralBase.bin;
import static org.junit.Assert.*; import static jscl.NumeralBase.dec;
import static jscl.NumeralBase.hex;
import static jscl.NumeralBase.oct;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.solovyev.android.calculator.CalculatorTestUtils.staticSetUp; import static org.solovyev.android.calculator.CalculatorTestUtils.staticSetUp;
@ -21,46 +28,46 @@ import static org.solovyev.android.calculator.CalculatorTestUtils.staticSetUp;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class NumeralBasesButtonTest { public class NumeralBasesButtonTest {
private NumeralBasesButton button; private NumeralBasesButton button;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
staticSetUp(); staticSetUp();
final Activity context = Robolectric.buildActivity(Activity.class).create().get(); final Activity context = Robolectric.buildActivity(Activity.class).create().get();
final ShadowActivity activity = Robolectric.shadowOf(context); final ShadowActivity activity = Robolectric.shadowOf(context);
button = new NumeralBasesButton(context, activity.createAttributeSet(new ArrayList<Attribute>(), NumeralBasesButton.class)); button = new NumeralBasesButton(context, activity.createAttributeSet(new ArrayList<Attribute>(), NumeralBasesButton.class));
} }
@Test @Test
public void testShouldReturnDifferentColorsForDifferentNumeralBase() throws Exception { public void testShouldReturnDifferentColorsForDifferentNumeralBase() throws Exception {
button.setNumeralBase(dec); button.setNumeralBase(dec);
assertEquals(button.getDirectionTextColor(dec.name()), button.getDirectionTextColor(dec.name())); assertEquals(button.getDirectionTextColor(dec.name()), button.getDirectionTextColor(dec.name()));
assertEquals(button.getDirectionTextColor(hex.name()), button.getDirectionTextColor(bin.name())); assertEquals(button.getDirectionTextColor(hex.name()), button.getDirectionTextColor(bin.name()));
assertNotSame(button.getDirectionTextColor(dec.name()), button.getDirectionTextColor(bin.name())); assertNotSame(button.getDirectionTextColor(dec.name()), button.getDirectionTextColor(bin.name()));
assertNotSame(button.getDirectionTextColor(dec.name()), button.getDirectionTextColor(hex.name())); assertNotSame(button.getDirectionTextColor(dec.name()), button.getDirectionTextColor(hex.name()));
assertNotSame(button.getDirectionTextColor(dec.name()), button.getDirectionTextColor(oct.name())); assertNotSame(button.getDirectionTextColor(dec.name()), button.getDirectionTextColor(oct.name()));
} }
@Test @Test
public void testIsCurrentNumeralBase() throws Exception { public void testIsCurrentNumeralBase() throws Exception {
button.setNumeralBase(dec); button.setNumeralBase(dec);
assertTrue(button.isCurrentNumberBase(dec.name())); assertTrue(button.isCurrentNumberBase(dec.name()));
assertFalse(button.isCurrentNumberBase(hex.name())); assertFalse(button.isCurrentNumberBase(hex.name()));
assertFalse(button.isCurrentNumberBase(bin.name())); assertFalse(button.isCurrentNumberBase(bin.name()));
} }
@Test @Test
public void testInvalidateShouldBeCalledOnlyWhenChangeIsDone() throws Exception { public void testInvalidateShouldBeCalledOnlyWhenChangeIsDone() throws Exception {
button.setNumeralBase(dec); button.setNumeralBase(dec);
button = Mockito.spy(button); button = Mockito.spy(button);
button.setNumeralBase(hex); button.setNumeralBase(hex);
verify(button, times(1)).invalidate(); verify(button, times(1)).invalidate();
button.setNumeralBase(hex); button.setNumeralBase(hex);
verify(button, times(1)).invalidate(); verify(button, times(1)).invalidate();
} }
} }

View File

@ -26,6 +26,7 @@ import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -37,161 +38,166 @@ import org.solovyev.android.wizard.Wizard;
import org.solovyev.android.wizard.WizardUi; import org.solovyev.android.wizard.WizardUi;
import org.solovyev.android.wizard.Wizards; import org.solovyev.android.wizard.Wizards;
import javax.annotation.Nonnull;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import static org.junit.Assert.*; import javax.annotation.Nonnull;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.solovyev.android.calculator.wizard.CalculatorWizardStep.choose_mode; import static org.solovyev.android.calculator.wizard.CalculatorWizardStep.choose_mode;
@RunWith(value = CalculatorTestRunner.class) @RunWith(value = CalculatorTestRunner.class)
public class CalculatorWizardActivityTest { public class CalculatorWizardActivityTest {
private ActivityController<WizardActivity> controller; private ActivityController<WizardActivity> controller;
private WizardActivity activity; private WizardActivity activity;
private Wizards wizards; private Wizards wizards;
private Field uiField; private Field uiField;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
controller = Robolectric.buildActivity(WizardActivity.class); controller = Robolectric.buildActivity(WizardActivity.class);
activity = controller.get(); activity = controller.get();
wizards = new CalculatorWizards(Robolectric.application); wizards = new CalculatorWizards(Robolectric.application);
activity.setWizards(wizards); activity.setWizards(wizards);
controller.attach(); controller.attach();
controller.create(); controller.create();
uiField = WizardActivity.class.getDeclaredField("wizardUi"); uiField = WizardActivity.class.getDeclaredField("wizardUi");
uiField.setAccessible(true); uiField.setAccessible(true);
} }
@Test @Test
public void testShouldBeFirstTimeWizardByDefault() throws Exception { public void testShouldBeFirstTimeWizardByDefault() throws Exception {
assertEquals(CalculatorWizards.FIRST_TIME_WIZARD, getWizardUi().getWizard().getName()); assertEquals(CalculatorWizards.FIRST_TIME_WIZARD, getWizardUi().getWizard().getName());
} }
@Nonnull @Nonnull
private WizardUi getWizardUi() throws IllegalAccessException { private WizardUi getWizardUi() throws IllegalAccessException {
return (WizardUi) uiField.get(activity); return (WizardUi) uiField.get(activity);
} }
@Test @Test
public void testShouldBeFirstStep() throws Exception { public void testShouldBeFirstStep() throws Exception {
assertNotNull(getWizardUi().getStep()); assertNotNull(getWizardUi().getStep());
assertEquals(getWizardUi().getFlow().getFirstStep(), getWizardUi().getStep()); assertEquals(getWizardUi().getFlow().getFirstStep(), getWizardUi().getStep());
} }
@Test @Test
public void testShouldSaveState() throws Exception { public void testShouldSaveState() throws Exception {
getWizardUi().setStep(choose_mode); getWizardUi().setStep(choose_mode);
final Bundle outState = new Bundle(); final Bundle outState = new Bundle();
controller.saveInstanceState(outState); controller.saveInstanceState(outState);
controller = Robolectric.buildActivity(WizardActivity.class); controller = Robolectric.buildActivity(WizardActivity.class);
controller.create(outState); controller.create(outState);
activity = controller.get(); activity = controller.get();
assertNotNull(getWizardUi().getFlow()); assertNotNull(getWizardUi().getFlow());
assertEquals(CalculatorWizards.FIRST_TIME_WIZARD, getWizardUi().getWizard().getName()); assertEquals(CalculatorWizards.FIRST_TIME_WIZARD, getWizardUi().getWizard().getName());
assertNotNull(getWizardUi().getStep()); assertNotNull(getWizardUi().getStep());
assertEquals(choose_mode, getWizardUi().getStep()); assertEquals(choose_mode, getWizardUi().getStep());
} }
@Test @Test
public void testCreate() throws Exception { public void testCreate() throws Exception {
final Intent intent = new Intent(); final Intent intent = new Intent();
intent.setClass(activity, WizardActivity.class); intent.setClass(activity, WizardActivity.class);
intent.putExtra("flow", CalculatorWizards.DEFAULT_WIZARD_FLOW); intent.putExtra("flow", CalculatorWizards.DEFAULT_WIZARD_FLOW);
controller = Robolectric.buildActivity(WizardActivity.class).withIntent(intent); controller = Robolectric.buildActivity(WizardActivity.class).withIntent(intent);
controller.create(); controller.create();
activity = controller.get(); activity = controller.get();
assertEquals(CalculatorWizards.DEFAULT_WIZARD_FLOW, getWizardUi().getWizard().getName()); assertEquals(CalculatorWizards.DEFAULT_WIZARD_FLOW, getWizardUi().getWizard().getName());
assertEquals(getWizardUi().getFlow().getFirstStep(), getWizardUi().getStep()); assertEquals(getWizardUi().getFlow().getFirstStep(), getWizardUi().getStep());
final Bundle outState1 = new Bundle(); final Bundle outState1 = new Bundle();
controller.saveInstanceState(outState1); controller.saveInstanceState(outState1);
controller = Robolectric.buildActivity(WizardActivity.class); controller = Robolectric.buildActivity(WizardActivity.class);
activity = controller.get(); activity = controller.get();
controller.create(outState1); controller.create(outState1);
assertEquals(CalculatorWizards.DEFAULT_WIZARD_FLOW, getWizardUi().getWizard().getName()); assertEquals(CalculatorWizards.DEFAULT_WIZARD_FLOW, getWizardUi().getWizard().getName());
assertEquals(getWizardUi().getFlow().getFirstStep(), getWizardUi().getStep()); assertEquals(getWizardUi().getFlow().getFirstStep(), getWizardUi().getStep());
} }
@Test @Test
public void testShouldAddFirstFragment() throws Exception { public void testShouldAddFirstFragment() throws Exception {
controller.start().resume(); controller.start().resume();
final FragmentManager fm = activity.getSupportFragmentManager(); final FragmentManager fm = activity.getSupportFragmentManager();
final Fragment f = fm.findFragmentByTag(CalculatorWizardStep.welcome.getFragmentTag()); final Fragment f = fm.findFragmentByTag(CalculatorWizardStep.welcome.getFragmentTag());
assertNotNull(f); assertNotNull(f);
assertTrue(f.isAdded()); assertTrue(f.isAdded());
} }
@Test @Test
public void testShouldAddStepFragment() throws Exception { public void testShouldAddStepFragment() throws Exception {
controller.start().resume(); controller.start().resume();
final FragmentManager fm = activity.getSupportFragmentManager(); final FragmentManager fm = activity.getSupportFragmentManager();
getWizardUi().setStep(choose_mode); getWizardUi().setStep(choose_mode);
final Fragment f = fm.findFragmentByTag(choose_mode.getFragmentTag()); final Fragment f = fm.findFragmentByTag(choose_mode.getFragmentTag());
assertNotNull(f); assertNotNull(f);
assertTrue(f.isAdded()); assertTrue(f.isAdded());
} }
@Test @Test
public void testSetStep() throws Exception { public void testSetStep() throws Exception {
getWizardUi().setStep(choose_mode); getWizardUi().setStep(choose_mode);
assertEquals(choose_mode, getWizardUi().getStep()); assertEquals(choose_mode, getWizardUi().getStep());
} }
@Test @Test
public void testShouldStartWizardActivityAfterStart() throws Exception { public void testShouldStartWizardActivityAfterStart() throws Exception {
final ShadowActivity shadowActivity = Robolectric.shadowOf(controller.get()); final ShadowActivity shadowActivity = Robolectric.shadowOf(controller.get());
WizardUi.startWizard(activity.getWizards(), CalculatorWizards.DEFAULT_WIZARD_FLOW, shadowActivity.getApplicationContext()); WizardUi.startWizard(activity.getWizards(), CalculatorWizards.DEFAULT_WIZARD_FLOW, shadowActivity.getApplicationContext());
assertNotNull(shadowActivity.getNextStartedActivity()); assertNotNull(shadowActivity.getNextStartedActivity());
} }
@Test @Test
public void testTitleShouldBeSet() throws Exception { public void testTitleShouldBeSet() throws Exception {
getWizardUi().setStep(choose_mode); getWizardUi().setStep(choose_mode);
assertEquals(activity.getString(choose_mode.getTitleResId()), activity.getTitle().toString()); assertEquals(activity.getString(choose_mode.getTitleResId()), activity.getTitle().toString());
} }
private void setLastStep() throws IllegalAccessException { private void setLastStep() throws IllegalAccessException {
getWizardUi().setStep(CalculatorWizardStep.values()[CalculatorWizardStep.values().length - 1]); getWizardUi().setStep(CalculatorWizardStep.values()[CalculatorWizardStep.values().length - 1]);
} }
private void setFirstStep() throws IllegalAccessException { private void setFirstStep() throws IllegalAccessException {
getWizardUi().setStep(CalculatorWizardStep.values()[0]); getWizardUi().setStep(CalculatorWizardStep.values()[0]);
} }
@Test @Test
public void testShouldSaveLastWizardStateOnPause() throws Exception { public void testShouldSaveLastWizardStateOnPause() throws Exception {
final Wizard wizard = wizards.getWizard(getWizardUi().getWizard().getName()); final Wizard wizard = wizards.getWizard(getWizardUi().getWizard().getName());
assertNull(wizard.getLastSavedStepName()); assertNull(wizard.getLastSavedStepName());
getWizardUi().setStep(CalculatorWizardStep.drag_button); getWizardUi().setStep(CalculatorWizardStep.drag_button);
activity.onPause(); activity.onPause();
assertEquals(CalculatorWizardStep.drag_button.getName(), wizard.getLastSavedStepName()); assertEquals(CalculatorWizardStep.drag_button.getName(), wizard.getLastSavedStepName());
} }
@Test @Test
public void testShouldSaveFinishedIfLastStep() throws Exception { public void testShouldSaveFinishedIfLastStep() throws Exception {
final Wizard wizard = wizards.getWizard(getWizardUi().getWizard().getName()); final Wizard wizard = wizards.getWizard(getWizardUi().getWizard().getName());
assertFalse(wizard.isFinished()); assertFalse(wizard.isFinished());
setLastStep(); setLastStep();
getWizardUi().finishWizard(); getWizardUi().finishWizard();
assertTrue(wizard.isFinished()); assertTrue(wizard.isFinished());
} }
@Test @Test
public void testShouldNotSaveFinishedIfNotLastStep() throws Exception { public void testShouldNotSaveFinishedIfNotLastStep() throws Exception {
final Wizard wizard = wizards.getWizard(getWizardUi().getWizard().getName()); final Wizard wizard = wizards.getWizard(getWizardUi().getWizard().getName());
assertFalse(wizard.isFinished()); assertFalse(wizard.isFinished());
setFirstStep(); setFirstStep();
getWizardUi().finishWizard(); getWizardUi().finishWizard();
assertFalse(wizard.isFinished()); assertFalse(wizard.isFinished());
} }
} }

View File

@ -11,89 +11,96 @@ import org.solovyev.android.wizard.Wizards;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals;
import static org.solovyev.android.calculator.wizard.CalculatorWizardStep.*; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.solovyev.android.calculator.wizard.CalculatorWizardStep.choose_mode;
import static org.solovyev.android.calculator.wizard.CalculatorWizardStep.last;
import static org.solovyev.android.calculator.wizard.CalculatorWizardStep.welcome;
@RunWith(value = CalculatorTestRunner.class) @RunWith(value = CalculatorTestRunner.class)
public class CalculatorWizardTest { public class CalculatorWizardTest {
@Nonnull @Nonnull
private Wizards wizards; private Wizards wizards;
@Nonnull @Nonnull
private Wizard wizard; private Wizard wizard;
@Nonnull @Nonnull
private Wizard defaultWizard; private Wizard defaultWizard;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
wizards = new CalculatorWizards(Robolectric.application); wizards = new CalculatorWizards(Robolectric.application);
wizard = wizards.getWizard(null); wizard = wizards.getWizard(null);
defaultWizard = wizards.getWizard(CalculatorWizards.DEFAULT_WIZARD_FLOW); defaultWizard = wizards.getWizard(CalculatorWizards.DEFAULT_WIZARD_FLOW);
} }
@Test @Test
public void testDefaultFlowShouldNotContainWelcomeAndLastSteps() throws Exception { public void testDefaultFlowShouldNotContainWelcomeAndLastSteps() throws Exception {
final WizardFlow flow = defaultWizard.getFlow(); final WizardFlow flow = defaultWizard.getFlow();
assertNull(flow.getStepByName(welcome.getName())); assertNull(flow.getStepByName(welcome.getName()));
assertNull(flow.getStepByName(last.getName())); assertNull(flow.getStepByName(last.getName()));
} }
@Test @Test
public void testFirstTimeFlowShouldContainWelcomeAndLastSteps() throws Exception { public void testFirstTimeFlowShouldContainWelcomeAndLastSteps() throws Exception {
final WizardFlow flow = wizard.getFlow(); final WizardFlow flow = wizard.getFlow();
assertNotNull(flow.getStepByName(welcome.getName())); assertNotNull(flow.getStepByName(welcome.getName()));
assertNotNull(flow.getStepByName(last.getName())); assertNotNull(flow.getStepByName(last.getName()));
} }
@Test @Test
public void testShouldThrowExceptionIfUnknownWizard() throws Exception { public void testShouldThrowExceptionIfUnknownWizard() throws Exception {
try { try {
wizards.getWizard("testtesttesttesttest"); wizards.getWizard("testtesttesttesttest");
fail(); fail();
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
// ok // ok
} }
} }
@Test @Test
public void testShouldReturnWizard() throws Exception { public void testShouldReturnWizard() throws Exception {
assertNotNull(wizards.getWizard(CalculatorWizards.FIRST_TIME_WIZARD)); assertNotNull(wizards.getWizard(CalculatorWizards.FIRST_TIME_WIZARD));
assertNotNull(wizards.getWizard(CalculatorWizards.DEFAULT_WIZARD_FLOW)); assertNotNull(wizards.getWizard(CalculatorWizards.DEFAULT_WIZARD_FLOW));
} }
@Test @Test
public void testShouldSaveWizardIsFinishedWhenNotLastStepAndForce() throws Exception { public void testShouldSaveWizardIsFinishedWhenNotLastStepAndForce() throws Exception {
assertFalse(wizard.isFinished()); assertFalse(wizard.isFinished());
wizard.saveFinished(CalculatorWizardStep.drag_button, true); wizard.saveFinished(CalculatorWizardStep.drag_button, true);
assertTrue(wizard.isFinished()); assertTrue(wizard.isFinished());
} }
@Test @Test
public void testShouldNotSaveWizardIsFinishedWhenNotLastStepAndNotForce() throws Exception { public void testShouldNotSaveWizardIsFinishedWhenNotLastStepAndNotForce() throws Exception {
assertFalse(wizard.isFinished()); assertFalse(wizard.isFinished());
wizard.saveFinished(CalculatorWizardStep.drag_button, false); wizard.saveFinished(CalculatorWizardStep.drag_button, false);
assertFalse(wizard.isFinished()); assertFalse(wizard.isFinished());
} }
@Test @Test
public void testShouldSaveWizardIsFinishedWhenLastStep() throws Exception { public void testShouldSaveWizardIsFinishedWhenLastStep() throws Exception {
assertFalse(wizard.isFinished()); assertFalse(wizard.isFinished());
wizard.saveFinished(CalculatorWizardStep.last, false); wizard.saveFinished(CalculatorWizardStep.last, false);
assertTrue(wizard.isFinished()); assertTrue(wizard.isFinished());
} }
@Test @Test
public void testShouldSaveLastWizardStep() throws Exception { public void testShouldSaveLastWizardStep() throws Exception {
assertFalse(wizard.isStarted()); assertFalse(wizard.isStarted());
assertNull(wizard.getLastSavedStepName()); assertNull(wizard.getLastSavedStepName());
wizard.saveLastStep(choose_mode); wizard.saveLastStep(choose_mode);
assertTrue(wizard.isStarted()); assertTrue(wizard.isStarted());
assertEquals(choose_mode.name(), wizard.getLastSavedStepName()); assertEquals(choose_mode.name(), wizard.getLastSavedStepName());
} }
} }

View File

@ -30,58 +30,59 @@ import org.robolectric.util.ActivityController;
import org.solovyev.android.CalculatorTestRunner; import org.solovyev.android.CalculatorTestRunner;
import org.solovyev.android.wizard.WizardUi; import org.solovyev.android.wizard.WizardUi;
import javax.annotation.Nonnull;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import javax.annotation.Nonnull;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@RunWith(CalculatorTestRunner.class) @RunWith(CalculatorTestRunner.class)
public class OnScreenCalculatorWizardStepTest { public class OnScreenCalculatorWizardStepTest {
@Nonnull @Nonnull
private OnScreenCalculatorWizardStep fragment; private OnScreenCalculatorWizardStep fragment;
@Nonnull @Nonnull
private WizardActivity activity; private WizardActivity activity;
@Nonnull @Nonnull
private ActivityController<WizardActivity> controller; private ActivityController<WizardActivity> controller;
private Field uiField; private Field uiField;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
uiField = WizardActivity.class.getDeclaredField("wizardUi"); uiField = WizardActivity.class.getDeclaredField("wizardUi");
uiField.setAccessible(true); uiField.setAccessible(true);
createActivity(); createActivity();
setFragment(); setFragment();
} }
@Nonnull @Nonnull
private WizardUi getWizardUi() throws IllegalAccessException { private WizardUi getWizardUi() throws IllegalAccessException {
return (WizardUi) uiField.get(activity); return (WizardUi) uiField.get(activity);
} }
private void createActivity() { private void createActivity() {
controller = Robolectric.buildActivity(WizardActivity.class).create().start().resume(); controller = Robolectric.buildActivity(WizardActivity.class).create().start().resume();
activity = controller.get(); activity = controller.get();
} }
private void setFragment() throws IllegalAccessException { private void setFragment() throws IllegalAccessException {
getWizardUi().setStep(CalculatorWizardStep.on_screen_calculator); getWizardUi().setStep(CalculatorWizardStep.on_screen_calculator);
activity.getSupportFragmentManager().executePendingTransactions(); activity.getSupportFragmentManager().executePendingTransactions();
fragment = (OnScreenCalculatorWizardStep) activity.getSupportFragmentManager().findFragmentByTag(CalculatorWizardStep.on_screen_calculator.getFragmentTag()); fragment = (OnScreenCalculatorWizardStep) activity.getSupportFragmentManager().findFragmentByTag(CalculatorWizardStep.on_screen_calculator.getFragmentTag());
} }
@Test @Test
public void testShouldRestoreStateOnRestart() throws Exception { public void testShouldRestoreStateOnRestart() throws Exception {
fragment.getCheckbox().setChecked(true); fragment.getCheckbox().setChecked(true);
controller.restart(); controller.restart();
assertTrue(fragment.getCheckbox().isChecked()); assertTrue(fragment.getCheckbox().isChecked());
fragment.getCheckbox().setChecked(false); fragment.getCheckbox().setChecked(false);
controller.restart(); controller.restart();
assertFalse(fragment.getCheckbox().isChecked()); assertFalse(fragment.getCheckbox().isChecked());
} }
} }

View File

@ -55,7 +55,7 @@ android {
} }
repositories { repositories {
flatDir{ flatDir {
dirs 'misc/libs' dirs 'misc/libs'
} }
} }
@ -86,7 +86,7 @@ dependencies {
compile 'com.google.android.gms:play-services-base:8.4.0' compile 'com.google.android.gms:play-services-base:8.4.0'
compile 'com.google.android.gms:play-services-analytics:8.4.0' compile 'com.google.android.gms:play-services-analytics:8.4.0'
compile 'com.melnykov:floatingactionbutton:1.1.0' compile 'com.melnykov:floatingactionbutton:1.1.0'
compile(name:'plotter', ext:'aar') compile(name: 'plotter', ext: 'aar')
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1' debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'

View File

@ -1,210 +1,310 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto" package="org.solovyev.android.calculator"> <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.solovyev.android.calculator"
android:installLocation="auto">
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.android.vending.BILLING"/> <uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--TODO: REMOVE IN PRODUCTION--> <!--TODO: REMOVE IN PRODUCTION-->
<!--<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>--> <!--<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>-->
<!-- for onscreen --> <!-- for onscreen -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<supports-screens android:smallScreens="true"/> <supports-screens android:smallScreens="true" />
<supports-screens android:normalScreens="true"/> <supports-screens android:normalScreens="true" />
<supports-screens android:largeScreens="true"/> <supports-screens android:largeScreens="true" />
<supports-screens android:xlargeScreens="true"/> <supports-screens android:xlargeScreens="true" />
<supports-screens android:anyDensity="true"/> <supports-screens android:anyDensity="true" />
<application android:allowBackup="true" android:hardwareAccelerated="true" android:icon="@drawable/ic_launcher" android:label="@string/c_app_name" android:name=".CalculatorApplication" android:theme="@style/Cpp.Theme.Material"> <application
android:name=".CalculatorApplication"
android:allowBackup="true"
android:hardwareAccelerated="true"
android:icon="@drawable/ic_launcher"
android:label="@string/c_app_name"
android:theme="@style/Cpp.Theme.Material">
<meta-data <meta-data
android:name="com.google.android.gms.version" android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" /> android:value="@integer/google_play_services_version" />
<activity android:clearTaskOnLaunch="true" android:label="@string/c_app_name" android:launchMode="singleTop" android:name=".CalculatorActivity" android:windowSoftInputMode="adjustPan"> <activity
android:name=".CalculatorActivity"
android:clearTaskOnLaunch="true"
android:label="@string/c_app_name"
android:launchMode="singleTop"
android:windowSoftInputMode="adjustPan">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<receiver android:exported="false" android:name=".CalculatorReceiver"> <receiver
<intent-filter> android:name=".CalculatorReceiver"
<action android:name="org.solovyev.android.calculator.BUTTON_PRESSED"/> android:exported="false">
</intent-filter> <intent-filter>
</receiver> <action android:name="org.solovyev.android.calculator.BUTTON_PRESSED" />
</intent-filter>
</receiver>
<activity android:clearTaskOnLaunch="true" android:label="@string/c_app_name" android:launchMode="singleTop" android:name=".CalculatorActivityMobile" android:windowSoftInputMode="adjustPan"/> <activity
android:name=".CalculatorActivityMobile"
android:clearTaskOnLaunch="true"
android:label="@string/c_app_name"
android:launchMode="singleTop"
android:windowSoftInputMode="adjustPan" />
<activity android:label="@string/c_app_settings" android:name=".preferences.PreferencesActivity"/> <activity
android:name=".preferences.PreferencesActivity"
android:label="@string/c_app_settings" />
<activity android:label="@string/c_history" android:name=".history.CalculatorHistoryActivity"/> <activity
android:name=".history.CalculatorHistoryActivity"
android:label="@string/c_history" />
<activity android:excludeFromRecents="true" android:finishOnTaskLaunch="true" android:label="@string/calculation_messages_dialog_title" android:launchMode="singleTask" android:name=".FixableMessagesDialog" android:theme="@style/Cpp.Theme.Dialog.Material"/> <activity
android:name=".FixableMessagesDialog"
android:excludeFromRecents="true"
android:finishOnTaskLaunch="true"
android:label="@string/calculation_messages_dialog_title"
android:launchMode="singleTask"
android:theme="@style/Cpp.Theme.Dialog.Material" />
<activity android:label="@string/c_about" android:name=".about.CalculatorAboutActivity"/> <activity
android:name=".about.CalculatorAboutActivity"
android:label="@string/c_about" />
<activity android:label="@string/c_functions" android:name=".math.edit.CalculatorFunctionsActivity"/> <activity
android:name=".math.edit.CalculatorFunctionsActivity"
android:label="@string/c_functions" />
<activity android:label="@string/c_operators" android:name=".math.edit.CalculatorOperatorsActivity"/> <activity
android:name=".math.edit.CalculatorOperatorsActivity"
android:label="@string/c_operators" />
<activity android:label="@string/c_vars_and_constants" android:name=".math.edit.CalculatorVarsActivity"/> <activity
<activity android:launchMode="singleTop" android:name=".wizard.WizardActivity" android:theme="@style/Cpp.Theme.Wizard"> android:name=".math.edit.CalculatorVarsActivity"
<intent-filter> android:label="@string/c_vars_and_constants" />
<action android:name="android.intent.action.MAIN"/> <activity
</intent-filter> android:name=".wizard.WizardActivity"
</activity> android:launchMode="singleTop"
android:theme="@style/Cpp.Theme.Wizard">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity android:hardwareAccelerated="false" android:label="@string/c_plot_graph" android:name=".plot.CalculatorPlotActivity" android:theme="@style/Cpp.Theme.Material"/> <activity
<activity android:label="@string/cpp_plot_functions" android:name=".plot.CalculatorPlotFunctionsActivity" android:theme="@style/Cpp.Theme.Dialog.Material"/> android:name=".plot.CalculatorPlotActivity"
<activity android:label="@string/cpp_plot_function_settings" android:name=".plot.CalculatorPlotFunctionSettingsActivity" android:theme="@style/Cpp.Theme.Dialog.Material"/> android:hardwareAccelerated="false"
<activity android:label="@string/cpp_plot_range" android:name=".plot.CalculatorPlotRangeActivity" android:theme="@style/Cpp.Theme.Dialog.Material"/> 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.Dialog.Material" />
<activity
android:name=".plot.CalculatorPlotFunctionSettingsActivity"
android:label="@string/cpp_plot_function_settings"
android:theme="@style/Cpp.Theme.Dialog.Material" />
<activity
android:name=".plot.CalculatorPlotRangeActivity"
android:label="@string/cpp_plot_range"
android:theme="@style/Cpp.Theme.Dialog.Material" />
<activity android:label="@string/cpp_purchase_title" android:name=".preferences.PurchaseDialogActivity" android:theme="@style/Cpp.Theme.Dialog.Material"/> <activity
android:name=".preferences.PurchaseDialogActivity"
android:label="@string/cpp_purchase_title"
android:theme="@style/Cpp.Theme.Dialog.Material" />
<activity android:name=".CalculatorDialogActivity" android:theme="@style/Cpp.Theme.Dialog.Material"/> <activity
android:name=".CalculatorDialogActivity"
android:theme="@style/Cpp.Theme.Dialog.Material" />
<!-- todo serso: strings--> <!-- todo serso: strings-->
<activity android:label="@string/c_plot_graph" android:name=".matrix.CalculatorMatrixActivity"> <activity
<intent-filter> android:name=".matrix.CalculatorMatrixActivity"
<action android:name="android.intent.action.MAIN"/> android:label="@string/c_plot_graph">
</intent-filter> <intent-filter>
</activity> <action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity android:name=".widget.CalculatorWidgetConfigurationActivity" android:theme="@style/cpp_metro_blue_theme"> <activity
<intent-filter> android:name=".widget.CalculatorWidgetConfigurationActivity"
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/> android:theme="@style/cpp_metro_blue_theme">
</intent-filter> <intent-filter>
</activity> <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<!-- ONSCREEN CONFIG --> <!-- ONSCREEN CONFIG -->
<activity android:icon="@drawable/ic_launcher_window" android:label="@string/c_app_name_on_screen" android:launchMode="singleInstance" android:name=".onscreen.CalculatorOnscreenStartActivity" android:theme="@style/Cpp.Theme.Dialog.Material"> <activity
android:name=".onscreen.CalculatorOnscreenStartActivity"
android:icon="@drawable/ic_launcher_window"
android:label="@string/c_app_name_on_screen"
android:launchMode="singleInstance"
android:theme="@style/Cpp.Theme.Dialog.Material">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<service android:exported="false" android:name=".onscreen.CalculatorOnscreenService"> <service
<intent-filter> android:name=".onscreen.CalculatorOnscreenService"
<action android:name="org.solovyev.android.calculator.onscreen.SHOW_WINDOW"/> android:exported="false">
<action android:name="org.solovyev.android.calculator.onscreen.SHOW_NOTIFICATION"/> <intent-filter>
</intent-filter> <action android:name="org.solovyev.android.calculator.onscreen.SHOW_WINDOW" />
</service> <action android:name="org.solovyev.android.calculator.onscreen.SHOW_NOTIFICATION" />
</intent-filter>
</service>
<receiver android:name=".onscreen.CalculatorOnscreenBroadcastReceiver"> <receiver android:name=".onscreen.CalculatorOnscreenBroadcastReceiver">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/> <action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="org.solovyev.android.calculator.onscreen.SHOW_WINDOW"/> <action android:name="org.solovyev.android.calculator.onscreen.SHOW_WINDOW" />
<action android:name="org.solovyev.android.calculator.onscreen.SHOW_NOTIFICATION"/> <action android:name="org.solovyev.android.calculator.onscreen.SHOW_NOTIFICATION" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<!-- WIDGET CONFIG --> <!-- WIDGET CONFIG -->
<receiver android:icon="@drawable/ic_launcher" android:label="@string/c_app_name" android:name=".widget.CalculatorWidget"> <receiver
android:name=".widget.CalculatorWidget"
android:icon="@drawable/ic_launcher"
android:label="@string/c_app_name">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="org.solovyev.android.calculator.INIT"/> <action android:name="org.solovyev.android.calculator.INIT" />
<action android:name="org.solovyev.android.calculator.EDITOR_STATE_CHANGED"/> <action android:name="org.solovyev.android.calculator.EDITOR_STATE_CHANGED" />
<action android:name="org.solovyev.android.calculator.DISPLAY_STATE_CHANGED"/> <action android:name="org.solovyev.android.calculator.DISPLAY_STATE_CHANGED" />
<action android:name="org.solovyev.android.calculator.BUTTON_PRESSED"/> <action android:name="org.solovyev.android.calculator.BUTTON_PRESSED" />
<action android:name="org.solovyev.android.calculator.THEME_CHANGED"/> <action android:name="org.solovyev.android.calculator.THEME_CHANGED" />
</intent-filter> </intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/calculator_widget"/> <meta-data
</receiver> android:name="android.appwidget.provider"
android:resource="@xml/calculator_widget" />
</receiver>
<receiver android:icon="@drawable/ic_launcher" android:label="@string/c_app_widget_3x3_name" android:name=".widget.CalculatorWidgetProvider"> <receiver
android:name=".widget.CalculatorWidgetProvider"
android:icon="@drawable/ic_launcher"
android:label="@string/c_app_widget_3x3_name">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="org.solovyev.android.calculator.INIT"/> <action android:name="org.solovyev.android.calculator.INIT" />
<action android:name="org.solovyev.android.calculator.EDITOR_STATE_CHANGED"/> <action android:name="org.solovyev.android.calculator.EDITOR_STATE_CHANGED" />
<action android:name="org.solovyev.android.calculator.DISPLAY_STATE_CHANGED"/> <action android:name="org.solovyev.android.calculator.DISPLAY_STATE_CHANGED" />
<action android:name="org.solovyev.android.calculator.BUTTON_PRESSED"/> <action android:name="org.solovyev.android.calculator.BUTTON_PRESSED" />
<action android:name="org.solovyev.android.calculator.THEME_CHANGED"/> <action android:name="org.solovyev.android.calculator.THEME_CHANGED" />
</intent-filter> </intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/calculator_widget_info_3x3"/> <meta-data
</receiver> android:name="android.appwidget.provider"
android:resource="@xml/calculator_widget_info_3x3" />
</receiver>
<receiver android:icon="@drawable/ic_launcher" android:label="@string/c_app_widget_3x4_name" android:name=".widget.CalculatorWidgetProvider3x4"> <receiver
android:name=".widget.CalculatorWidgetProvider3x4"
android:icon="@drawable/ic_launcher"
android:label="@string/c_app_widget_3x4_name">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="org.solovyev.android.calculator.INIT"/> <action android:name="org.solovyev.android.calculator.INIT" />
<action android:name="org.solovyev.android.calculator.EDITOR_STATE_CHANGED"/> <action android:name="org.solovyev.android.calculator.EDITOR_STATE_CHANGED" />
<action android:name="org.solovyev.android.calculator.DISPLAY_STATE_CHANGED"/> <action android:name="org.solovyev.android.calculator.DISPLAY_STATE_CHANGED" />
<action android:name="org.solovyev.android.calculator.BUTTON_PRESSED"/> <action android:name="org.solovyev.android.calculator.BUTTON_PRESSED" />
<action android:name="org.solovyev.android.calculator.THEME_CHANGED"/> <action android:name="org.solovyev.android.calculator.THEME_CHANGED" />
</intent-filter> </intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/calculator_widget_info_3x4"/> <meta-data
</receiver> android:name="android.appwidget.provider"
android:resource="@xml/calculator_widget_info_3x4" />
</receiver>
<receiver android:icon="@drawable/ic_launcher" android:label="@string/c_app_widget_4x4_name" android:name=".widget.CalculatorWidgetProvider4x4"> <receiver
android:name=".widget.CalculatorWidgetProvider4x4"
android:icon="@drawable/ic_launcher"
android:label="@string/c_app_widget_4x4_name">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="org.solovyev.android.calculator.INIT"/> <action android:name="org.solovyev.android.calculator.INIT" />
<action android:name="org.solovyev.android.calculator.EDITOR_STATE_CHANGED"/> <action android:name="org.solovyev.android.calculator.EDITOR_STATE_CHANGED" />
<action android:name="org.solovyev.android.calculator.DISPLAY_STATE_CHANGED"/> <action android:name="org.solovyev.android.calculator.DISPLAY_STATE_CHANGED" />
<action android:name="org.solovyev.android.calculator.BUTTON_PRESSED"/> <action android:name="org.solovyev.android.calculator.BUTTON_PRESSED" />
<action android:name="org.solovyev.android.calculator.THEME_CHANGED"/> <action android:name="org.solovyev.android.calculator.THEME_CHANGED" />
</intent-filter> </intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/calculator_widget_info_4x4"/> <meta-data
</receiver> android:name="android.appwidget.provider"
android:resource="@xml/calculator_widget_info_4x4" />
</receiver>
<receiver android:icon="@drawable/ic_launcher" android:label="@string/c_app_widget_4x5_name" android:name=".widget.CalculatorWidgetProvider4x5"> <receiver
android:name=".widget.CalculatorWidgetProvider4x5"
android:icon="@drawable/ic_launcher"
android:label="@string/c_app_widget_4x5_name">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="org.solovyev.android.calculator.INIT"/> <action android:name="org.solovyev.android.calculator.INIT" />
<action android:name="org.solovyev.android.calculator.EDITOR_STATE_CHANGED"/> <action android:name="org.solovyev.android.calculator.EDITOR_STATE_CHANGED" />
<action android:name="org.solovyev.android.calculator.DISPLAY_STATE_CHANGED"/> <action android:name="org.solovyev.android.calculator.DISPLAY_STATE_CHANGED" />
<action android:name="org.solovyev.android.calculator.BUTTON_PRESSED"/> <action android:name="org.solovyev.android.calculator.BUTTON_PRESSED" />
<action android:name="org.solovyev.android.calculator.THEME_CHANGED"/> <action android:name="org.solovyev.android.calculator.THEME_CHANGED" />
</intent-filter> </intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/calculator_widget_info_4x5"/> <meta-data
</receiver> android:name="android.appwidget.provider"
android:resource="@xml/calculator_widget_info_4x5" />
</receiver>
<!-- ADMOB --> <!-- ADMOB -->
<activity <activity
android:name="com.google.android.gms.ads.AdActivity" android:name="com.google.android.gms.ads.AdActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
android:theme="@android:style/Theme.Translucent" /> android:theme="@android:style/Theme.Translucent" />
<!-- ACRA CONFIG --> <!-- ACRA CONFIG -->
<activity android:excludeFromRecents="true" android:finishOnTaskLaunch="true" android:launchMode="singleInstance" android:name="org.acra.CrashReportDialog" android:theme="@android:style/Theme.Dialog"/> <activity
android:name="org.acra.CrashReportDialog"
android:excludeFromRecents="true"
android:finishOnTaskLaunch="true"
android:launchMode="singleInstance"
android:theme="@android:style/Theme.Dialog" />
<!-- Google Analytics --> <!-- Google Analytics -->
<receiver <receiver
android:name="com.google.android.gms.analytics.AnalyticsReceiver" android:name="com.google.android.gms.analytics.AnalyticsReceiver"
android:enabled="true"> android:enabled="true">
<intent-filter> <intent-filter>
<action android:name="com.google.android.gms.analytics.ANALYTICS_DISPATCH"/> <action android:name="com.google.android.gms.analytics.ANALYTICS_DISPATCH" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<service <service
android:name="com.google.android.gms.analytics.AnalyticsService" android:name="com.google.android.gms.analytics.AnalyticsService"
android:enabled="true" android:enabled="true"
android:exported="false"/> android:exported="false" />
</application> </application>
</manifest> </manifest>

View File

@ -32,6 +32,7 @@ import android.util.AttributeSet;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewConfiguration; import android.view.ViewConfiguration;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import static android.graphics.Paint.ANTI_ALIAS_FLAG; import static android.graphics.Paint.ANTI_ALIAS_FLAG;
@ -44,11 +45,10 @@ import static android.widget.LinearLayout.VERTICAL;
*/ */
public class CirclePageIndicator extends View implements PageIndicator { public class CirclePageIndicator extends View implements PageIndicator {
private static final int INVALID_POINTER = -1; private static final int INVALID_POINTER = -1;
private float mRadius;
private final Paint mPaintPageFill = new Paint(ANTI_ALIAS_FLAG); private final Paint mPaintPageFill = new Paint(ANTI_ALIAS_FLAG);
private final Paint mPaintStroke = new Paint(ANTI_ALIAS_FLAG); private final Paint mPaintStroke = new Paint(ANTI_ALIAS_FLAG);
private final Paint mPaintFill = new Paint(ANTI_ALIAS_FLAG); private final Paint mPaintFill = new Paint(ANTI_ALIAS_FLAG);
private float mRadius;
private ViewPager mViewPager; private ViewPager mViewPager;
private ViewPager.OnPageChangeListener mListener; private ViewPager.OnPageChangeListener mListener;
private int mCurrentPage; private int mCurrentPage;
@ -105,7 +105,7 @@ public class CirclePageIndicator extends View implements PageIndicator {
Drawable background = a.getDrawable(R.styleable.CirclePageIndicator_android_background); Drawable background = a.getDrawable(R.styleable.CirclePageIndicator_android_background);
if (background != null) { if (background != null) {
setBackgroundDrawable(background); setBackgroundDrawable(background);
} }
a.recycle(); a.recycle();
@ -114,18 +114,12 @@ public class CirclePageIndicator extends View implements PageIndicator {
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration); mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
} }
public void setCentered(boolean centered) {
mCentered = centered;
invalidate();
}
public boolean isCentered() { public boolean isCentered() {
return mCentered; return mCentered;
} }
public void setPageColor(int pageColor) { public void setCentered(boolean centered) {
mPaintPageFill.setColor(pageColor); mCentered = centered;
invalidate(); invalidate();
} }
@ -133,8 +127,8 @@ public class CirclePageIndicator extends View implements PageIndicator {
return mPaintPageFill.getColor(); return mPaintPageFill.getColor();
} }
public void setFillColor(int fillColor) { public void setPageColor(int pageColor) {
mPaintFill.setColor(fillColor); mPaintPageFill.setColor(pageColor);
invalidate(); invalidate();
} }
@ -142,6 +136,15 @@ public class CirclePageIndicator extends View implements PageIndicator {
return mPaintFill.getColor(); return mPaintFill.getColor();
} }
public void setFillColor(int fillColor) {
mPaintFill.setColor(fillColor);
invalidate();
}
public int getOrientation() {
return mOrientation;
}
public void setOrientation(int orientation) { public void setOrientation(int orientation) {
switch (orientation) { switch (orientation) {
case HORIZONTAL: case HORIZONTAL:
@ -155,8 +158,8 @@ public class CirclePageIndicator extends View implements PageIndicator {
} }
} }
public int getOrientation() { public int getStrokeColor() {
return mOrientation; return mPaintStroke.getColor();
} }
public void setStrokeColor(int strokeColor) { public void setStrokeColor(int strokeColor) {
@ -164,8 +167,8 @@ public class CirclePageIndicator extends View implements PageIndicator {
invalidate(); invalidate();
} }
public int getStrokeColor() { public float getStrokeWidth() {
return mPaintStroke.getColor(); return mPaintStroke.getStrokeWidth();
} }
public void setStrokeWidth(float strokeWidth) { public void setStrokeWidth(float strokeWidth) {
@ -173,8 +176,8 @@ public class CirclePageIndicator extends View implements PageIndicator {
invalidate(); invalidate();
} }
public float getStrokeWidth() { public float getRadius() {
return mPaintStroke.getStrokeWidth(); return mRadius;
} }
public void setRadius(float radius) { public void setRadius(float radius) {
@ -182,8 +185,8 @@ public class CirclePageIndicator extends View implements PageIndicator {
invalidate(); invalidate();
} }
public float getRadius() { public boolean isSnap() {
return mRadius; return mSnap;
} }
public void setSnap(boolean snap) { public void setSnap(boolean snap) {
@ -191,10 +194,6 @@ public class CirclePageIndicator extends View implements PageIndicator {
invalidate(); invalidate();
} }
public boolean isSnap() {
return mSnap;
}
@Override @Override
protected void onDraw(Canvas canvas) { protected void onDraw(Canvas canvas) {
super.onDraw(canvas); super.onDraw(canvas);
@ -454,8 +453,7 @@ public class CirclePageIndicator extends View implements PageIndicator {
/** /**
* Determines the width of this view * Determines the width of this view
* *
* @param measureSpec * @param measureSpec A measureSpec packed into an int
* A measureSpec packed into an int
* @return The width of the view, honoring constraints from measureSpec * @return The width of the view, honoring constraints from measureSpec
*/ */
private int measureLong(int measureSpec) { private int measureLong(int measureSpec) {
@ -469,7 +467,7 @@ public class CirclePageIndicator extends View implements PageIndicator {
} else { } else {
//Calculate the width according the views count //Calculate the width according the views count
final int count = mViewPager.getAdapter().getCount(); final int count = mViewPager.getAdapter().getCount();
result = (int)(getPaddingLeft() + getPaddingRight() result = (int) (getPaddingLeft() + getPaddingRight()
+ (count * 2 * mRadius) + (count - 1) * mRadius + 1); + (count * 2 * mRadius) + (count - 1) * mRadius + 1);
//Respect AT_MOST value if that was what is called for by measureSpec //Respect AT_MOST value if that was what is called for by measureSpec
if (specMode == MeasureSpec.AT_MOST) { if (specMode == MeasureSpec.AT_MOST) {
@ -482,8 +480,7 @@ public class CirclePageIndicator extends View implements PageIndicator {
/** /**
* Determines the height of this view * Determines the height of this view
* *
* @param measureSpec * @param measureSpec A measureSpec packed into an int
* A measureSpec packed into an int
* @return The height of the view, honoring constraints from measureSpec * @return The height of the view, honoring constraints from measureSpec
*/ */
private int measureShort(int measureSpec) { private int measureShort(int measureSpec) {
@ -496,7 +493,7 @@ public class CirclePageIndicator extends View implements PageIndicator {
result = specSize; result = specSize;
} else { } else {
//Measure the height //Measure the height
result = (int)(2 * mRadius + getPaddingTop() + getPaddingBottom() + 1); result = (int) (2 * mRadius + getPaddingTop() + getPaddingBottom() + 1);
//Respect AT_MOST value if that was what is called for by measureSpec //Respect AT_MOST value if that was what is called for by measureSpec
if (specMode == MeasureSpec.AT_MOST) { if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize); result = Math.min(result, specSize);
@ -507,7 +504,7 @@ public class CirclePageIndicator extends View implements PageIndicator {
@Override @Override
public void onRestoreInstanceState(Parcelable state) { public void onRestoreInstanceState(Parcelable state) {
SavedState savedState = (SavedState)state; SavedState savedState = (SavedState) state;
super.onRestoreInstanceState(savedState.getSuperState()); super.onRestoreInstanceState(savedState.getSuperState());
mCurrentPage = savedState.currentPage; mCurrentPage = savedState.currentPage;
mSnapPage = savedState.currentPage; mSnapPage = savedState.currentPage;
@ -523,6 +520,18 @@ public class CirclePageIndicator extends View implements PageIndicator {
} }
static class SavedState extends BaseSavedState { static class SavedState extends BaseSavedState {
@SuppressWarnings("UnusedDeclaration")
public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
int currentPage; int currentPage;
public SavedState(Parcelable superState) { public SavedState(Parcelable superState) {
@ -539,18 +548,5 @@ public class CirclePageIndicator extends View implements PageIndicator {
super.writeToParcel(dest, flags); super.writeToParcel(dest, flags);
dest.writeInt(currentPage); dest.writeInt(currentPage);
} }
@SuppressWarnings("UnusedDeclaration")
public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
} }
} }

View File

@ -41,7 +41,7 @@ public interface PageIndicator extends ViewPager.OnPageChangeListener {
/** /**
* <p>Set the current page of both the ViewPager and indicator.</p> * <p>Set the current page of both the ViewPager and indicator.</p>
* * <p/>
* <p>This <strong>must</strong> be used if you need to set the page before * <p>This <strong>must</strong> be used if you need to set the page before
* the views are drawn on screen (e.g., default start page).</p> * the views are drawn on screen (e.g., default start page).</p>
* *

View File

@ -34,139 +34,139 @@ import static java.lang.Thread.currentThread;
public final class Check { public final class Check {
private static final boolean junit = isJunit(); private static final boolean junit = isJunit();
private static boolean isJunit() { private Check() {
final StackTraceElement[] stackTrace = currentThread().getStackTrace(); throw new AssertionError();
for (StackTraceElement element : stackTrace) { }
if (element.getClassName().startsWith("org.junit.")) {
return true;
}
}
return false;
}
private Check() { private static boolean isJunit() {
throw new AssertionError(); final StackTraceElement[] stackTrace = currentThread().getStackTrace();
} for (StackTraceElement element : stackTrace) {
if (element.getClassName().startsWith("org.junit.")) {
return true;
}
}
return false;
}
public static void isMainThread() { public static void isMainThread() {
if (!junit && Looper.getMainLooper() != Looper.myLooper()) { if (!junit && Looper.getMainLooper() != Looper.myLooper()) {
throw new AssertionException("Should be called on the main thread"); throw new AssertionException("Should be called on the main thread");
} }
} }
public static void isNotNull(@Nullable Object o) { public static void isNotNull(@Nullable Object o) {
isNotNull(o, "Object should not be null"); isNotNull(o, "Object should not be null");
} }
public static void isNotNull(@Nullable Object o, @Nonnull String message) { public static void isNotNull(@Nullable Object o, @Nonnull String message) {
if (o == null) { if (o == null) {
throw new AssertionException(message); throw new AssertionException(message);
} }
} }
public static void notEquals(int expected, int actual) { public static void notEquals(int expected, int actual) {
if (expected == actual) { if (expected == actual) {
throw new AssertionException("Should not be equal"); throw new AssertionException("Should not be equal");
} }
} }
public static void equals(int expected, int actual) { public static void equals(int expected, int actual) {
if (expected != actual) { if (expected != actual) {
throw new AssertionException("Should be equal"); throw new AssertionException("Should be equal");
} }
} }
public static void equals(@Nullable Object expected, @Nullable Object actual) { public static void equals(@Nullable Object expected, @Nullable Object actual) {
equals(expected, actual, "Should be equal"); equals(expected, actual, "Should be equal");
} }
public static void equals(@Nullable Object expected, @Nullable Object actual, @Nonnull String message) { public static void equals(@Nullable Object expected, @Nullable Object actual, @Nonnull String message) {
if (expected == actual) { if (expected == actual) {
// both nulls or same // both nulls or same
return; return;
} }
if (expected != null && actual != null && expected.equals(actual)) { if (expected != null && actual != null && expected.equals(actual)) {
// equals // equals
return; return;
} }
throw new AssertionException(message); throw new AssertionException(message);
} }
public static void isTrue(boolean expression) { public static void isTrue(boolean expression) {
if (!expression) { if (!expression) {
throw new AssertionException(""); throw new AssertionException("");
} }
} }
public static void isTrue(boolean expression, @Nonnull String message) { public static void isTrue(boolean expression, @Nonnull String message) {
if (!expression) { if (!expression) {
throw new AssertionException(message); throw new AssertionException(message);
} }
} }
public static void isFalse(boolean expression, @Nonnull String message) { public static void isFalse(boolean expression, @Nonnull String message) {
if (expression) { if (expression) {
throw new AssertionException(message); throw new AssertionException(message);
} }
} }
public static void isNull(@Nullable Object o) { public static void isNull(@Nullable Object o) {
isNull(o, "Object should be null"); isNull(o, "Object should be null");
} }
public static void isNull(@Nullable Object o, @Nonnull String message) { public static void isNull(@Nullable Object o, @Nonnull String message) {
if (o != null) { if (o != null) {
throw new AssertionException(message); throw new AssertionException(message);
} }
} }
public static void isNotEmpty(@Nullable String s) { public static void isNotEmpty(@Nullable String s) {
if (s == null || s.length() == 0) { if (s == null || s.length() == 0) {
throw new AssertionException("String should not be empty"); throw new AssertionException("String should not be empty");
} }
} }
public static void isNotEmpty(@Nullable String[] array) { public static void isNotEmpty(@Nullable String[] array) {
if (array == null || array.length == 0) { if (array == null || array.length == 0) {
throw new AssertionException("Array should not be empty"); throw new AssertionException("Array should not be empty");
} }
} }
public static void isNotEmpty(@Nullable Collection<?> c) { public static void isNotEmpty(@Nullable Collection<?> c) {
if (c == null || c.size() == 0) { if (c == null || c.size() == 0) {
throw new AssertionException("Collection should not be empty"); throw new AssertionException("Collection should not be empty");
} }
} }
public static void isNotEmpty(@Nullable Map<?, ?> c) { public static void isNotEmpty(@Nullable Map<?, ?> c) {
if (c == null || c.size() == 0) { if (c == null || c.size() == 0) {
throw new AssertionException("Map should not be empty"); throw new AssertionException("Map should not be empty");
} }
} }
public static void same(Object expected, Object actual) { public static void same(Object expected, Object actual) {
if (expected != actual) { if (expected != actual) {
throw new AssertionException("Objects should be the same"); throw new AssertionException("Objects should be the same");
} }
} }
public static void isEmpty(@Nullable Collection<?> c) { public static void isEmpty(@Nullable Collection<?> c) {
if (c != null && !c.isEmpty()) { if (c != null && !c.isEmpty()) {
throw new AssertionException("Collection should be empty"); throw new AssertionException("Collection should be empty");
} }
} }
public static void shouldNotHappen() { public static void shouldNotHappen() {
throw new AssertionException("Should not happen"); throw new AssertionException("Should not happen");
} }
private static final class AssertionException extends RuntimeException { private static final class AssertionException extends RuntimeException {
private AssertionException(@Nonnull String message) { private AssertionException(@Nonnull String message) {
super(message); super(message);
} }
} }
} }

View File

@ -50,319 +50,319 @@ import javax.annotation.Nullable;
public class ActivityUi extends BaseUi { public class ActivityUi extends BaseUi {
private int layoutId; private int layoutId;
@Nonnull @Nonnull
private Preferences.Gui.Theme theme = Preferences.Gui.Theme.material_theme; private Preferences.Gui.Theme theme = Preferences.Gui.Theme.material_theme;
@Nonnull @Nonnull
private Preferences.Gui.Layout layout = Preferences.Gui.Layout.main_calculator; private Preferences.Gui.Layout layout = Preferences.Gui.Layout.main_calculator;
@Nonnull @Nonnull
private Language language = Languages.SYSTEM_LANGUAGE; private Language language = Languages.SYSTEM_LANGUAGE;
private int selectedNavigationIndex = 0; private int selectedNavigationIndex = 0;
public ActivityUi(@LayoutRes int layoutId, @Nonnull String logTag) { public ActivityUi(@LayoutRes int layoutId, @Nonnull String logTag) {
super(logTag); super(logTag);
this.layoutId = layoutId; this.layoutId = layoutId;
} }
public void setLayoutId(int layoutId) { public static boolean restartIfThemeChanged(@Nonnull Activity activity, @Nonnull Preferences.Gui.Theme oldTheme) {
this.layoutId = layoutId; final Preferences.Gui.Theme newTheme = Preferences.Gui.theme.getPreference(App.getPreferences());
} final int themeId = oldTheme.getThemeId(activity);
final int newThemeId = newTheme.getThemeId(activity);
if (themeId != newThemeId) {
Activities.restartActivity(activity);
return true;
}
return false;
}
public void onPreCreate(@Nonnull Activity activity) { public static boolean restartIfLanguageChanged(@Nonnull Activity activity, @Nonnull Language oldLanguage) {
final SharedPreferences preferences = App.getPreferences(); final Language current = App.getLanguages().getCurrent();
if (!current.equals(oldLanguage)) {
Activities.restartActivity(activity);
return true;
}
return false;
}
theme = Preferences.Gui.getTheme(preferences); public static void reportActivityStop(@Nonnull Activity activity) {
activity.setTheme(theme.getThemeId(activity)); App.getGa().getAnalytics().reportActivityStop(activity);
}
layout = Preferences.Gui.getLayout(preferences); public static void reportActivityStart(@Nonnull Activity activity) {
language = App.getLanguages().getCurrent(); App.getGa().getAnalytics().reportActivityStart(activity);
} }
@Override public void onPreCreate(@Nonnull Activity activity) {
public void onCreate(@Nonnull Activity activity) { final SharedPreferences preferences = App.getPreferences();
super.onCreate(activity);
App.getLanguages().updateLanguage(activity, false);
if (activity instanceof CalculatorEventListener) { theme = Preferences.Gui.getTheme(preferences);
Locator.getInstance().getCalculator().addCalculatorEventListener((CalculatorEventListener) activity); activity.setTheme(theme.getThemeId(activity));
}
activity.setContentView(layoutId); layout = Preferences.Gui.getLayout(preferences);
language = App.getLanguages().getCurrent();
}
final View root = activity.findViewById(R.id.main_layout); @Override
if (root != null) { public void onCreate(@Nonnull Activity activity) {
processButtons(activity, root); super.onCreate(activity);
fixFonts(root); App.getLanguages().updateLanguage(activity, false);
addHelpInfo(activity, root);
}
}
public void onCreate(@Nonnull final ActionBarActivity activity) { if (activity instanceof CalculatorEventListener) {
onCreate((Activity) activity); Locator.getInstance().getCalculator().addCalculatorEventListener((CalculatorEventListener) activity);
final ActionBar actionBar = activity.getSupportActionBar(); }
if (actionBar != null) {
initActionBar(activity, actionBar);
}
}
private void initActionBar(@Nonnull Activity activity, @Nonnull ActionBar actionBar) { activity.setContentView(layoutId);
actionBar.setDisplayUseLogoEnabled(false);
final boolean homeAsUp = !(activity instanceof CalculatorActivity);
actionBar.setDisplayHomeAsUpEnabled(homeAsUp);
actionBar.setHomeButtonEnabled(false);
actionBar.setDisplayShowHomeEnabled(true);
actionBar.setElevation(0);
toggleTitle(activity, actionBar, true); final View root = activity.findViewById(R.id.main_layout);
if (root != null) {
processButtons(activity, root);
fixFonts(root);
addHelpInfo(activity, root);
}
}
if (!homeAsUp) { public void onCreate(@Nonnull final ActionBarActivity activity) {
actionBar.setIcon(R.drawable.ab_logo); onCreate((Activity) activity);
} final ActionBar actionBar = activity.getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); if (actionBar != null) {
} initActionBar(activity, actionBar);
}
}
private void toggleTitle(@Nonnull Activity activity, @Nonnull ActionBar actionBar, boolean showTitle) { private void initActionBar(@Nonnull Activity activity, @Nonnull ActionBar actionBar) {
if (activity instanceof CalculatorActivity) { actionBar.setDisplayUseLogoEnabled(false);
if (Views.getScreenOrientation(activity) == Configuration.ORIENTATION_PORTRAIT) { final boolean homeAsUp = !(activity instanceof CalculatorActivity);
actionBar.setDisplayShowTitleEnabled(true); actionBar.setDisplayHomeAsUpEnabled(homeAsUp);
} else { actionBar.setHomeButtonEnabled(false);
actionBar.setDisplayShowTitleEnabled(false); actionBar.setDisplayShowHomeEnabled(true);
} actionBar.setElevation(0);
} else {
actionBar.setDisplayShowTitleEnabled(showTitle);
}
}
public void restoreSavedTab(@Nonnull ActionBarActivity activity) { toggleTitle(activity, actionBar, true);
final ActionBar actionBar = activity.getSupportActionBar();
if (actionBar != null) {
if (selectedNavigationIndex >= 0 && selectedNavigationIndex < actionBar.getTabCount()) {
actionBar.setSelectedNavigationItem(selectedNavigationIndex);
}
}
}
public void onSaveInstanceState(@Nonnull ActionBarActivity activity, @Nonnull Bundle outState) { if (!homeAsUp) {
onSaveInstanceState((Activity) activity, outState); actionBar.setIcon(R.drawable.ab_logo);
} }
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
}
public void onSaveInstanceState(@Nonnull Activity activity, @Nonnull Bundle outState) { private void toggleTitle(@Nonnull Activity activity, @Nonnull ActionBar actionBar, boolean showTitle) {
} if (activity instanceof CalculatorActivity) {
if (Views.getScreenOrientation(activity) == Configuration.ORIENTATION_PORTRAIT) {
actionBar.setDisplayShowTitleEnabled(true);
} else {
actionBar.setDisplayShowTitleEnabled(false);
}
} else {
actionBar.setDisplayShowTitleEnabled(showTitle);
}
}
public void onResume(@Nonnull Activity activity) { public void restoreSavedTab(@Nonnull ActionBarActivity activity) {
if (!restartIfThemeChanged(activity, theme)) { final ActionBar actionBar = activity.getSupportActionBar();
restartIfLanguageChanged(activity, language); if (actionBar != null) {
} if (selectedNavigationIndex >= 0 && selectedNavigationIndex < actionBar.getTabCount()) {
} actionBar.setSelectedNavigationItem(selectedNavigationIndex);
}
}
}
public static boolean restartIfThemeChanged(@Nonnull Activity activity, @Nonnull Preferences.Gui.Theme oldTheme) { public void onSaveInstanceState(@Nonnull ActionBarActivity activity, @Nonnull Bundle outState) {
final Preferences.Gui.Theme newTheme = Preferences.Gui.theme.getPreference(App.getPreferences()); onSaveInstanceState((Activity) activity, outState);
final int themeId = oldTheme.getThemeId(activity); }
final int newThemeId = newTheme.getThemeId(activity);
if (themeId != newThemeId) {
Activities.restartActivity(activity);
return true;
}
return false;
}
public static boolean restartIfLanguageChanged(@Nonnull Activity activity, @Nonnull Language oldLanguage) { public void onSaveInstanceState(@Nonnull Activity activity, @Nonnull Bundle outState) {
final Language current = App.getLanguages().getCurrent(); }
if (!current.equals(oldLanguage)) {
Activities.restartActivity(activity);
return true;
}
return false;
}
public void onPause(@Nonnull Activity activity) { public void onResume(@Nonnull Activity activity) {
} if (!restartIfThemeChanged(activity, theme)) {
restartIfLanguageChanged(activity, language);
}
}
public void onPause(@Nonnull ActionBarActivity activity) { public void onPause(@Nonnull Activity activity) {
onPause((Activity) activity); }
final ActionBar actionBar = activity.getSupportActionBar(); public void onPause(@Nonnull ActionBarActivity activity) {
if (actionBar != null) { onPause((Activity) activity);
final int selectedNavigationIndex = actionBar.getSelectedNavigationIndex();
if (selectedNavigationIndex >= 0) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
final SharedPreferences.Editor editor = preferences.edit();
editor.putInt(getSavedTabPreferenceName(activity), selectedNavigationIndex);
editor.apply();
}
}
}
@Nonnull final ActionBar actionBar = activity.getSupportActionBar();
private String getSavedTabPreferenceName(@Nonnull Activity activity) { if (actionBar != null) {
return "tab_" + activity.getClass().getSimpleName(); final int selectedNavigationIndex = actionBar.getSelectedNavigationIndex();
} if (selectedNavigationIndex >= 0) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
final SharedPreferences.Editor editor = preferences.edit();
editor.putInt(getSavedTabPreferenceName(activity), selectedNavigationIndex);
editor.apply();
}
}
}
@Override @Nonnull
public void onDestroy(@Nonnull Activity activity) { private String getSavedTabPreferenceName(@Nonnull Activity activity) {
super.onDestroy(activity); return "tab_" + activity.getClass().getSimpleName();
}
if (activity instanceof CalculatorEventListener) { @Override
Locator.getInstance().getCalculator().removeCalculatorEventListener((CalculatorEventListener) activity); public void onDestroy(@Nonnull Activity activity) {
} super.onDestroy(activity);
}
public void onDestroy(@Nonnull ActionBarActivity activity) { if (activity instanceof CalculatorEventListener) {
this.onDestroy((Activity) activity); Locator.getInstance().getCalculator().removeCalculatorEventListener((CalculatorEventListener) activity);
} }
}
public void addTab(@Nonnull ActionBarActivity activity, public void onDestroy(@Nonnull ActionBarActivity activity) {
@Nonnull String tag, this.onDestroy((Activity) activity);
@Nonnull Class<? extends Fragment> fragmentClass, }
@Nullable Bundle fragmentArgs,
int captionResId,
int parentViewId) {
final ActionBar actionBar = activity.getSupportActionBar();
final ActionBar.Tab tab = actionBar.newTab(); public void addTab(@Nonnull ActionBarActivity activity,
tab.setTag(tag); @Nonnull String tag,
tab.setText(captionResId); @Nonnull Class<? extends Fragment> fragmentClass,
@Nullable Bundle fragmentArgs,
int captionResId,
int parentViewId) {
final ActionBar actionBar = activity.getSupportActionBar();
final ActionBarFragmentTabListener listener = new ActionBarFragmentTabListener(activity, tag, fragmentClass, fragmentArgs, parentViewId); final ActionBar.Tab tab = actionBar.newTab();
tab.setTabListener(listener); tab.setTag(tag);
actionBar.addTab(tab); tab.setText(captionResId);
}
public void addTab(@Nonnull ActionBarActivity activity, @Nonnull CalculatorFragmentType fragmentType, @Nullable Bundle fragmentArgs, int parentViewId) { final ActionBarFragmentTabListener listener = new ActionBarFragmentTabListener(activity, tag, fragmentClass, fragmentArgs, parentViewId);
addTab(activity, fragmentType.getFragmentTag(), fragmentType.getFragmentClass(), fragmentArgs, fragmentType.getDefaultTitleResId(), parentViewId); tab.setTabListener(listener);
} actionBar.addTab(tab);
}
public void setFragment(@Nonnull ActionBarActivity activity, @Nonnull CalculatorFragmentType fragmentType, @Nullable Bundle fragmentArgs, int parentViewId) { public void addTab(@Nonnull ActionBarActivity activity, @Nonnull CalculatorFragmentType fragmentType, @Nullable Bundle fragmentArgs, int parentViewId) {
final FragmentManager fm = activity.getSupportFragmentManager(); addTab(activity, fragmentType.getFragmentTag(), fragmentType.getFragmentClass(), fragmentArgs, fragmentType.getDefaultTitleResId(), parentViewId);
}
Fragment fragment = fm.findFragmentByTag(fragmentType.getFragmentTag()); public void setFragment(@Nonnull ActionBarActivity activity, @Nonnull CalculatorFragmentType fragmentType, @Nullable Bundle fragmentArgs, int parentViewId) {
if (fragment == null) { final FragmentManager fm = activity.getSupportFragmentManager();
fragment = Fragment.instantiate(activity, fragmentType.getFragmentClass().getName(), fragmentArgs);
final FragmentTransaction ft = fm.beginTransaction();
ft.add(parentViewId, fragment, fragmentType.getFragmentTag());
ft.commit();
} else {
if (fragment.isDetached()) {
final FragmentTransaction ft = fm.beginTransaction();
ft.attach(fragment);
ft.commit();
}
} Fragment fragment = fm.findFragmentByTag(fragmentType.getFragmentTag());
} if (fragment == null) {
fragment = Fragment.instantiate(activity, fragmentType.getFragmentClass().getName(), fragmentArgs);
final FragmentTransaction ft = fm.beginTransaction();
ft.add(parentViewId, fragment, fragmentType.getFragmentTag());
ft.commit();
} else {
if (fragment.isDetached()) {
final FragmentTransaction ft = fm.beginTransaction();
ft.attach(fragment);
ft.commit();
}
public void selectTab(@Nonnull ActionBarActivity activity, @Nonnull CalculatorFragmentType fragmentType) { }
final ActionBar actionBar = activity.getSupportActionBar(); }
for (int i = 0; i < actionBar.getTabCount(); i++) {
final ActionBar.Tab tab = actionBar.getTabAt(i);
if (tab != null && fragmentType.getFragmentTag().equals(tab.getTag())) {
actionBar.setSelectedNavigationItem(i);
break;
}
}
}
public int getLayoutId() { public void selectTab(@Nonnull ActionBarActivity activity, @Nonnull CalculatorFragmentType fragmentType) {
return layoutId; final ActionBar actionBar = activity.getSupportActionBar();
} for (int i = 0; i < actionBar.getTabCount(); i++) {
final ActionBar.Tab tab = actionBar.getTabAt(i);
if (tab != null && fragmentType.getFragmentTag().equals(tab.getTag())) {
actionBar.setSelectedNavigationItem(i);
break;
}
}
}
@Nonnull public int getLayoutId() {
public Preferences.Gui.Theme getTheme() { return layoutId;
return theme; }
}
@Nonnull public void setLayoutId(int layoutId) {
public Language getLanguage() { this.layoutId = layoutId;
return language; }
}
@Nonnull @Nonnull
public Preferences.Gui.Layout getLayout() { public Preferences.Gui.Theme getTheme() {
return layout; return theme;
} }
public void onResume(@Nonnull ActionBarActivity activity) { @Nonnull
onResume((Activity) activity); public Language getLanguage() {
return language;
}
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity); @Nonnull
selectedNavigationIndex = preferences.getInt(getSavedTabPreferenceName(activity), -1); public Preferences.Gui.Layout getLayout() {
restoreSavedTab(activity); return layout;
} }
private void addHelpInfo(@Nonnull Activity activity, @Nonnull View root) { public void onResume(@Nonnull ActionBarActivity activity) {
if (CalculatorApplication.isMonkeyRunner(activity)) { onResume((Activity) activity);
if (root instanceof ViewGroup) {
final TextView helperTextView = new TextView(activity);
final DisplayMetrics dm = new DisplayMetrics(); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
activity.getWindowManager().getDefaultDisplay().getMetrics(dm); selectedNavigationIndex = preferences.getInt(getSavedTabPreferenceName(activity), -1);
restoreSavedTab(activity);
}
helperTextView.setTextSize(15); private void addHelpInfo(@Nonnull Activity activity, @Nonnull View root) {
helperTextView.setTextColor(Color.WHITE); if (CalculatorApplication.isMonkeyRunner(activity)) {
if (root instanceof ViewGroup) {
final TextView helperTextView = new TextView(activity);
final Configuration c = activity.getResources().getConfiguration(); final DisplayMetrics dm = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
final StringBuilder helpText = new StringBuilder(); helperTextView.setTextSize(15);
helpText.append("Size: "); helperTextView.setTextColor(Color.WHITE);
if (Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_XLARGE, c)) {
helpText.append("xlarge");
} else if (Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE, c)) {
helpText.append("large");
} else if (Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_NORMAL, c)) {
helpText.append("normal");
} else if (Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_SMALL, c)) {
helpText.append("small");
} else {
helpText.append("unknown");
}
helpText.append(" (").append(dm.widthPixels).append("x").append(dm.heightPixels).append(")"); final Configuration c = activity.getResources().getConfiguration();
helpText.append(" Density: "); final StringBuilder helpText = new StringBuilder();
switch (dm.densityDpi) { helpText.append("Size: ");
case DisplayMetrics.DENSITY_LOW: if (Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_XLARGE, c)) {
helpText.append("ldpi"); helpText.append("xlarge");
break; } else if (Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE, c)) {
case DisplayMetrics.DENSITY_MEDIUM: helpText.append("large");
helpText.append("mdpi"); } else if (Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_NORMAL, c)) {
break; helpText.append("normal");
case DisplayMetrics.DENSITY_HIGH: } else if (Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_SMALL, c)) {
helpText.append("hdpi"); helpText.append("small");
break; } else {
case DisplayMetrics.DENSITY_XHIGH: helpText.append("unknown");
helpText.append("xhdpi"); }
break;
case DisplayMetrics.DENSITY_TV:
helpText.append("tv");
break;
}
helpText.append(" (").append(dm.densityDpi).append(")"); helpText.append(" (").append(dm.widthPixels).append("x").append(dm.heightPixels).append(")");
helperTextView.setText(helpText); helpText.append(" Density: ");
switch (dm.densityDpi) {
case DisplayMetrics.DENSITY_LOW:
helpText.append("ldpi");
break;
case DisplayMetrics.DENSITY_MEDIUM:
helpText.append("mdpi");
break;
case DisplayMetrics.DENSITY_HIGH:
helpText.append("hdpi");
break;
case DisplayMetrics.DENSITY_XHIGH:
helpText.append("xhdpi");
break;
case DisplayMetrics.DENSITY_TV:
helpText.append("tv");
break;
}
((ViewGroup) root).addView(helperTextView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); helpText.append(" (").append(dm.densityDpi).append(")");
}
}
}
public void onStop(@Nonnull Activity activity) { helperTextView.setText(helpText);
reportActivityStop(activity);
}
public static void reportActivityStop(@Nonnull Activity activity) { ((ViewGroup) root).addView(helperTextView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
App.getGa().getAnalytics().reportActivityStop(activity); }
} }
}
public void onStart(@Nonnull Activity activity) { public void onStop(@Nonnull Activity activity) {
reportActivityStart(activity); reportActivityStop(activity);
} }
public static void reportActivityStart(@Nonnull Activity activity) { public void onStart(@Nonnull Activity activity) {
App.getGa().getAnalytics().reportActivityStart(activity); reportActivityStart(activity);
} }
} }

View File

@ -16,118 +16,118 @@ import javax.annotation.Nullable;
public class AdView extends FrameLayout { public class AdView extends FrameLayout {
@Nullable @Nullable
private com.google.android.gms.ads.AdView admobView; private com.google.android.gms.ads.AdView admobView;
@Nullable @Nullable
private AdView.AdViewListener admobListener; private AdView.AdViewListener admobListener;
public AdView(Context context) { public AdView(Context context) {
super(context); super(context);
} }
public AdView(Context context, AttributeSet attrs) { public AdView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
} }
public AdView(Context context, AttributeSet attrs, int defStyle) { public AdView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
} }
public void destroy() { public void destroy() {
destroyAdmobView(); destroyAdmobView();
} }
private void destroyAdmobView() { private void destroyAdmobView() {
if (admobView != null) { if (admobView != null) {
admobView.destroy(); admobView.destroy();
admobView.setAdListener(null); admobView.setAdListener(null);
admobView = null; admobView = null;
} }
if(admobListener != null) { if (admobListener != null) {
admobListener.destroy(); admobListener.destroy();
admobListener = null; admobListener = null;
} }
} }
public void pause() { public void pause() {
if (admobView != null) { if (admobView != null) {
admobView.pause(); admobView.pause();
} }
} }
public void resume() { public void resume() {
if (admobView != null) { if (admobView != null) {
admobView.resume(); admobView.resume();
} }
} }
public void show() { public void show() {
if (admobView != null) { if (admobView != null) {
return; return;
} }
LayoutInflater.from(getContext()).inflate(R.layout.admob, this); LayoutInflater.from(getContext()).inflate(R.layout.admob, this);
admobView = (com.google.android.gms.ads.AdView) findViewById(R.id.admob); admobView = (com.google.android.gms.ads.AdView) findViewById(R.id.admob);
Check.isNotNull(admobView); Check.isNotNull(admobView);
if (admobView == null) { if (admobView == null) {
return; return;
} }
admobListener = new AdView.AdViewListener(this); admobListener = new AdView.AdViewListener(this);
admobView.setAdListener(admobListener); admobView.setAdListener(admobListener);
final AdRequest.Builder b = new AdRequest.Builder(); final AdRequest.Builder b = new AdRequest.Builder();
b.addTestDevice(AdRequest.DEVICE_ID_EMULATOR); b.addTestDevice(AdRequest.DEVICE_ID_EMULATOR);
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
// LG Nexus 5 // LG Nexus 5
b.addTestDevice("B80E676D60CE6FDBE1B84A55464E3FE1"); b.addTestDevice("B80E676D60CE6FDBE1B84A55464E3FE1");
} }
admobView.loadAd(b.build()); admobView.loadAd(b.build());
} }
public void hide() { public void hide() {
if(admobView == null) { if (admobView == null) {
return; return;
} }
setVisibility(GONE); setVisibility(GONE);
admobView.setVisibility(View.GONE); admobView.setVisibility(View.GONE);
admobView.pause(); admobView.pause();
destroyAdmobView(); destroyAdmobView();
} }
private static class AdViewListener extends AdListener { private static class AdViewListener extends AdListener {
@Nullable @Nullable
private AdView adView; private AdView adView;
public AdViewListener(@Nonnull AdView adView) { public AdViewListener(@Nonnull AdView adView) {
this.adView = adView; this.adView = adView;
} }
void destroy() { void destroy() {
adView = null; adView = null;
} }
@Override @Override
public void onAdFailedToLoad(int errorCode) { public void onAdFailedToLoad(int errorCode) {
if (adView != null) { if (adView != null) {
adView.hide(); adView.hide();
adView = null; adView = null;
} }
} }
@Override @Override
public void onAdLoaded() { public void onAdLoaded() {
if (adView != null) { if (adView != null) {
final com.google.android.gms.ads.AdView admobView = adView.admobView; final com.google.android.gms.ads.AdView admobView = adView.admobView;
if (admobView != null) { if (admobView != null) {
admobView.setVisibility(View.VISIBLE); admobView.setVisibility(View.VISIBLE);
} }
adView.setVisibility(VISIBLE); adView.setVisibility(VISIBLE);
adView = null; adView = null;
} }
} }
} }
} }

View File

@ -46,192 +46,192 @@ import jscl.math.Generic;
*/ */
public class AndroidCalculator implements Calculator, CalculatorEventListener, SharedPreferences.OnSharedPreferenceChangeListener { public class AndroidCalculator implements Calculator, CalculatorEventListener, SharedPreferences.OnSharedPreferenceChangeListener {
@Nonnull @Nonnull
private final CalculatorImpl calculator = new CalculatorImpl(); private final CalculatorImpl calculator = new CalculatorImpl();
@Nonnull @Nonnull
private final Application context; private final Application context;
public AndroidCalculator(@Nonnull Application application) { public AndroidCalculator(@Nonnull Application application) {
this.context = application; this.context = application;
this.calculator.addCalculatorEventListener(this); this.calculator.addCalculatorEventListener(this);
PreferenceManager.getDefaultSharedPreferences(application).registerOnSharedPreferenceChangeListener(this); PreferenceManager.getDefaultSharedPreferences(application).registerOnSharedPreferenceChangeListener(this);
} }
/* /*
********************************************************************** **********************************************************************
* *
* DELEGATED TO CALCULATOR * DELEGATED TO CALCULATOR
* *
********************************************************************** **********************************************************************
*/ */
@Override @Override
@Nonnull @Nonnull
public CalculatorEventData evaluate(@Nonnull JsclOperation operation, @Nonnull String expression) { public CalculatorEventData evaluate(@Nonnull JsclOperation operation, @Nonnull String expression) {
return calculator.evaluate(operation, expression); return calculator.evaluate(operation, expression);
} }
@Override @Override
@Nonnull @Nonnull
public CalculatorEventData evaluate(@Nonnull JsclOperation operation, @Nonnull String expression, @Nonnull Long sequenceId) { public CalculatorEventData evaluate(@Nonnull JsclOperation operation, @Nonnull String expression, @Nonnull Long sequenceId) {
return calculator.evaluate(operation, expression, sequenceId); return calculator.evaluate(operation, expression, sequenceId);
} }
@Override @Override
public void setCalculateOnFly(boolean calculateOnFly) { public boolean isCalculateOnFly() {
calculator.setCalculateOnFly(calculateOnFly); return calculator.isCalculateOnFly();
} }
@Override @Override
public boolean isCalculateOnFly() { public void setCalculateOnFly(boolean calculateOnFly) {
return calculator.isCalculateOnFly(); calculator.setCalculateOnFly(calculateOnFly);
} }
@Override @Override
public boolean isConversionPossible(@Nonnull Generic generic, @Nonnull NumeralBase from, @Nonnull NumeralBase to) { public boolean isConversionPossible(@Nonnull Generic generic, @Nonnull NumeralBase from, @Nonnull NumeralBase to) {
return calculator.isConversionPossible(generic, from, to); return calculator.isConversionPossible(generic, from, to);
} }
@Override @Override
@Nonnull @Nonnull
public CalculatorEventData convert(@Nonnull Generic generic, @Nonnull NumeralBase to) { public CalculatorEventData convert(@Nonnull Generic generic, @Nonnull NumeralBase to) {
return calculator.convert(generic, to); return calculator.convert(generic, to);
} }
@Override @Override
@Nonnull @Nonnull
public CalculatorEventData fireCalculatorEvent(@Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) { public CalculatorEventData fireCalculatorEvent(@Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
return calculator.fireCalculatorEvent(calculatorEventType, data); return calculator.fireCalculatorEvent(calculatorEventType, data);
} }
@Nonnull @Nonnull
@Override @Override
public CalculatorEventData fireCalculatorEvent(@Nonnull CalculatorEventType calculatorEventType, @Nullable Object data, @Nonnull Object source) { public CalculatorEventData fireCalculatorEvent(@Nonnull CalculatorEventType calculatorEventType, @Nullable Object data, @Nonnull Object source) {
return calculator.fireCalculatorEvent(calculatorEventType, data, source); return calculator.fireCalculatorEvent(calculatorEventType, data, source);
} }
@Override @Override
@Nonnull @Nonnull
public CalculatorEventData fireCalculatorEvent(@Nonnull CalculatorEventType calculatorEventType, @Nullable Object data, @Nonnull Long sequenceId) { public CalculatorEventData fireCalculatorEvent(@Nonnull CalculatorEventType calculatorEventType, @Nullable Object data, @Nonnull Long sequenceId) {
return calculator.fireCalculatorEvent(calculatorEventType, data, sequenceId); return calculator.fireCalculatorEvent(calculatorEventType, data, sequenceId);
} }
@Nonnull @Nonnull
@Override @Override
public PreparedExpression prepareExpression(@Nonnull String expression) throws CalculatorParseException { public PreparedExpression prepareExpression(@Nonnull String expression) throws CalculatorParseException {
return calculator.prepareExpression(expression); return calculator.prepareExpression(expression);
} }
@Override @Override
public void init() { public void init() {
this.calculator.init(); this.calculator.init();
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
this.calculator.setCalculateOnFly(Preferences.Calculations.calculateOnFly.getPreference(prefs)); this.calculator.setCalculateOnFly(Preferences.Calculations.calculateOnFly.getPreference(prefs));
} }
@Override @Override
public void addCalculatorEventListener(@Nonnull CalculatorEventListener calculatorEventListener) { public void addCalculatorEventListener(@Nonnull CalculatorEventListener calculatorEventListener) {
calculator.addCalculatorEventListener(calculatorEventListener); calculator.addCalculatorEventListener(calculatorEventListener);
} }
@Override @Override
public void removeCalculatorEventListener(@Nonnull CalculatorEventListener calculatorEventListener) { public void removeCalculatorEventListener(@Nonnull CalculatorEventListener calculatorEventListener) {
calculator.removeCalculatorEventListener(calculatorEventListener); calculator.removeCalculatorEventListener(calculatorEventListener);
} }
@Override @Override
public void fireCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) { public void fireCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
calculator.fireCalculatorEvent(calculatorEventData, calculatorEventType, data); calculator.fireCalculatorEvent(calculatorEventData, calculatorEventType, data);
} }
@Override @Override
public void fireCalculatorEvents(@Nonnull List<CalculatorEvent> calculatorEvents) { public void fireCalculatorEvents(@Nonnull List<CalculatorEvent> calculatorEvents) {
calculator.fireCalculatorEvents(calculatorEvents); calculator.fireCalculatorEvents(calculatorEvents);
} }
@Override @Override
public void doHistoryAction(@Nonnull HistoryAction historyAction) { public void doHistoryAction(@Nonnull HistoryAction historyAction) {
calculator.doHistoryAction(historyAction); calculator.doHistoryAction(historyAction);
} }
@Override @Override
public void setCurrentHistoryState(@Nonnull CalculatorHistoryState editorHistoryState) { @Nonnull
calculator.setCurrentHistoryState(editorHistoryState); public CalculatorHistoryState getCurrentHistoryState() {
} return calculator.getCurrentHistoryState();
}
@Override @Override
@Nonnull public void setCurrentHistoryState(@Nonnull CalculatorHistoryState editorHistoryState) {
public CalculatorHistoryState getCurrentHistoryState() { calculator.setCurrentHistoryState(editorHistoryState);
return calculator.getCurrentHistoryState(); }
}
@Override @Override
public void evaluate() { public void evaluate() {
calculator.evaluate(); calculator.evaluate();
} }
@Override @Override
public void evaluate(@Nonnull Long sequenceId) { public void evaluate(@Nonnull Long sequenceId) {
calculator.evaluate(sequenceId); calculator.evaluate(sequenceId);
} }
@Override @Override
public void simplify() { public void simplify() {
calculator.simplify(); calculator.simplify();
} }
@Override @Override
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) { public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
switch (calculatorEventType) { switch (calculatorEventType) {
case calculation_messages: case calculation_messages:
CalculatorActivityLauncher.showCalculationMessagesDialog(CalculatorApplication.getInstance(), (List<Message>) data); CalculatorActivityLauncher.showCalculationMessagesDialog(CalculatorApplication.getInstance(), (List<Message>) data);
break; break;
case show_history: case show_history:
CalculatorActivityLauncher.showHistory(CalculatorApplication.getInstance()); CalculatorActivityLauncher.showHistory(CalculatorApplication.getInstance());
break; break;
case show_history_detached: case show_history_detached:
CalculatorActivityLauncher.showHistory(CalculatorApplication.getInstance(), true); CalculatorActivityLauncher.showHistory(CalculatorApplication.getInstance(), true);
break; break;
case show_functions: case show_functions:
CalculatorActivityLauncher.showFunctions(CalculatorApplication.getInstance()); CalculatorActivityLauncher.showFunctions(CalculatorApplication.getInstance());
break; break;
case show_functions_detached: case show_functions_detached:
CalculatorActivityLauncher.showFunctions(CalculatorApplication.getInstance(), true); CalculatorActivityLauncher.showFunctions(CalculatorApplication.getInstance(), true);
break; break;
case show_operators: case show_operators:
CalculatorActivityLauncher.showOperators(CalculatorApplication.getInstance()); CalculatorActivityLauncher.showOperators(CalculatorApplication.getInstance());
break; break;
case show_operators_detached: case show_operators_detached:
CalculatorActivityLauncher.showOperators(CalculatorApplication.getInstance(), true); CalculatorActivityLauncher.showOperators(CalculatorApplication.getInstance(), true);
break; break;
case show_vars: case show_vars:
CalculatorActivityLauncher.showVars(CalculatorApplication.getInstance()); CalculatorActivityLauncher.showVars(CalculatorApplication.getInstance());
break; break;
case show_vars_detached: case show_vars_detached:
CalculatorActivityLauncher.showVars(CalculatorApplication.getInstance(), true); CalculatorActivityLauncher.showVars(CalculatorApplication.getInstance(), true);
break; break;
case show_settings: case show_settings:
CalculatorActivityLauncher.showSettings(CalculatorApplication.getInstance()); CalculatorActivityLauncher.showSettings(CalculatorApplication.getInstance());
break; break;
case show_settings_detached: case show_settings_detached:
CalculatorActivityLauncher.showSettings(CalculatorApplication.getInstance(), true); CalculatorActivityLauncher.showSettings(CalculatorApplication.getInstance(), true);
break; break;
case show_like_dialog: case show_like_dialog:
CalculatorActivityLauncher.likeButtonPressed(CalculatorApplication.getInstance()); CalculatorActivityLauncher.likeButtonPressed(CalculatorApplication.getInstance());
break; break;
case open_app: case open_app:
CalculatorActivityLauncher.openApp(CalculatorApplication.getInstance()); CalculatorActivityLauncher.openApp(CalculatorApplication.getInstance());
break; break;
} }
} }
@Override @Override
public void onSharedPreferenceChanged(@Nonnull SharedPreferences prefs, @Nonnull String key) { public void onSharedPreferenceChanged(@Nonnull SharedPreferences prefs, @Nonnull String key) {
if (Preferences.Calculations.calculateOnFly.getKey().equals(key)) { if (Preferences.Calculations.calculateOnFly.getKey().equals(key)) {
this.calculator.setCalculateOnFly(Preferences.Calculations.calculateOnFly.getPreference(prefs)); this.calculator.setCalculateOnFly(Preferences.Calculations.calculateOnFly.getPreference(prefs));
} }
} }
} }

View File

@ -35,32 +35,32 @@ import javax.annotation.Nonnull;
*/ */
public class AndroidCalculatorClipboard implements CalculatorClipboard { public class AndroidCalculatorClipboard implements CalculatorClipboard {
@Nonnull @Nonnull
private final Context context; private final Context context;
public AndroidCalculatorClipboard(@Nonnull Application application) { public AndroidCalculatorClipboard(@Nonnull Application application) {
this.context = application; this.context = application;
} }
@Override @Override
public String getText() { public String getText() {
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
if (clipboard.hasText()) { if (clipboard.hasText()) {
return String.valueOf(clipboard.getText()); return String.valueOf(clipboard.getText());
} else { } else {
return null; return null;
} }
} }
@Override @Override
public void setText(@Nonnull String text) { public void setText(@Nonnull CharSequence text) {
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
clipboard.setText(text); clipboard.setText(text);
} }
@Override @Override
public void setText(@Nonnull CharSequence text) { public void setText(@Nonnull String text) {
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
clipboard.setText(text); clipboard.setText(text);
} }
} }

View File

@ -47,15 +47,15 @@ import javax.annotation.Nullable;
public class AndroidCalculatorDisplayView extends AutoResizeTextView implements CalculatorDisplayView { public class AndroidCalculatorDisplayView extends AutoResizeTextView implements CalculatorDisplayView {
/* /*
********************************************************************** **********************************************************************
* *
* STATIC FIELDS * STATIC FIELDS
* *
********************************************************************** **********************************************************************
*/ */
@Nonnull @Nonnull
private final TextProcessor<TextProcessorEditorResult, String> textHighlighter; private final TextProcessor<TextProcessorEditorResult, String> textHighlighter;
/* /*
********************************************************************** **********************************************************************
@ -64,17 +64,13 @@ public class AndroidCalculatorDisplayView extends AutoResizeTextView implements
* *
********************************************************************** **********************************************************************
*/ */
@Nonnull
@Nonnull private final Object lock = new Object();
private volatile CalculatorDisplayViewState state = CalculatorDisplayViewStateImpl.newDefaultInstance(); @Nonnull
private final Handler uiHandler = new Handler();
@Nonnull @Nonnull
private final Object lock = new Object(); private volatile CalculatorDisplayViewState state = CalculatorDisplayViewStateImpl.newDefaultInstance();
private volatile boolean initialized = false;
@Nonnull
private final Handler uiHandler = new Handler();
private volatile boolean initialized = false;
/* /*
********************************************************************** **********************************************************************
@ -84,20 +80,20 @@ public class AndroidCalculatorDisplayView extends AutoResizeTextView implements
********************************************************************** **********************************************************************
*/ */
public AndroidCalculatorDisplayView(Context context) { public AndroidCalculatorDisplayView(Context context) {
super(context); super(context);
textHighlighter = new TextHighlighter(getTextColors().getDefaultColor(), false); textHighlighter = new TextHighlighter(getTextColors().getDefaultColor(), false);
} }
public AndroidCalculatorDisplayView(Context context, AttributeSet attrs) { public AndroidCalculatorDisplayView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
textHighlighter = new TextHighlighter(getTextColors().getDefaultColor(), false); textHighlighter = new TextHighlighter(getTextColors().getDefaultColor(), false);
} }
public AndroidCalculatorDisplayView(Context context, AttributeSet attrs, int defStyle) { public AndroidCalculatorDisplayView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
textHighlighter = new TextHighlighter(getTextColors().getDefaultColor(), false); textHighlighter = new TextHighlighter(getTextColors().getDefaultColor(), false);
} }
/* /*
********************************************************************** **********************************************************************
@ -107,100 +103,99 @@ public class AndroidCalculatorDisplayView extends AutoResizeTextView implements
********************************************************************** **********************************************************************
*/ */
private Preferences.Gui.TextColor getTextColor() {
final Context context = getContext();
return App.getThemeIn(context).getTextColor(context);
}
@Override @Nonnull
public void setState(@Nonnull final CalculatorDisplayViewState state) { @Override
public CalculatorDisplayViewState getState() {
synchronized (lock) {
return this.state;
}
}
uiHandler.post(new Runnable() { @Override
@Override public void setState(@Nonnull final CalculatorDisplayViewState state) {
public void run() {
synchronized (lock) { uiHandler.post(new Runnable() {
@Override
public void run() {
final CharSequence text = prepareText(state.getStringResult(), state.isValid()); synchronized (lock) {
AndroidCalculatorDisplayView.this.state = state; final CharSequence text = prepareText(state.getStringResult(), state.isValid());
if (state.isValid()) {
setTextColor(getTextColor().normal);
setText(text);
adjustTextSize(); AndroidCalculatorDisplayView.this.state = state;
if (state.isValid()) {
setTextColor(getTextColor().normal);
setText(text);
} else { adjustTextSize();
// update text in order to get rid of HTML tags
setText(getText().toString());
setTextColor(getTextColor().error);
// error messages are never shown -> just greyed out text (error message will be shown on click) } else {
//setText(state.getErrorMessage()); // update text in order to get rid of HTML tags
//redraw(); setText(getText().toString());
} setTextColor(getTextColor().error);
}
}
});
}
private Preferences.Gui.TextColor getTextColor() { // error messages are never shown -> just greyed out text (error message will be shown on click)
final Context context = getContext(); //setText(state.getErrorMessage());
return App.getThemeIn(context).getTextColor(context); //redraw();
} }
}
}
});
}
@Nonnull @Nullable
@Override private CharSequence prepareText(@Nullable String text, boolean valid) {
public CalculatorDisplayViewState getState() { CharSequence result;
synchronized (lock) {
return this.state;
}
}
@Nullable if (valid && text != null) {
private CharSequence prepareText(@Nullable String text, boolean valid) { try {
CharSequence result; final TextProcessorEditorResult processedText = textHighlighter.process(text);
text = processedText.toString();
result = Html.fromHtml(text);
} catch (CalculatorParseException e) {
result = text;
}
} else {
result = text;
}
if (valid && text != null) { return result;
try { }
final TextProcessorEditorResult processedText = textHighlighter.process(text);
text = processedText.toString();
result = Html.fromHtml(text);
} catch (CalculatorParseException e) {
result = text;
}
} else {
result = text;
}
return result; private void adjustTextSize() {
} // todo serso: think where to move it (keep in mind org.solovyev.android.view.AutoResizeTextView.resetTextSize())
setAddEllipsis(false);
setMinTextSize(10);
resizeText();
}
private void adjustTextSize() { public synchronized void init(@Nonnull Context context) {
// todo serso: think where to move it (keep in mind org.solovyev.android.view.AutoResizeTextView.resetTextSize()) this.init(context, true);
setAddEllipsis(false); }
setMinTextSize(10);
resizeText();
}
public synchronized void init(@Nonnull Context context) { public synchronized void init(@Nonnull Context context, boolean fromApp) {
this.init(context, true); if (!initialized) {
} if (fromApp) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
final Preferences.Gui.Layout layout = Preferences.Gui.getLayout(preferences);
public synchronized void init(@Nonnull Context context, boolean fromApp) { if (!layout.isOptimized()) {
if (!initialized) { setTextSize(TypedValue.COMPLEX_UNIT_SP, getResources().getDimension(R.dimen.cpp_display_text_size_mobile));
if (fromApp) { }
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
final Preferences.Gui.Layout layout = Preferences.Gui.getLayout(preferences);
if (!layout.isOptimized()) { if (context instanceof FragmentActivity) {
setTextSize(TypedValue.COMPLEX_UNIT_SP, getResources().getDimension(R.dimen.cpp_display_text_size_mobile)); this.setOnClickListener(new CalculatorDisplayOnClickListener((FragmentActivity) context));
} } else {
throw new IllegalArgumentException("Must be fragment activity, got " + context.getClass());
}
}
if (context instanceof FragmentActivity) { this.initialized = true;
this.setOnClickListener(new CalculatorDisplayOnClickListener((FragmentActivity) context)); }
} else { }
throw new IllegalArgumentException("Must be fragment activity, got " + context.getClass());
}
}
this.initialized = true;
}
}
} }

View File

@ -43,140 +43,137 @@ import javax.annotation.Nonnull;
*/ */
public class AndroidCalculatorEditorView extends EditText implements CalculatorEditorView { public class AndroidCalculatorEditorView extends EditText implements CalculatorEditorView {
private volatile boolean initialized = false; @Nonnull
private final Handler uiHandler = new Handler();
private volatile boolean initialized = false;
@SuppressWarnings("UnusedDeclaration")
@Nonnull
private volatile CalculatorEditorViewState viewState = CalculatorEditorViewStateImpl.newDefaultInstance();
private volatile boolean viewStateChange = false;
@SuppressWarnings("UnusedDeclaration") public AndroidCalculatorEditorView(Context context) {
@Nonnull super(context);
private volatile CalculatorEditorViewState viewState = CalculatorEditorViewStateImpl.newDefaultInstance(); }
private volatile boolean viewStateChange = false; public AndroidCalculatorEditorView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Nonnull public AndroidCalculatorEditorView(Context context, AttributeSet attrs, int defStyle) {
private final Handler uiHandler = new Handler(); super(context, attrs, defStyle);
}
public AndroidCalculatorEditorView(Context context) { @Override
super(context); public boolean onCheckIsTextEditor() {
} // NOTE: code below can be used carefully and should not be copied without special intention
// The main purpose of code is to disable soft input (virtual keyboard) but leave all the TextEdit functionality, like cursor, scrolling, copy/paste menu etc
public AndroidCalculatorEditorView(Context context, AttributeSet attrs) { if (Build.VERSION.SDK_INT >= 11) {
super(context, attrs); // fix for missing cursor in android 3 and higher
} try {
// IDEA: return false always except if method was called from TextView.isCursorVisible() method
for (StackTraceElement stackTraceElement : Collections.asList(Thread.currentThread().getStackTrace())) {
if ("isCursorVisible".equals(stackTraceElement.getMethodName())) {
return true;
}
}
} catch (RuntimeException e) {
// just in case...
}
public AndroidCalculatorEditorView(Context context, AttributeSet attrs, int defStyle) { return false;
super(context, attrs, defStyle); } else {
} return false;
}
}
@Override @Override
public boolean onCheckIsTextEditor() { protected void onCreateContextMenu(ContextMenu menu) {
// NOTE: code below can be used carefully and should not be copied without special intention super.onCreateContextMenu(menu);
// The main purpose of code is to disable soft input (virtual keyboard) but leave all the TextEdit functionality, like cursor, scrolling, copy/paste menu etc
if (Build.VERSION.SDK_INT >= 11) { menu.removeItem(android.R.id.selectAll);
// fix for missing cursor in android 3 and higher }
try {
// IDEA: return false always except if method was called from TextView.isCursorVisible() method
for (StackTraceElement stackTraceElement : Collections.asList(Thread.currentThread().getStackTrace())) {
if ("isCursorVisible".equals(stackTraceElement.getMethodName())) {
return true;
}
}
} catch (RuntimeException e) {
// just in case...
}
return false; public void setHighlightText(boolean highlightText) {
} else { //this.highlightText = highlightText;
return false; Locator.getInstance().getEditor().updateViewState();
} }
}
@Override public synchronized void init() {
protected void onCreateContextMenu(ContextMenu menu) { if (!initialized) {
super.onCreateContextMenu(menu); this.addTextChangedListener(new TextWatcherImpl());
menu.removeItem(android.R.id.selectAll); initialized = true;
} }
}
public void setHighlightText(boolean highlightText) { @Override
//this.highlightText = highlightText; public void setState(@Nonnull final CalculatorEditorViewState viewState) {
Locator.getInstance().getEditor().updateViewState(); synchronized (this) {
}
public synchronized void init() { uiHandler.post(new Runnable() {
if (!initialized) { @Override
this.addTextChangedListener(new TextWatcherImpl()); public void run() {
final AndroidCalculatorEditorView editorView = AndroidCalculatorEditorView.this;
synchronized (AndroidCalculatorEditorView.this) {
try {
editorView.viewStateChange = true;
editorView.viewState = viewState;
if (App.getTheme().isLight() && getContext() instanceof CalculatorOnscreenService) {
// don't need formatting
editorView.setText(viewState.getText());
} else {
editorView.setText(viewState.getTextAsCharSequence(), BufferType.EDITABLE);
}
final int selection = CalculatorEditorImpl.correctSelection(viewState.getSelection(), editorView.getText());
editorView.setSelection(selection);
} finally {
editorView.viewStateChange = false;
}
}
}
});
}
}
initialized = true; @Override
} protected void onSelectionChanged(int selStart, int selEnd) {
} synchronized (this) {
if (initialized && !viewStateChange) {
// external text change => need to notify editor
super.onSelectionChanged(selStart, selEnd);
@Override if (selStart == selEnd) {
public void setState(@Nonnull final CalculatorEditorViewState viewState) { // only if cursor moving, if selection do nothing
synchronized (this) { Locator.getInstance().getEditor().setSelection(selStart);
}
}
}
}
uiHandler.post(new Runnable() { public void handleTextChange(Editable s) {
@Override synchronized (this) {
public void run() { if (initialized && !viewStateChange) {
final AndroidCalculatorEditorView editorView = AndroidCalculatorEditorView.this; // external text change => need to notify editor
synchronized (AndroidCalculatorEditorView.this) { Locator.getInstance().getEditor().setText(String.valueOf(s));
try { }
editorView.viewStateChange = true; }
editorView.viewState = viewState; }
if (App.getTheme().isLight() && getContext() instanceof CalculatorOnscreenService) {
// don't need formatting
editorView.setText(viewState.getText());
} else {
editorView.setText(viewState.getTextAsCharSequence(), BufferType.EDITABLE);
}
final int selection = CalculatorEditorImpl.correctSelection(viewState.getSelection(), editorView.getText());
editorView.setSelection(selection);
} finally {
editorView.viewStateChange = false;
}
}
}
});
}
}
@Override private final class TextWatcherImpl implements TextWatcher {
protected void onSelectionChanged(int selStart, int selEnd) {
synchronized (this) {
if (initialized && !viewStateChange) {
// external text change => need to notify editor
super.onSelectionChanged(selStart, selEnd);
if (selStart == selEnd) { @Override
// only if cursor moving, if selection do nothing public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Locator.getInstance().getEditor().setSelection(selStart);
}
}
}
}
public void handleTextChange(Editable s) { }
synchronized (this) {
if (initialized && !viewStateChange) {
// external text change => need to notify editor
Locator.getInstance().getEditor().setText(String.valueOf(s));
}
}
}
private final class TextWatcherImpl implements TextWatcher { @Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override @Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { public void afterTextChanged(Editable s) {
handleTextChange(s);
} }
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
handleTextChange(s);
}
}
} }

View File

@ -22,13 +22,8 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.app.Activity;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import org.solovyev.android.view.VibratorContainer;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -40,71 +35,71 @@ import javax.annotation.Nullable;
*/ */
public class AndroidCalculatorKeyboard implements CalculatorKeyboard { public class AndroidCalculatorKeyboard implements CalculatorKeyboard {
@Nonnull @Nonnull
private final CalculatorKeyboard calculatorKeyboard; private final CalculatorKeyboard calculatorKeyboard;
@Nonnull @Nonnull
private final Context context; private final Context context;
@android.support.annotation.Nullable @android.support.annotation.Nullable
private org.solovyev.android.calculator.Vibrator vibrator; private org.solovyev.android.calculator.Vibrator vibrator;
public AndroidCalculatorKeyboard(@Nonnull Application application, public AndroidCalculatorKeyboard(@Nonnull Application application,
@Nonnull CalculatorKeyboard calculatorKeyboard) { @Nonnull CalculatorKeyboard calculatorKeyboard) {
this.context = application; this.context = application;
this.calculatorKeyboard = calculatorKeyboard; this.calculatorKeyboard = calculatorKeyboard;
} }
@Override @Override
public boolean buttonPressed(@Nullable String text) { public boolean buttonPressed(@Nullable String text) {
App.getGa().onButtonPressed(text); App.getGa().onButtonPressed(text);
final boolean processed = calculatorKeyboard.buttonPressed(text); final boolean processed = calculatorKeyboard.buttonPressed(text);
if (processed) { if (processed) {
vibrate(); vibrate();
} }
return processed; return processed;
} }
private void vibrate() { private void vibrate() {
if (vibrator == null) { if (vibrator == null) {
vibrator = App.getVibrator(); vibrator = App.getVibrator();
} }
vibrator.vibrate(); vibrator.vibrate();
} }
@Override @Override
public void roundBracketsButtonPressed() { public void roundBracketsButtonPressed() {
vibrate(); vibrate();
calculatorKeyboard.roundBracketsButtonPressed(); calculatorKeyboard.roundBracketsButtonPressed();
} }
@Override @Override
public void pasteButtonPressed() { public void pasteButtonPressed() {
vibrate(); vibrate();
calculatorKeyboard.pasteButtonPressed(); calculatorKeyboard.pasteButtonPressed();
} }
@Override @Override
public void clearButtonPressed() { public void clearButtonPressed() {
vibrate(); vibrate();
calculatorKeyboard.clearButtonPressed(); calculatorKeyboard.clearButtonPressed();
} }
@Override @Override
public void copyButtonPressed() { public void copyButtonPressed() {
vibrate(); vibrate();
calculatorKeyboard.copyButtonPressed(); calculatorKeyboard.copyButtonPressed();
} }
@Override @Override
public void moveCursorLeft() { public void moveCursorLeft() {
vibrate(); vibrate();
calculatorKeyboard.moveCursorLeft(); calculatorKeyboard.moveCursorLeft();
} }
@Override @Override
public void moveCursorRight() { public void moveCursorRight() {
vibrate(); vibrate();
calculatorKeyboard.moveCursorRight(); calculatorKeyboard.moveCursorRight();
} }
} }

View File

@ -34,31 +34,31 @@ import javax.annotation.Nullable;
*/ */
public class AndroidCalculatorLogger implements CalculatorLogger { public class AndroidCalculatorLogger implements CalculatorLogger {
@Nonnull @Nonnull
private static final String TAG = "Calculatorpp"; private static final String TAG = "Calculatorpp";
@Override @Override
public void debug(@Nullable String tag, @Nonnull String message) { public void debug(@Nullable String tag, @Nonnull String message) {
Log.d(getTag(tag), message); Log.d(getTag(tag), message);
} }
@Nonnull @Nonnull
private String getTag(@Nullable String tag) { private String getTag(@Nullable String tag) {
return tag != null ? TAG + "/" + tag : TAG; return tag != null ? TAG + "/" + tag : TAG;
} }
@Override @Override
public void debug(@Nullable String tag, @Nullable String message, @Nonnull Throwable e) { public void debug(@Nullable String tag, @Nullable String message, @Nonnull Throwable e) {
Log.d(getTag(tag), message, e); Log.d(getTag(tag), message, e);
} }
@Override @Override
public void error(@Nullable String tag, @Nullable String message, @Nonnull Throwable e) { public void error(@Nullable String tag, @Nullable String message, @Nonnull Throwable e) {
Log.e(getTag(tag), message, e); Log.e(getTag(tag), message, e);
} }
@Override @Override
public void error(@Nullable String tag, @Nullable String message) { public void error(@Nullable String tag, @Nullable String message) {
Log.e(getTag(tag), message); Log.e(getTag(tag), message);
} }
} }

View File

@ -25,14 +25,16 @@ package org.solovyev.android.calculator;
import android.app.Application; import android.app.Application;
import android.os.Handler; import android.os.Handler;
import android.widget.Toast; import android.widget.Toast;
import org.solovyev.android.Threads; import org.solovyev.android.Threads;
import org.solovyev.android.msg.AndroidMessage; import org.solovyev.android.msg.AndroidMessage;
import org.solovyev.common.msg.Message; import org.solovyev.common.msg.Message;
import org.solovyev.common.msg.MessageType; import org.solovyev.common.msg.MessageType;
import java.util.List;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.List;
/** /**
* User: serso * User: serso
@ -41,58 +43,58 @@ import java.util.List;
*/ */
public class AndroidCalculatorNotifier implements CalculatorNotifier { public class AndroidCalculatorNotifier implements CalculatorNotifier {
@Nonnull @Nonnull
private final Application application; private final Application application;
@Nonnull @Nonnull
private final Handler uiHandler = new Handler(); private final Handler uiHandler = new Handler();
private final boolean showDebugMessages; private final boolean showDebugMessages;
public AndroidCalculatorNotifier(@Nonnull Application application) { public AndroidCalculatorNotifier(@Nonnull Application application) {
this(application, false); this(application, false);
} }
public AndroidCalculatorNotifier(@Nonnull Application application, boolean showDebugMessages) { public AndroidCalculatorNotifier(@Nonnull Application application, boolean showDebugMessages) {
if (!Threads.isUiThread()) throw new AssertionError(); if (!Threads.isUiThread()) throw new AssertionError();
this.application = application; this.application = application;
this.showDebugMessages = showDebugMessages; this.showDebugMessages = showDebugMessages;
} }
@Override @Override
public void showMessage(@Nonnull Message message) { public void showMessage(@Nonnull Message message) {
showMessageInUiThread(message.getLocalizedMessage()); showMessageInUiThread(message.getLocalizedMessage());
} }
@Override @Override
public void showMessage(@Nonnull Integer messageCode, @Nonnull MessageType messageType, @Nonnull List<Object> parameters) { public void showMessage(@Nonnull Integer messageCode, @Nonnull MessageType messageType, @Nonnull List<Object> parameters) {
showMessage(new AndroidMessage(messageCode, messageType, application, parameters)); showMessage(new AndroidMessage(messageCode, messageType, application, parameters));
} }
@Override @Override
public void showMessage(@Nonnull Integer messageCode, @Nonnull MessageType messageType, @Nullable Object... parameters) { public void showMessage(@Nonnull Integer messageCode, @Nonnull MessageType messageType, @Nullable Object... parameters) {
showMessage(new AndroidMessage(messageCode, messageType, application, parameters)); showMessage(new AndroidMessage(messageCode, messageType, application, parameters));
} }
@Override @Override
public void showDebugMessage(@Nullable final String tag, @Nonnull final String message) { public void showDebugMessage(@Nullable final String tag, @Nonnull final String message) {
if (showDebugMessages) { if (showDebugMessages) {
showMessageInUiThread(tag == null ? message : tag + ": " + message); showMessageInUiThread(tag == null ? message : tag + ": " + message);
} }
} }
private void showMessageInUiThread(@Nonnull final String message) { private void showMessageInUiThread(@Nonnull final String message) {
if (Threads.isUiThread()) { if (Threads.isUiThread()) {
Toast.makeText(application, message, Toast.LENGTH_SHORT).show(); Toast.makeText(application, message, Toast.LENGTH_SHORT).show();
} else { } else {
uiHandler.post(new Runnable() { uiHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
Toast.makeText(application, message, Toast.LENGTH_SHORT).show(); Toast.makeText(application, message, Toast.LENGTH_SHORT).show();
} }
}); });
} }
} }
} }

View File

@ -25,10 +25,6 @@ package org.solovyev.android.calculator;
import android.app.Application; import android.app.Application;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import jscl.AngleUnit;
import jscl.NumeralBase;
import javax.annotation.Nonnull;
import org.solovyev.android.calculator.model.AndroidCalculatorEngine; import org.solovyev.android.calculator.model.AndroidCalculatorEngine;
import org.solovyev.android.msg.AndroidMessage; import org.solovyev.android.msg.AndroidMessage;
@ -37,6 +33,11 @@ import org.solovyev.common.msg.MessageType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
import jscl.AngleUnit;
import jscl.NumeralBase;
/** /**
* User: serso * User: serso
* Date: 11/17/12 * Date: 11/17/12
@ -44,75 +45,75 @@ import java.util.List;
*/ */
public class AndroidCalculatorPreferenceService implements CalculatorPreferenceService { public class AndroidCalculatorPreferenceService implements CalculatorPreferenceService {
// one hour // one hour
private static final Long PREFERRED_PREFS_INTERVAL_TIME = 1000L * 60L * 60L; private static final Long PREFERRED_PREFS_INTERVAL_TIME = 1000L * 60L * 60L;
@Nonnull @Nonnull
private final Application application; private final Application application;
public AndroidCalculatorPreferenceService(@Nonnull Application application) { public AndroidCalculatorPreferenceService(@Nonnull Application application) {
this.application = application; this.application = application;
} }
@Override @Override
public void checkPreferredPreferences(boolean force) { public void checkPreferredPreferences(boolean force) {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(application); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(application);
final Long currentTime = System.currentTimeMillis(); final Long currentTime = System.currentTimeMillis();
if (force || (Preferences.Calculations.showCalculationMessagesDialog.getPreference(prefs) && isTimeForCheck(currentTime, prefs))) { if (force || (Preferences.Calculations.showCalculationMessagesDialog.getPreference(prefs) && isTimeForCheck(currentTime, prefs))) {
final NumeralBase preferredNumeralBase = Preferences.Calculations.preferredNumeralBase.getPreference(prefs); final NumeralBase preferredNumeralBase = Preferences.Calculations.preferredNumeralBase.getPreference(prefs);
final NumeralBase numeralBase = AndroidCalculatorEngine.Preferences.numeralBase.getPreference(prefs); final NumeralBase numeralBase = AndroidCalculatorEngine.Preferences.numeralBase.getPreference(prefs);
final AngleUnit preferredAngleUnits = Preferences.Calculations.preferredAngleUnits.getPreference(prefs); final AngleUnit preferredAngleUnits = Preferences.Calculations.preferredAngleUnits.getPreference(prefs);
final AngleUnit angleUnits = AndroidCalculatorEngine.Preferences.angleUnit.getPreference(prefs); final AngleUnit angleUnits = AndroidCalculatorEngine.Preferences.angleUnit.getPreference(prefs);
final List<FixableMessage> messages = new ArrayList<FixableMessage>(2); final List<FixableMessage> messages = new ArrayList<FixableMessage>(2);
if (numeralBase != preferredNumeralBase) { if (numeralBase != preferredNumeralBase) {
messages.add(new FixableMessage(application.getString(R.string.preferred_numeral_base_message, preferredNumeralBase.name(), numeralBase.name()), MessageType.warning, CalculatorFixableError.preferred_numeral_base)); messages.add(new FixableMessage(application.getString(R.string.preferred_numeral_base_message, preferredNumeralBase.name(), numeralBase.name()), MessageType.warning, CalculatorFixableError.preferred_numeral_base));
} }
if (angleUnits != preferredAngleUnits) { if (angleUnits != preferredAngleUnits) {
messages.add(new FixableMessage(application.getString(R.string.preferred_angle_units_message, preferredAngleUnits.name(), angleUnits.name()), MessageType.warning, CalculatorFixableError.preferred_angle_units)); messages.add(new FixableMessage(application.getString(R.string.preferred_angle_units_message, preferredAngleUnits.name(), angleUnits.name()), MessageType.warning, CalculatorFixableError.preferred_angle_units));
} }
FixableMessagesDialog.showDialog(messages, application, true); FixableMessagesDialog.showDialog(messages, application, true);
Preferences.Calculations.lastPreferredPreferencesCheck.putPreference(prefs, currentTime); Preferences.Calculations.lastPreferredPreferencesCheck.putPreference(prefs, currentTime);
} }
} }
private boolean isTimeForCheck(@Nonnull Long currentTime, @Nonnull SharedPreferences preferences) { private boolean isTimeForCheck(@Nonnull Long currentTime, @Nonnull SharedPreferences preferences) {
final Long lastPreferredPreferencesCheckTime = Preferences.Calculations.lastPreferredPreferencesCheck.getPreference(preferences); final Long lastPreferredPreferencesCheckTime = Preferences.Calculations.lastPreferredPreferencesCheck.getPreference(preferences);
return currentTime - lastPreferredPreferencesCheckTime > PREFERRED_PREFS_INTERVAL_TIME; return currentTime - lastPreferredPreferencesCheckTime > PREFERRED_PREFS_INTERVAL_TIME;
} }
@Override @Override
public void setPreferredAngleUnits() { public void setPreferredAngleUnits() {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(application); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(application);
setAngleUnits(Preferences.Calculations.preferredAngleUnits.getPreference(preferences)); setAngleUnits(Preferences.Calculations.preferredAngleUnits.getPreference(preferences));
} }
@Override @Override
public void setAngleUnits(@Nonnull AngleUnit angleUnit) { public void setAngleUnits(@Nonnull AngleUnit angleUnit) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(application); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(application);
AndroidCalculatorEngine.Preferences.angleUnit.putPreference(preferences, angleUnit); AndroidCalculatorEngine.Preferences.angleUnit.putPreference(preferences, angleUnit);
Locator.getInstance().getNotifier().showMessage(new AndroidMessage(R.string.c_angle_units_changed_to, MessageType.info, application, angleUnit.name())); Locator.getInstance().getNotifier().showMessage(new AndroidMessage(R.string.c_angle_units_changed_to, MessageType.info, application, angleUnit.name()));
} }
@Override @Override
public void setPreferredNumeralBase() { public void setPreferredNumeralBase() {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(application); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(application);
setNumeralBase(Preferences.Calculations.preferredNumeralBase.getPreference(preferences)); setNumeralBase(Preferences.Calculations.preferredNumeralBase.getPreference(preferences));
} }
@Override @Override
public void setNumeralBase(@Nonnull NumeralBase numeralBase) { public void setNumeralBase(@Nonnull NumeralBase numeralBase) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(application); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(application);
AndroidCalculatorEngine.Preferences.numeralBase.putPreference(preferences, numeralBase); AndroidCalculatorEngine.Preferences.numeralBase.putPreference(preferences, numeralBase);
Locator.getInstance().getNotifier().showMessage(new AndroidMessage(R.string.c_numeral_base_changed_to, MessageType.info, application, numeralBase.name())); Locator.getInstance().getNotifier().showMessage(new AndroidMessage(R.string.c_numeral_base_changed_to, MessageType.info, application, numeralBase.name()));
} }
} }

View File

@ -32,30 +32,30 @@ import javax.annotation.Nullable;
*/ */
public enum AndroidFunctionCategory { public enum AndroidFunctionCategory {
trigonometric(R.string.c_fun_category_trig), trigonometric(R.string.c_fun_category_trig),
hyperbolic_trigonometric(R.string.c_fun_category_hyper_trig), hyperbolic_trigonometric(R.string.c_fun_category_hyper_trig),
comparison(R.string.c_fun_category_comparison), comparison(R.string.c_fun_category_comparison),
my(R.string.c_fun_category_my), my(R.string.c_fun_category_my),
common(R.string.c_fun_category_common); common(R.string.c_fun_category_common);
private final int captionId; private final int captionId;
AndroidFunctionCategory(int captionId) { AndroidFunctionCategory(int captionId) {
this.captionId = captionId; this.captionId = captionId;
} }
public int getCaptionId() { @Nullable
return captionId; public static AndroidFunctionCategory valueOf(@Nonnull FunctionCategory functionCategory) {
} for (AndroidFunctionCategory androidFunctionCategory : values()) {
if (androidFunctionCategory.name().equals(functionCategory.name())) {
return androidFunctionCategory;
}
}
@Nullable return null;
public static AndroidFunctionCategory valueOf(@Nonnull FunctionCategory functionCategory) { }
for (AndroidFunctionCategory androidFunctionCategory : values()) {
if (androidFunctionCategory.name().equals(functionCategory.name())) {
return androidFunctionCategory;
}
}
return null; public int getCaptionId() {
} return captionId;
}
} }

View File

@ -23,18 +23,19 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.app.Activity; import android.app.Activity;
import jscl.NumeralBase;
import javax.annotation.Nonnull;
import org.solovyev.android.calculator.units.CalculatorNumeralBase;
import org.solovyev.android.calculator.drag.DirectionDragButton; import org.solovyev.android.calculator.drag.DirectionDragButton;
import org.solovyev.android.calculator.drag.DragDirection; import org.solovyev.android.calculator.drag.DragDirection;
import org.solovyev.android.calculator.units.CalculatorNumeralBase;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
import jscl.NumeralBase;
/** /**
* User: serso * User: serso
* Date: 4/21/12 * Date: 4/21/12
@ -42,92 +43,92 @@ import java.util.List;
*/ */
public enum AndroidNumeralBase { public enum AndroidNumeralBase {
bin(CalculatorNumeralBase.bin) { bin(CalculatorNumeralBase.bin) {
@Nonnull @Nonnull
@Override @Override
public List<Integer> getButtonIds() { public List<Integer> getButtonIds() {
return Arrays.asList(R.id.cpp_button_0, R.id.cpp_button_1); return Arrays.asList(R.id.cpp_button_0, R.id.cpp_button_1);
} }
}, },
oct(CalculatorNumeralBase.oct) { oct(CalculatorNumeralBase.oct) {
@Nonnull @Nonnull
@Override @Override
public List<Integer> getButtonIds() { public List<Integer> getButtonIds() {
final List<Integer> result = new ArrayList<Integer>(bin.getButtonIds()); final List<Integer> result = new ArrayList<Integer>(bin.getButtonIds());
result.addAll(Arrays.asList(R.id.cpp_button_2, R.id.cpp_button_3, R.id.cpp_button_4, R.id.cpp_button_5, R.id.cpp_button_6, R.id.cpp_button_7)); result.addAll(Arrays.asList(R.id.cpp_button_2, R.id.cpp_button_3, R.id.cpp_button_4, R.id.cpp_button_5, R.id.cpp_button_6, R.id.cpp_button_7));
return result; return result;
} }
}, },
dec(CalculatorNumeralBase.dec) { dec(CalculatorNumeralBase.dec) {
@Nonnull @Nonnull
@Override @Override
public List<Integer> getButtonIds() { public List<Integer> getButtonIds() {
final List<Integer> result = new ArrayList<Integer>(oct.getButtonIds()); final List<Integer> result = new ArrayList<Integer>(oct.getButtonIds());
result.addAll(Arrays.asList(R.id.cpp_button_8, R.id.cpp_button_9)); result.addAll(Arrays.asList(R.id.cpp_button_8, R.id.cpp_button_9));
return result; return result;
} }
}, },
hex(CalculatorNumeralBase.hex) { hex(CalculatorNumeralBase.hex) {
@Nonnull @Nonnull
private List<Integer> specialHexButtonIds = Arrays.asList(R.id.cpp_button_1, R.id.cpp_button_2, R.id.cpp_button_3, R.id.cpp_button_4, R.id.cpp_button_5, R.id.cpp_button_6); private List<Integer> specialHexButtonIds = Arrays.asList(R.id.cpp_button_1, R.id.cpp_button_2, R.id.cpp_button_3, R.id.cpp_button_4, R.id.cpp_button_5, R.id.cpp_button_6);
@Nonnull @Nonnull
@Override @Override
public List<Integer> getButtonIds() { public List<Integer> getButtonIds() {
return dec.getButtonIds(); return dec.getButtonIds();
} }
@Override @Override
protected void toggleButton(boolean show, @Nonnull DirectionDragButton button) { protected void toggleButton(boolean show, @Nonnull DirectionDragButton button) {
super.toggleButton(show, button); super.toggleButton(show, button);
if (specialHexButtonIds.contains(button.getId())) { if (specialHexButtonIds.contains(button.getId())) {
button.showDirectionText(show, DragDirection.left); button.showDirectionText(show, DragDirection.left);
button.invalidate(); button.invalidate();
} }
} }
}; };
@Nonnull @Nonnull
private final CalculatorNumeralBase calculatorNumeralBase; private final CalculatorNumeralBase calculatorNumeralBase;
private AndroidNumeralBase(@Nonnull CalculatorNumeralBase calculatorNumeralBase) { private AndroidNumeralBase(@Nonnull CalculatorNumeralBase calculatorNumeralBase) {
this.calculatorNumeralBase = calculatorNumeralBase; this.calculatorNumeralBase = calculatorNumeralBase;
} }
@Nonnull @Nonnull
public abstract List<Integer> getButtonIds(); public static AndroidNumeralBase valueOf(@Nonnull NumeralBase nb) {
for (AndroidNumeralBase androidNumeralBase : values()) {
if (androidNumeralBase.calculatorNumeralBase.getNumeralBase() == nb) {
return androidNumeralBase;
}
}
public void toggleButtons(boolean show, @Nonnull Activity activity) { throw new IllegalArgumentException(nb + " is not supported numeral base!");
for (Integer buttonId : getButtonIds()) { }
final DirectionDragButton button = (DirectionDragButton) activity.findViewById(buttonId);
if (button != null) {
toggleButton(show, button);
}
}
}
protected void toggleButton(boolean show, @Nonnull DirectionDragButton button) { @Nonnull
button.setShowText(show); public abstract List<Integer> getButtonIds();
button.invalidate();
}
@Nonnull public void toggleButtons(boolean show, @Nonnull Activity activity) {
public NumeralBase getNumeralBase() { for (Integer buttonId : getButtonIds()) {
return calculatorNumeralBase.getNumeralBase(); final DirectionDragButton button = (DirectionDragButton) activity.findViewById(buttonId);
} if (button != null) {
toggleButton(show, button);
}
}
}
@Nonnull protected void toggleButton(boolean show, @Nonnull DirectionDragButton button) {
public static AndroidNumeralBase valueOf(@Nonnull NumeralBase nb) { button.setShowText(show);
for (AndroidNumeralBase androidNumeralBase : values()) { button.invalidate();
if (androidNumeralBase.calculatorNumeralBase.getNumeralBase() == nb) { }
return androidNumeralBase;
}
}
throw new IllegalArgumentException(nb + " is not supported numeral base!"); @Nonnull
} public NumeralBase getNumeralBase() {
return calculatorNumeralBase.getNumeralBase();
}
} }

View File

@ -32,29 +32,29 @@ import javax.annotation.Nullable;
*/ */
public enum AndroidOperatorCategory { public enum AndroidOperatorCategory {
derivatives(R.string.derivatives), derivatives(R.string.derivatives),
other(R.string.other), other(R.string.other),
my(R.string.c_fun_category_my), my(R.string.c_fun_category_my),
common(R.string.c_fun_category_common); common(R.string.c_fun_category_common);
private final int captionId; private final int captionId;
AndroidOperatorCategory(int captionId) { AndroidOperatorCategory(int captionId) {
this.captionId = captionId; this.captionId = captionId;
} }
public int getCaptionId() { @Nullable
return captionId; public static AndroidOperatorCategory valueOf(@Nonnull OperatorCategory operatorCategory) {
} for (AndroidOperatorCategory androidOperatorCategory : values()) {
if (androidOperatorCategory.name().equals(operatorCategory.name())) {
return androidOperatorCategory;
}
}
@Nullable return null;
public static AndroidOperatorCategory valueOf(@Nonnull OperatorCategory operatorCategory) { }
for (AndroidOperatorCategory androidOperatorCategory : values()) {
if (androidOperatorCategory.name().equals(operatorCategory.name())) {
return androidOperatorCategory;
}
}
return null; public int getCaptionId() {
} return captionId;
}
} }

View File

@ -32,27 +32,27 @@ import javax.annotation.Nullable;
*/ */
public enum AndroidVarCategory { public enum AndroidVarCategory {
system(R.string.c_var_system), system(R.string.c_var_system),
my(R.string.c_var_my); my(R.string.c_var_my);
private final int captionId; private final int captionId;
AndroidVarCategory(int captionId) { AndroidVarCategory(int captionId) {
this.captionId = captionId; this.captionId = captionId;
} }
public int getCaptionId() { @Nullable
return captionId; public static AndroidVarCategory valueOf(@Nonnull VarCategory varCategory) {
} for (AndroidVarCategory androidVarCategory : values()) {
if (androidVarCategory.name().equals(varCategory.name())) {
return androidVarCategory;
}
}
@Nullable return null;
public static AndroidVarCategory valueOf(@Nonnull VarCategory varCategory) { }
for (AndroidVarCategory androidVarCategory : values()) {
if (androidVarCategory.name().equals(varCategory.name())) {
return androidVarCategory;
}
}
return null; public int getCaptionId() {
} return captionId;
}
} }

View File

@ -84,273 +84,259 @@ import javax.annotation.Nullable;
* Before first usage this class must be initialized by calling {@link App#init(android.app.Application)} method (for example, from {@link android.app.Application#onCreate()}) * Before first usage this class must be initialized by calling {@link App#init(android.app.Application)} method (for example, from {@link android.app.Application#onCreate()})
*/ */
public final class App { public final class App {
@Nonnull @Nonnull
private static final List<Class<? extends BaseCalculatorWidgetProvider>> OLD_WIDGETS = Arrays.asList(CalculatorWidgetProvider.class, CalculatorWidgetProvider3x4.class, CalculatorWidgetProvider4x4.class, CalculatorWidgetProvider4x5.class); private static final List<Class<? extends BaseCalculatorWidgetProvider>> OLD_WIDGETS = Arrays.asList(CalculatorWidgetProvider.class, CalculatorWidgetProvider3x4.class, CalculatorWidgetProvider4x4.class, CalculatorWidgetProvider4x5.class);
@Nonnull
private static final Products products = Products.create().add(ProductTypes.IN_APP, Arrays.asList("ad_free"));
@Nonnull
private static final Languages languages = new Languages();
@Nonnull
private static volatile Application application;
@Nonnull
private static volatile DelayedExecutor uiThreadExecutor;
@Nonnull
private static volatile JEventListeners<JEventListener<? extends JEvent>, JEvent> eventBus;
private static volatile boolean initialized;
@Nonnull
private static CalculatorBroadcaster broadcaster;
@Nonnull
private static SharedPreferences preferences;
@Nonnull
private static volatile Ga ga;
@Nonnull
private static volatile Billing billing;
@Nullable
private static Boolean lg = null;
@Nonnull
private static volatile Vibrator vibrator;
@Nonnull
private static volatile ScreenMetrics screenMetrics;
@Nonnull
private static volatile Plotter plotter;
@Nonnull private App() {
private static volatile Application application; throw new AssertionError();
}
@Nonnull
private static volatile DelayedExecutor uiThreadExecutor;
@Nonnull
private static volatile JEventListeners<JEventListener<? extends JEvent>, JEvent> eventBus;
private static volatile boolean initialized;
@Nonnull
private static CalculatorBroadcaster broadcaster;
@Nonnull
private static SharedPreferences preferences;
@Nonnull
private static volatile Ga ga;
@Nonnull
private static volatile Billing billing;
@Nonnull
private static final Products products = Products.create().add(ProductTypes.IN_APP, Arrays.asList("ad_free"));
@Nullable
private static Boolean lg = null;
@Nonnull
private static volatile Vibrator vibrator;
@Nonnull
private static volatile ScreenMetrics screenMetrics;
@Nonnull
private static volatile Plotter plotter;
@Nonnull
private static final Languages languages = new Languages();
private App() {
throw new AssertionError();
}
/* /*
********************************************************************** **********************************************************************
* *
* METHODS * METHODS
* *
********************************************************************** **********************************************************************
*/ */
public static void init(@Nonnull Application application) { public static void init(@Nonnull Application application) {
init(application, new UiThreadExecutor(), Listeners.newEventBus()); init(application, new UiThreadExecutor(), Listeners.newEventBus());
} }
public static void init(@Nonnull Application application, public static void init(@Nonnull Application application,
@Nonnull UiThreadExecutor uiThreadExecutor, @Nonnull UiThreadExecutor uiThreadExecutor,
@Nonnull JEventListeners<JEventListener<? extends JEvent>, JEvent> eventBus) { @Nonnull JEventListeners<JEventListener<? extends JEvent>, JEvent> eventBus) {
if (!initialized) { if (!initialized) {
App.application = application; App.application = application;
App.preferences = PreferenceManager.getDefaultSharedPreferences(application); App.preferences = PreferenceManager.getDefaultSharedPreferences(application);
App.uiThreadExecutor = uiThreadExecutor; App.uiThreadExecutor = uiThreadExecutor;
App.eventBus = eventBus; App.eventBus = eventBus;
App.ga = new Ga(application, preferences, eventBus); App.ga = new Ga(application, preferences, eventBus);
App.billing = new Billing(application, new Billing.DefaultConfiguration() { App.billing = new Billing(application, new Billing.DefaultConfiguration() {
@Nonnull @Nonnull
@Override @Override
public String getPublicKey() { public String getPublicKey() {
return CalculatorSecurity.getPK(); return CalculatorSecurity.getPK();
} }
@Nullable @Nullable
@Override @Override
public Inventory getFallbackInventory(@Nonnull Checkout checkout, @Nonnull Executor onLoadExecutor) { public Inventory getFallbackInventory(@Nonnull Checkout checkout, @Nonnull Executor onLoadExecutor) {
if (RobotmediaDatabase.exists(billing.getContext())) { if (RobotmediaDatabase.exists(billing.getContext())) {
return new RobotmediaInventory(checkout, onLoadExecutor); return new RobotmediaInventory(checkout, onLoadExecutor);
} else { } else {
return null; return null;
} }
} }
}); });
App.broadcaster = new CalculatorBroadcaster(application, preferences); App.broadcaster = new CalculatorBroadcaster(application, preferences);
App.vibrator = new Vibrator(application, preferences); App.vibrator = new Vibrator(application, preferences);
App.screenMetrics = new ScreenMetrics(application); App.screenMetrics = new ScreenMetrics(application);
final List<Class<? extends AppWidgetProvider>> oldNotUsedWidgetClasses = findNotUsedWidgets(application); final List<Class<? extends AppWidgetProvider>> oldNotUsedWidgetClasses = findNotUsedWidgets(application);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
for (Class<? extends AppWidgetProvider> oldNotUsedWidgetClass : oldNotUsedWidgetClasses) { for (Class<? extends AppWidgetProvider> oldNotUsedWidgetClass : oldNotUsedWidgetClasses) {
Android.enableComponent(application, oldNotUsedWidgetClass, false); Android.enableComponent(application, oldNotUsedWidgetClass, false);
} }
} else { } else {
// smaller widgets should be still used for smaller screens // smaller widgets should be still used for smaller screens
if (oldNotUsedWidgetClasses.contains(CalculatorWidgetProvider4x5.class)) { if (oldNotUsedWidgetClasses.contains(CalculatorWidgetProvider4x5.class)) {
Android.enableComponent(application, CalculatorWidgetProvider4x5.class, false); Android.enableComponent(application, CalculatorWidgetProvider4x5.class, false);
} }
if (oldNotUsedWidgetClasses.contains(CalculatorWidgetProvider4x4.class)) { if (oldNotUsedWidgetClasses.contains(CalculatorWidgetProvider4x4.class)) {
Android.enableComponent(application, CalculatorWidgetProvider4x4.class, false); Android.enableComponent(application, CalculatorWidgetProvider4x4.class, false);
} }
} }
App.languages.init(App.preferences); App.languages.init(App.preferences);
App.plotter = Plot.newPlotter(application); App.plotter = Plot.newPlotter(application);
App.initialized = true; App.initialized = true;
} else { } else {
throw new IllegalStateException("Already initialized!"); throw new IllegalStateException("Already initialized!");
} }
} }
@Nonnull @Nonnull
private static List<Class<? extends AppWidgetProvider>> findNotUsedWidgets(@Nonnull Application application) { private static List<Class<? extends AppWidgetProvider>> findNotUsedWidgets(@Nonnull Application application) {
final List<Class<? extends AppWidgetProvider>> result = new ArrayList<>(); final List<Class<? extends AppWidgetProvider>> result = new ArrayList<>();
final AppWidgetManager widgetManager = AppWidgetManager.getInstance(application); final AppWidgetManager widgetManager = AppWidgetManager.getInstance(application);
for (Class<? extends AppWidgetProvider> widgetClass : OLD_WIDGETS) { for (Class<? extends AppWidgetProvider> widgetClass : OLD_WIDGETS) {
final int ids[] = widgetManager.getAppWidgetIds(new ComponentName(application, widgetClass)); final int ids[] = widgetManager.getAppWidgetIds(new ComponentName(application, widgetClass));
if (ids == null || ids.length == 0) { if (ids == null || ids.length == 0) {
result.add(widgetClass); result.add(widgetClass);
} }
} }
return result; return result;
} }
private static void checkInit() { private static void checkInit() {
if (!initialized) { if (!initialized) {
throw new IllegalStateException("App should be initialized!"); throw new IllegalStateException("App should be initialized!");
} }
} }
/** /**
* @return if App has already been initialized, false otherwise * @return if App has already been initialized, false otherwise
*/ */
public static boolean isInitialized() { public static boolean isInitialized() {
return initialized; return initialized;
} }
/** /**
* @param <A> real type of application * @param <A> real type of application
* @return application instance which was provided in {@link App#init(android.app.Application)} method * @return application instance which was provided in {@link App#init(android.app.Application)} method
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Nonnull @Nonnull
public static <A extends Application> A getApplication() { public static <A extends Application> A getApplication() {
checkInit(); checkInit();
return (A) application; return (A) application;
} }
/** /**
* Method returns executor which runs on Main Application's thread. It's safe to do all UI work on this executor * Method returns executor which runs on Main Application's thread. It's safe to do all UI work on this executor
* *
* @return UI thread executor * @return UI thread executor
*/ */
@Nonnull @Nonnull
public static DelayedExecutor getUiThreadExecutor() { public static DelayedExecutor getUiThreadExecutor() {
checkInit(); checkInit();
return uiThreadExecutor; return uiThreadExecutor;
} }
/** /**
* @return application's event bus * @return application's event bus
*/ */
@Nonnull @Nonnull
public static JEventListeners<JEventListener<? extends JEvent>, JEvent> getEventBus() { public static JEventListeners<JEventListener<? extends JEvent>, JEvent> getEventBus() {
checkInit(); checkInit();
return eventBus; return eventBus;
} }
@Nonnull @Nonnull
public static CalculatorBroadcaster getBroadcaster() { public static CalculatorBroadcaster getBroadcaster() {
return broadcaster; return broadcaster;
} }
@Nonnull @Nonnull
public static Ga getGa() { public static Ga getGa() {
return ga; return ga;
} }
@Nonnull @Nonnull
public static Billing getBilling() { public static Billing getBilling() {
return billing; return billing;
} }
@Nonnull @Nonnull
public static Products getProducts() { public static Products getProducts() {
return products; return products;
} }
public static boolean isLargeScreen() { public static boolean isLargeScreen() {
return Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE, App.getApplication().getResources().getConfiguration()); return Views.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE, App.getApplication().getResources().getConfiguration());
} }
@Nonnull @Nonnull
public static SharedPreferences getPreferences() { public static SharedPreferences getPreferences() {
return preferences; return preferences;
} }
@Nonnull @Nonnull
public static Preferences.Gui.Theme getTheme() { public static Preferences.Gui.Theme getTheme() {
return Preferences.Gui.getTheme(getPreferences()); return Preferences.Gui.getTheme(getPreferences());
} }
@Nonnull @Nonnull
public static Preferences.SimpleTheme getWidgetTheme() { public static Preferences.SimpleTheme getWidgetTheme() {
return Preferences.Widget.getTheme(getPreferences()); return Preferences.Widget.getTheme(getPreferences());
} }
@Nonnull @Nonnull
public static Preferences.Gui.Theme getThemeIn(@Nonnull Context context) { public static Preferences.Gui.Theme getThemeIn(@Nonnull Context context) {
if (context instanceof CalculatorOnscreenService) { if (context instanceof CalculatorOnscreenService) {
final SharedPreferences p = getPreferences(); final SharedPreferences p = getPreferences();
final Preferences.SimpleTheme onscreenTheme = Preferences.Onscreen.getTheme(p); final Preferences.SimpleTheme onscreenTheme = Preferences.Onscreen.getTheme(p);
final Preferences.Gui.Theme appTheme = Preferences.Gui.getTheme(p); final Preferences.Gui.Theme appTheme = Preferences.Gui.getTheme(p);
return onscreenTheme.resolveThemeFor(appTheme).getAppTheme(); return onscreenTheme.resolveThemeFor(appTheme).getAppTheme();
} else { } else {
return App.getTheme(); return App.getTheme();
} }
} }
@Nonnull @Nonnull
public static Languages getLanguages() { public static Languages getLanguages() {
return languages; return languages;
} }
public static boolean isLg() { public static boolean isLg() {
if (lg == null) { if (lg == null) {
lg = "lge".equalsIgnoreCase(Build.BRAND) || "lge".equalsIgnoreCase(Build.MANUFACTURER); lg = "lge".equalsIgnoreCase(Build.BRAND) || "lge".equalsIgnoreCase(Build.MANUFACTURER);
} }
return lg; return lg;
} }
// see https://code.google.com/p/android/issues/detail?id=78154 // see https://code.google.com/p/android/issues/detail?id=78154
// and http://developer.lge.com/community/forums/RetrieveForumContent.dev?detailContsId=FC29190703 // and http://developer.lge.com/community/forums/RetrieveForumContent.dev?detailContsId=FC29190703
public static boolean shouldOpenMenuManually() { public static boolean shouldOpenMenuManually() {
return isLg() && Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN; return isLg() && Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN;
} }
@Nonnull @Nonnull
public static Vibrator getVibrator() { public static Vibrator getVibrator() {
return vibrator; return vibrator;
} }
@Nonnull @Nonnull
public static ScreenMetrics getScreenMetrics() { public static ScreenMetrics getScreenMetrics() {
return screenMetrics; return screenMetrics;
} }
public static void showDialog(@Nonnull DialogFragment dialogFragment, public static void showDialog(@Nonnull DialogFragment dialogFragment,
@Nonnull String fragmentTag, @Nonnull String fragmentTag,
@Nonnull FragmentManager fm) { @Nonnull FragmentManager fm) {
final FragmentTransaction ft = fm.beginTransaction(); final FragmentTransaction ft = fm.beginTransaction();
Fragment prev = fm.findFragmentByTag(fragmentTag); Fragment prev = fm.findFragmentByTag(fragmentTag);
if (prev != null) { if (prev != null) {
ft.remove(prev); ft.remove(prev);
} }
// Create and show the dialog. // Create and show the dialog.
dialogFragment.show(ft, fragmentTag); dialogFragment.show(ft, fragmentTag);
} }
@Nonnull @Nonnull
public static Plotter getPlotter() { public static Plotter getPlotter() {
return plotter; return plotter;
} }
} }

View File

@ -10,86 +10,86 @@ import javax.annotation.Nonnull;
public class BaseActivity extends ActionBarActivity { public class BaseActivity extends ActionBarActivity {
@Nonnull @Nonnull
protected final ActivityUi ui; protected final ActivityUi ui;
public BaseActivity(@Nonnull ActivityUi ui) { public BaseActivity(@Nonnull ActivityUi ui) {
this.ui = ui; this.ui = ui;
} }
public BaseActivity(@LayoutRes int layout) { public BaseActivity(@LayoutRes int layout) {
this(layout, "Activity"); this(layout, "Activity");
} }
public BaseActivity(@LayoutRes int layout, @Nonnull String logTag) { public BaseActivity(@LayoutRes int layout, @Nonnull String logTag) {
this.ui = new ActivityUi(layout, logTag); this.ui = new ActivityUi(layout, logTag);
} }
@Nonnull @Nonnull
public ActivityUi getUi() { public ActivityUi getUi() {
return ui; return ui;
} }
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
ui.onPreCreate(this); ui.onPreCreate(this);
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
ui.onCreate(this); ui.onCreate(this);
} }
@Override @Override
protected void onSaveInstanceState(Bundle outState) { protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
ui.onSaveInstanceState(this, outState); ui.onSaveInstanceState(this, outState);
} }
@Override @Override
protected void onStart() { protected void onStart() {
super.onStart(); super.onStart();
ui.onStart(this); ui.onStart(this);
} }
@Override @Override
protected void onStop() { protected void onStop() {
ui.onStop(this); ui.onStop(this);
super.onStop(); super.onStop();
} }
@Override @Override
public boolean onKeyDown(int keyCode, KeyEvent event) { public boolean onKeyDown(int keyCode, KeyEvent event) {
if (App.shouldOpenMenuManually() && keyCode == KeyEvent.KEYCODE_MENU) { if (App.shouldOpenMenuManually() && keyCode == KeyEvent.KEYCODE_MENU) {
openOptionsMenu(); openOptionsMenu();
return true; return true;
} }
return super.onKeyDown(keyCode, event); return super.onKeyDown(keyCode, event);
} }
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
ui.onResume(this); ui.onResume(this);
} }
@Override @Override
protected void onPause() { protected void onPause() {
this.ui.onPause(this); this.ui.onPause(this);
super.onPause(); super.onPause();
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
ui.onDestroy(this); ui.onDestroy(this);
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case android.R.id.home: case android.R.id.home:
finish(); finish();
return true; return true;
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
} }

View File

@ -32,8 +32,13 @@ import android.util.Log;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import org.solovyev.android.Views; import org.solovyev.android.Views;
import org.solovyev.android.calculator.drag.*; import org.solovyev.android.calculator.drag.DirectionDragButton;
import org.solovyev.android.calculator.drag.DragButton;
import org.solovyev.android.calculator.drag.DragDirection;
import org.solovyev.android.calculator.drag.DragListener;
import org.solovyev.android.calculator.drag.SimpleDragListener;
import org.solovyev.android.calculator.history.CalculatorHistoryState; import org.solovyev.android.calculator.history.CalculatorHistoryState;
import org.solovyev.android.calculator.history.HistoryDragProcessor; import org.solovyev.android.calculator.history.HistoryDragProcessor;
import org.solovyev.android.calculator.view.AngleUnitsButton; import org.solovyev.android.calculator.view.AngleUnitsButton;
@ -42,11 +47,12 @@ import org.solovyev.android.calculator.view.NumeralBasesButton;
import org.solovyev.android.calculator.view.ViewsCache; import org.solovyev.android.calculator.view.ViewsCache;
import org.solovyev.common.math.Point2d; import org.solovyev.common.math.Point2d;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple; import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple;
import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple_mobile; import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple_mobile;
import static org.solovyev.android.calculator.model.AndroidCalculatorEngine.Preferences.angleUnit; import static org.solovyev.android.calculator.model.AndroidCalculatorEngine.Preferences.angleUnit;
@ -54,263 +60,263 @@ import static org.solovyev.android.calculator.model.AndroidCalculatorEngine.Pref
public abstract class BaseUi implements SharedPreferences.OnSharedPreferenceChangeListener { public abstract class BaseUi implements SharedPreferences.OnSharedPreferenceChangeListener {
@Nonnull @Nonnull
private static final List<Integer> viewIds = new ArrayList<>(200); private static final List<Integer> viewIds = new ArrayList<>(200);
@Nonnull @Nonnull
protected Preferences.Gui.Layout layout; protected Preferences.Gui.Layout layout;
@Nonnull @Nonnull
protected Preferences.Gui.Theme theme; protected Preferences.Gui.Theme theme;
@Nonnull @Nonnull
private String logTag = "CalculatorActivity"; private String logTag = "CalculatorActivity";
@Nullable @Nullable
private AngleUnitsButton angleUnitsButton; private AngleUnitsButton angleUnitsButton;
@Nullable @Nullable
private NumeralBasesButton clearButton; private NumeralBasesButton clearButton;
protected BaseUi() { protected BaseUi() {
} }
protected BaseUi(@Nonnull String logTag) { protected BaseUi(@Nonnull String logTag) {
this.logTag = logTag; this.logTag = logTag;
} }
protected void onCreate(@Nonnull Activity activity) { @Nonnull
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity); private static List<Integer> getViewIds() {
if (viewIds.isEmpty()) {
viewIds.add(R.id.wizard_dragbutton);
viewIds.add(R.id.cpp_button_vars);
viewIds.add(R.id.cpp_button_round_brackets);
viewIds.add(R.id.cpp_button_right);
viewIds.add(R.id.cpp_button_plus);
viewIds.add(R.id.cpp_button_operators);
viewIds.add(R.id.cpp_button_multiplication);
viewIds.add(R.id.cpp_button_subtraction);
viewIds.add(R.id.cpp_button_left);
viewIds.add(R.id.cpp_button_history);
viewIds.add(R.id.cpp_button_functions);
viewIds.add(R.id.cpp_button_equals);
viewIds.add(R.id.cpp_button_period);
viewIds.add(R.id.cpp_button_division);
viewIds.add(R.id.cpp_button_9);
viewIds.add(R.id.cpp_button_8);
viewIds.add(R.id.cpp_button_7);
viewIds.add(R.id.cpp_button_6);
viewIds.add(R.id.cpp_button_5);
viewIds.add(R.id.cpp_button_4);
viewIds.add(R.id.cpp_button_3);
viewIds.add(R.id.cpp_button_2);
viewIds.add(R.id.cpp_button_1);
viewIds.add(R.id.cpp_button_0);
viewIds.add(R.id.cpp_button_clear);
}
return viewIds;
}
layout = Preferences.Gui.layout.getPreferenceNoError(preferences); protected void onCreate(@Nonnull Activity activity) {
theme = Preferences.Gui.theme.getPreferenceNoError(preferences); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
preferences.registerOnSharedPreferenceChangeListener(this); layout = Preferences.Gui.layout.getPreferenceNoError(preferences);
theme = Preferences.Gui.theme.getPreferenceNoError(preferences);
// let's disable locking of screen for monkeyrunner preferences.registerOnSharedPreferenceChangeListener(this);
if (CalculatorApplication.isMonkeyRunner(activity)) {
final KeyguardManager km = (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE);
//noinspection deprecation
km.newKeyguardLock(activity.getClass().getName()).disableKeyguard();
}
}
public void logError(@Nonnull String message) { // let's disable locking of screen for monkeyrunner
Log.e(logTag, message); if (CalculatorApplication.isMonkeyRunner(activity)) {
} final KeyguardManager km = (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE);
//noinspection deprecation
km.newKeyguardLock(activity.getClass().getName()).disableKeyguard();
}
}
public void onDestroy(@Nonnull Activity activity) { public void logError(@Nonnull String message) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity); Log.e(logTag, message);
}
preferences.unregisterOnSharedPreferenceChangeListener(this); public void onDestroy(@Nonnull Activity activity) {
} final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
protected void fixFonts(@Nonnull View root) { preferences.unregisterOnSharedPreferenceChangeListener(this);
// some devices ship own fonts which causes issues with rendering. Let's use our own font for all text views }
final Typeface typeFace = CalculatorApplication.getInstance().getTypeFace();
Views.processViewsOfType(root, TextView.class, new Views.ViewProcessor<TextView>() {
@Override
public void process(@Nonnull TextView view) {
int style = Typeface.NORMAL;
final Typeface oldTypeface = view.getTypeface();
if (oldTypeface != null) {
style = oldTypeface.getStyle();
}
view.setTypeface(typeFace, style);
}
});
}
public void processButtons(@Nonnull final Activity activity, @Nonnull View root) { protected void fixFonts(@Nonnull View root) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity); // some devices ship own fonts which causes issues with rendering. Let's use our own font for all text views
final Typeface typeFace = CalculatorApplication.getInstance().getTypeFace();
Views.processViewsOfType(root, TextView.class, new Views.ViewProcessor<TextView>() {
@Override
public void process(@Nonnull TextView view) {
int style = Typeface.NORMAL;
final Typeface oldTypeface = view.getTypeface();
if (oldTypeface != null) {
style = oldTypeface.getStyle();
}
view.setTypeface(typeFace, style);
}
});
}
final ViewsCache views = ViewsCache.forView(root); public void processButtons(@Nonnull final Activity activity, @Nonnull View root) {
setOnDragListeners(views, activity); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
HistoryDragProcessor<CalculatorHistoryState> historyDragProcessor = new HistoryDragProcessor<>(getCalculator()); final ViewsCache views = ViewsCache.forView(root);
final DragListener historyDragListener = newDragListener(historyDragProcessor, activity); setOnDragListeners(views, activity);
final DragButton historyButton = getButton(views, R.id.cpp_button_history);
if (historyButton != null) {
historyButton.setOnDragListener(historyDragListener);
}
final DragButton minusButton = getButton(views, R.id.cpp_button_subtraction); HistoryDragProcessor<CalculatorHistoryState> historyDragProcessor = new HistoryDragProcessor<>(getCalculator());
if (minusButton != null) { final DragListener historyDragListener = newDragListener(historyDragProcessor, activity);
minusButton.setOnDragListener(newDragListener(new OperatorsDragProcessor(), activity)); final DragButton historyButton = getButton(views, R.id.cpp_button_history);
} if (historyButton != null) {
historyButton.setOnDragListener(historyDragListener);
}
final DragListener toPositionDragListener = new SimpleDragListener(new CursorDragProcessor(), activity); final DragButton minusButton = getButton(views, R.id.cpp_button_subtraction);
if (minusButton != null) {
minusButton.setOnDragListener(newDragListener(new OperatorsDragProcessor(), activity));
}
final DragButton rightButton = getButton(views, R.id.cpp_button_right); final DragListener toPositionDragListener = new SimpleDragListener(new CursorDragProcessor(), activity);
if (rightButton != null) {
rightButton.setOnDragListener(toPositionDragListener);
}
final DragButton leftButton = getButton(views, R.id.cpp_button_left); final DragButton rightButton = getButton(views, R.id.cpp_button_right);
if (leftButton != null) { if (rightButton != null) {
leftButton.setOnDragListener(toPositionDragListener); rightButton.setOnDragListener(toPositionDragListener);
} }
final DragButton equalsButton = getButton(views, R.id.cpp_button_equals); final DragButton leftButton = getButton(views, R.id.cpp_button_left);
if (equalsButton != null) { if (leftButton != null) {
equalsButton.setOnDragListener(newDragListener(new EqualsDragProcessor(), activity)); leftButton.setOnDragListener(toPositionDragListener);
} }
angleUnitsButton = getButton(views, R.id.cpp_button_6); final DragButton equalsButton = getButton(views, R.id.cpp_button_equals);
if (angleUnitsButton != null) { if (equalsButton != null) {
angleUnitsButton.setOnDragListener(newDragListener(new CalculatorButtons.AngleUnitsChanger(activity), activity)); equalsButton.setOnDragListener(newDragListener(new EqualsDragProcessor(), activity));
} }
final View eraseButton = getButton(views, R.id.cpp_button_erase); angleUnitsButton = getButton(views, R.id.cpp_button_6);
if (eraseButton != null) { if (angleUnitsButton != null) {
LongClickEraser.createAndAttach(eraseButton); angleUnitsButton.setOnDragListener(newDragListener(new CalculatorButtons.AngleUnitsChanger(activity), activity));
} }
clearButton = getButton(views, R.id.cpp_button_clear); final View eraseButton = getButton(views, R.id.cpp_button_erase);
if (clearButton != null) { if (eraseButton != null) {
clearButton.setOnDragListener(newDragListener(new CalculatorButtons.NumeralBasesChanger(activity), activity)); LongClickEraser.createAndAttach(eraseButton);
} }
final DragButton varsButton = getButton(views, R.id.cpp_button_vars); clearButton = getButton(views, R.id.cpp_button_clear);
if (varsButton != null) { if (clearButton != null) {
varsButton.setOnDragListener(newDragListener(new CalculatorButtons.VarsDragProcessor(activity), activity)); clearButton.setOnDragListener(newDragListener(new CalculatorButtons.NumeralBasesChanger(activity), activity));
} }
final DragButton functionsButton = getButton(views, R.id.cpp_button_functions); final DragButton varsButton = getButton(views, R.id.cpp_button_vars);
if (functionsButton != null) { if (varsButton != null) {
functionsButton.setOnDragListener(newDragListener(new CalculatorButtons.FunctionsDragProcessor(activity), activity)); varsButton.setOnDragListener(newDragListener(new CalculatorButtons.VarsDragProcessor(activity), activity));
} }
final DragButton roundBracketsButton = getButton(views, R.id.cpp_button_round_brackets); final DragButton functionsButton = getButton(views, R.id.cpp_button_functions);
if (roundBracketsButton != null) { if (functionsButton != null) {
roundBracketsButton.setOnDragListener(newDragListener(new CalculatorButtons.RoundBracketsDragProcessor(), activity)); functionsButton.setOnDragListener(newDragListener(new CalculatorButtons.FunctionsDragProcessor(activity), activity));
} }
if (layout == simple || layout == simple_mobile) { final DragButton roundBracketsButton = getButton(views, R.id.cpp_button_round_brackets);
toggleButtonDirectionText(views, R.id.cpp_button_1, false, DragDirection.up, DragDirection.down); if (roundBracketsButton != null) {
toggleButtonDirectionText(views, R.id.cpp_button_2, false, DragDirection.up, DragDirection.down); roundBracketsButton.setOnDragListener(newDragListener(new CalculatorButtons.RoundBracketsDragProcessor(), activity));
toggleButtonDirectionText(views, R.id.cpp_button_3, false, DragDirection.up, DragDirection.down); }
toggleButtonDirectionText(views, R.id.cpp_button_6, false, DragDirection.up, DragDirection.down); if (layout == simple || layout == simple_mobile) {
toggleButtonDirectionText(views, R.id.cpp_button_7, false, DragDirection.left, DragDirection.up, DragDirection.down); toggleButtonDirectionText(views, R.id.cpp_button_1, false, DragDirection.up, DragDirection.down);
toggleButtonDirectionText(views, R.id.cpp_button_8, false, DragDirection.left, DragDirection.up, DragDirection.down); toggleButtonDirectionText(views, R.id.cpp_button_2, false, DragDirection.up, DragDirection.down);
toggleButtonDirectionText(views, R.id.cpp_button_3, false, DragDirection.up, DragDirection.down);
toggleButtonDirectionText(views, R.id.cpp_button_clear, false, DragDirection.left, DragDirection.up, DragDirection.down); toggleButtonDirectionText(views, R.id.cpp_button_6, false, DragDirection.up, DragDirection.down);
toggleButtonDirectionText(views, R.id.cpp_button_7, false, DragDirection.left, DragDirection.up, DragDirection.down);
toggleButtonDirectionText(views, R.id.cpp_button_8, false, DragDirection.left, DragDirection.up, DragDirection.down);
toggleButtonDirectionText(views, R.id.cpp_button_4, false, DragDirection.down); toggleButtonDirectionText(views, R.id.cpp_button_clear, false, DragDirection.left, DragDirection.up, DragDirection.down);
toggleButtonDirectionText(views, R.id.cpp_button_5, false, DragDirection.down);
toggleButtonDirectionText(views, R.id.cpp_button_9, false, DragDirection.left); toggleButtonDirectionText(views, R.id.cpp_button_4, false, DragDirection.down);
toggleButtonDirectionText(views, R.id.cpp_button_5, false, DragDirection.down);
toggleButtonDirectionText(views, R.id.cpp_button_multiplication, false, DragDirection.left); toggleButtonDirectionText(views, R.id.cpp_button_9, false, DragDirection.left);
toggleButtonDirectionText(views, R.id.cpp_button_plus, false, DragDirection.down, DragDirection.up);
}
CalculatorButtons.fixButtonsTextSize(theme, layout, root); toggleButtonDirectionText(views, R.id.cpp_button_multiplication, false, DragDirection.left);
CalculatorButtons.toggleEqualsButton(preferences, activity); toggleButtonDirectionText(views, R.id.cpp_button_plus, false, DragDirection.down, DragDirection.up);
CalculatorButtons.initMultiplicationButton(root); }
NumeralBaseButtons.toggleNumericDigits(activity, preferences);
new ButtonOnClickListener().attachToViews(views); CalculatorButtons.fixButtonsTextSize(theme, layout, root);
} CalculatorButtons.toggleEqualsButton(preferences, activity);
CalculatorButtons.initMultiplicationButton(root);
NumeralBaseButtons.toggleNumericDigits(activity, preferences);
private void setOnDragListeners(@Nonnull ViewsCache views, @Nonnull Context context) { new ButtonOnClickListener().attachToViews(views);
final DragListener dragListener = newDragListener(new DigitButtonDragProcessor(getKeyboard()), context); }
final List<Integer> viewIds = getViewIds(); private void setOnDragListeners(@Nonnull ViewsCache views, @Nonnull Context context) {
for (Integer viewId : viewIds) { final DragListener dragListener = newDragListener(new DigitButtonDragProcessor(getKeyboard()), context);
final View view = views.findViewById(viewId);
if (view instanceof DragButton) {
((DragButton) view).setOnDragListener(dragListener);
}
}
}
@Nonnull final List<Integer> viewIds = getViewIds();
private SimpleDragListener newDragListener(@Nonnull SimpleDragListener.DragProcessor dragProcessor, @Nonnull Context context) { for (Integer viewId : viewIds) {
return new SimpleDragListener(dragProcessor, context); final View view = views.findViewById(viewId);
} if (view instanceof DragButton) {
((DragButton) view).setOnDragListener(dragListener);
}
}
}
private void toggleButtonDirectionText(@Nonnull ViewsCache views, int id, boolean showDirectionText, @Nonnull DragDirection... dragDirections) { @Nonnull
final View v = getButton(views, id); private SimpleDragListener newDragListener(@Nonnull SimpleDragListener.DragProcessor dragProcessor, @Nonnull Context context) {
if (v instanceof DirectionDragButton) { return new SimpleDragListener(dragProcessor, context);
final DirectionDragButton button = (DirectionDragButton) v; }
for (DragDirection dragDirection : dragDirections) {
button.showDirectionText(showDirectionText, dragDirection);
}
}
}
@Nonnull private void toggleButtonDirectionText(@Nonnull ViewsCache views, int id, boolean showDirectionText, @Nonnull DragDirection... dragDirections) {
private Calculator getCalculator() { final View v = getButton(views, id);
return Locator.getInstance().getCalculator(); if (v instanceof DirectionDragButton) {
} final DirectionDragButton button = (DirectionDragButton) v;
for (DragDirection dragDirection : dragDirections) {
button.showDirectionText(showDirectionText, dragDirection);
}
}
}
@Nonnull @Nonnull
private static List<Integer> getViewIds() { private Calculator getCalculator() {
if (viewIds.isEmpty()) { return Locator.getInstance().getCalculator();
viewIds.add(R.id.wizard_dragbutton); }
viewIds.add(R.id.cpp_button_vars);
viewIds.add(R.id.cpp_button_round_brackets);
viewIds.add(R.id.cpp_button_right);
viewIds.add(R.id.cpp_button_plus);
viewIds.add(R.id.cpp_button_operators);
viewIds.add(R.id.cpp_button_multiplication);
viewIds.add(R.id.cpp_button_subtraction);
viewIds.add(R.id.cpp_button_left);
viewIds.add(R.id.cpp_button_history);
viewIds.add(R.id.cpp_button_functions);
viewIds.add(R.id.cpp_button_equals);
viewIds.add(R.id.cpp_button_period);
viewIds.add(R.id.cpp_button_division);
viewIds.add(R.id.cpp_button_9);
viewIds.add(R.id.cpp_button_8);
viewIds.add(R.id.cpp_button_7);
viewIds.add(R.id.cpp_button_6);
viewIds.add(R.id.cpp_button_5);
viewIds.add(R.id.cpp_button_4);
viewIds.add(R.id.cpp_button_3);
viewIds.add(R.id.cpp_button_2);
viewIds.add(R.id.cpp_button_1);
viewIds.add(R.id.cpp_button_0);
viewIds.add(R.id.cpp_button_clear);
}
return viewIds;
}
@Nonnull @Nonnull
private CalculatorKeyboard getKeyboard() { private CalculatorKeyboard getKeyboard() {
return Locator.getInstance().getKeyboard(); return Locator.getInstance().getKeyboard();
} }
@Nullable @Nullable
private <V extends View> V getButton(@Nonnull ViewsCache views, int buttonId) { private <V extends View> V getButton(@Nonnull ViewsCache views, int buttonId) {
//noinspection unchecked //noinspection unchecked
return (V) views.findViewById(buttonId); return (V) views.findViewById(buttonId);
} }
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (angleUnit.isSameKey(key) || numeralBase.isSameKey(key)) { if (angleUnit.isSameKey(key) || numeralBase.isSameKey(key)) {
if (angleUnitsButton != null) { if (angleUnitsButton != null) {
angleUnitsButton.setAngleUnit(angleUnit.getPreference(preferences)); angleUnitsButton.setAngleUnit(angleUnit.getPreference(preferences));
} }
if (clearButton != null) { if (clearButton != null) {
clearButton.setNumeralBase(numeralBase.getPreference(preferences)); clearButton.setNumeralBase(numeralBase.getPreference(preferences));
} }
} }
} }
private static class OperatorsDragProcessor implements SimpleDragListener.DragProcessor { private static class OperatorsDragProcessor implements SimpleDragListener.DragProcessor {
@Override @Override
public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent) { public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent) {
if (dragDirection == DragDirection.down) { if (dragDirection == DragDirection.down) {
App.getVibrator().vibrate(); App.getVibrator().vibrate();
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_operators, null); Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_operators, null);
return true; return true;
} }
return false; return false;
} }
} }
} }

View File

@ -3,111 +3,112 @@ package org.solovyev.android.calculator;
import android.support.annotation.IdRes; import android.support.annotation.IdRes;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import org.solovyev.android.calculator.view.ViewsCache; import org.solovyev.android.calculator.view.ViewsCache;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
final class ButtonOnClickListener implements View.OnClickListener { final class ButtonOnClickListener implements View.OnClickListener {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
switch (v.getId()) { switch (v.getId()) {
case R.id.cpp_button_0: case R.id.cpp_button_0:
case R.id.cpp_button_1: case R.id.cpp_button_1:
case R.id.cpp_button_2: case R.id.cpp_button_2:
case R.id.cpp_button_3: case R.id.cpp_button_3:
case R.id.cpp_button_4: case R.id.cpp_button_4:
case R.id.cpp_button_5: case R.id.cpp_button_5:
case R.id.cpp_button_6: case R.id.cpp_button_6:
case R.id.cpp_button_7: case R.id.cpp_button_7:
case R.id.cpp_button_8: case R.id.cpp_button_8:
case R.id.cpp_button_9: case R.id.cpp_button_9:
case R.id.cpp_button_division: case R.id.cpp_button_division:
case R.id.cpp_button_period: case R.id.cpp_button_period:
case R.id.cpp_button_left: case R.id.cpp_button_left:
case R.id.cpp_button_subtraction: case R.id.cpp_button_subtraction:
case R.id.cpp_button_multiplication: case R.id.cpp_button_multiplication:
case R.id.cpp_button_plus: case R.id.cpp_button_plus:
case R.id.cpp_button_right: case R.id.cpp_button_right:
case R.id.cpp_button_round_brackets: case R.id.cpp_button_round_brackets:
onClick(((Button) v).getText().toString()); onClick(((Button) v).getText().toString());
break; break;
case R.id.cpp_button_clear: case R.id.cpp_button_clear:
onClick(CalculatorSpecialButton.clear); onClick(CalculatorSpecialButton.clear);
break; break;
case R.id.cpp_button_functions: case R.id.cpp_button_functions:
onClick(CalculatorSpecialButton.functions); onClick(CalculatorSpecialButton.functions);
break; break;
case R.id.cpp_button_history: case R.id.cpp_button_history:
onClick(CalculatorSpecialButton.history); onClick(CalculatorSpecialButton.history);
break; break;
case R.id.cpp_button_erase: case R.id.cpp_button_erase:
onClick(CalculatorSpecialButton.erase); onClick(CalculatorSpecialButton.erase);
break; break;
case R.id.cpp_button_paste: case R.id.cpp_button_paste:
onClick(CalculatorSpecialButton.paste); onClick(CalculatorSpecialButton.paste);
break; break;
case R.id.cpp_button_copy: case R.id.cpp_button_copy:
onClick(CalculatorSpecialButton.copy); onClick(CalculatorSpecialButton.copy);
break; break;
case R.id.cpp_button_like: case R.id.cpp_button_like:
onClick(CalculatorSpecialButton.like); onClick(CalculatorSpecialButton.like);
break; break;
case R.id.cpp_button_operators: case R.id.cpp_button_operators:
onClick(CalculatorSpecialButton.operators); onClick(CalculatorSpecialButton.operators);
break; break;
case R.id.cpp_button_vars: case R.id.cpp_button_vars:
onClick(CalculatorSpecialButton.vars); onClick(CalculatorSpecialButton.vars);
break; break;
case R.id.cpp_button_equals: case R.id.cpp_button_equals:
onClick(CalculatorSpecialButton.equals); onClick(CalculatorSpecialButton.equals);
break; break;
} }
} }
private void onClick(@Nonnull CalculatorSpecialButton b) { private void onClick(@Nonnull CalculatorSpecialButton b) {
onClick(b.getActionCode()); onClick(b.getActionCode());
} }
private void onClick(@Nonnull String s) { private void onClick(@Nonnull String s) {
Locator.getInstance().getKeyboard().buttonPressed(s); Locator.getInstance().getKeyboard().buttonPressed(s);
} }
public void attachToViews(@Nonnull ViewsCache views) { public void attachToViews(@Nonnull ViewsCache views) {
attachToView(views, R.id.cpp_button_0); attachToView(views, R.id.cpp_button_0);
attachToView(views, R.id.cpp_button_1); attachToView(views, R.id.cpp_button_1);
attachToView(views, R.id.cpp_button_2); attachToView(views, R.id.cpp_button_2);
attachToView(views, R.id.cpp_button_3); attachToView(views, R.id.cpp_button_3);
attachToView(views, R.id.cpp_button_4); attachToView(views, R.id.cpp_button_4);
attachToView(views, R.id.cpp_button_5); attachToView(views, R.id.cpp_button_5);
attachToView(views, R.id.cpp_button_6); attachToView(views, R.id.cpp_button_6);
attachToView(views, R.id.cpp_button_7); attachToView(views, R.id.cpp_button_7);
attachToView(views, R.id.cpp_button_8); attachToView(views, R.id.cpp_button_8);
attachToView(views, R.id.cpp_button_9); attachToView(views, R.id.cpp_button_9);
attachToView(views, R.id.cpp_button_division); attachToView(views, R.id.cpp_button_division);
attachToView(views, R.id.cpp_button_period); attachToView(views, R.id.cpp_button_period);
attachToView(views, R.id.cpp_button_left); attachToView(views, R.id.cpp_button_left);
attachToView(views, R.id.cpp_button_subtraction); attachToView(views, R.id.cpp_button_subtraction);
attachToView(views, R.id.cpp_button_multiplication); attachToView(views, R.id.cpp_button_multiplication);
attachToView(views, R.id.cpp_button_plus); attachToView(views, R.id.cpp_button_plus);
attachToView(views, R.id.cpp_button_right); attachToView(views, R.id.cpp_button_right);
attachToView(views, R.id.cpp_button_round_brackets); attachToView(views, R.id.cpp_button_round_brackets);
attachToView(views, R.id.cpp_button_clear); attachToView(views, R.id.cpp_button_clear);
attachToView(views, R.id.cpp_button_functions); attachToView(views, R.id.cpp_button_functions);
attachToView(views, R.id.cpp_button_history); attachToView(views, R.id.cpp_button_history);
attachToView(views, R.id.cpp_button_erase); attachToView(views, R.id.cpp_button_erase);
attachToView(views, R.id.cpp_button_paste); attachToView(views, R.id.cpp_button_paste);
attachToView(views, R.id.cpp_button_copy); attachToView(views, R.id.cpp_button_copy);
attachToView(views, R.id.cpp_button_like); attachToView(views, R.id.cpp_button_like);
attachToView(views, R.id.cpp_button_operators); attachToView(views, R.id.cpp_button_operators);
attachToView(views, R.id.cpp_button_vars); attachToView(views, R.id.cpp_button_vars);
attachToView(views, R.id.cpp_button_equals); attachToView(views, R.id.cpp_button_equals);
} }
private void attachToView(@Nonnull ViewsCache views, @IdRes int viewId) { private void attachToView(@Nonnull ViewsCache views, @IdRes int viewId) {
final View view = views.findViewById(viewId); final View view = views.findViewById(viewId);
if (view != null) { if (view != null) {
view.setOnClickListener(this); view.setOnClickListener(this);
} }
} }
} }

View File

@ -32,8 +32,13 @@ import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.view.*; import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.Window;
import android.widget.TextView; import android.widget.TextView;
import org.solovyev.android.Activities; import org.solovyev.android.Activities;
import org.solovyev.android.Android; import org.solovyev.android.Android;
import org.solovyev.android.Threads; import org.solovyev.android.Threads;
@ -54,230 +59,232 @@ import static android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; 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.Preferences.Gui.preventScreenFromFading;
import static org.solovyev.android.calculator.release.ReleaseNotes.hasReleaseNotes; import static org.solovyev.android.calculator.release.ReleaseNotes.hasReleaseNotes;
import static org.solovyev.android.wizard.WizardUi.*; 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 { public class CalculatorActivity extends BaseActivity implements SharedPreferences.OnSharedPreferenceChangeListener, CalculatorEventListener {
@Nonnull @Nonnull
public static final String TAG = CalculatorActivity.class.getSimpleName(); public static final String TAG = CalculatorActivity.class.getSimpleName();
private boolean useBackAsPrev; private boolean useBackAsPrev;
public CalculatorActivity() { public CalculatorActivity() {
super(0, TAG); super(0, TAG);
} }
/** private static void firstTimeInit(@Nonnull SharedPreferences preferences, @Nonnull Context context) {
* Called when the activity is first created. final Integer appOpenedCounter = Preferences.appOpenedCounter.getPreference(preferences);
*/ if (appOpenedCounter != null) {
@Override Preferences.appOpenedCounter.putPreference(preferences, appOpenedCounter + 1);
public void onCreate(@Nullable Bundle savedInstanceState) { }
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
final Preferences.Gui.Layout layout = Preferences.Gui.layout.getPreferenceNoError(preferences);
ui.setLayoutId(layout.getLayoutId());
super.onCreate(savedInstanceState); final Integer savedVersion = Preferences.appVersion.getPreference(preferences);
if (isMultiPane()) { final int appVersion = Android.getAppVersionCode(context);
ui.addTab(this, CalculatorFragmentType.history, null, R.id.main_second_pane);
ui.addTab(this, CalculatorFragmentType.saved_history, null, R.id.main_second_pane);
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())) {
actionBar.hide();
} else {
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
}
}
FragmentUtils.createFragment(this, CalculatorEditorFragment.class, R.id.editorContainer, "editor"); Preferences.appVersion.putPreference(preferences, appVersion);
FragmentUtils.createFragment(this, CalculatorDisplayFragment.class, R.id.displayContainer, "display");
FragmentUtils.createFragment(this, CalculatorKeyboardFragment.class, R.id.keyboardContainer, "keyboard");
this.useBackAsPrev = Preferences.Gui.usePrevAsBack.getPreference(preferences); if (!CalculatorApplication.isMonkeyRunner(context)) {
if (savedInstanceState == null) {
firstTimeInit(preferences, this);
}
toggleOrientationChange(preferences); boolean dialogShown = false;
final Wizards wizards = CalculatorApplication.getInstance().getWizards();
final Wizard wizard = wizards.getWizard(CalculatorWizards.FIRST_TIME_WIZARD);
if (wizard.isStarted() && !wizard.isFinished()) {
continueWizard(wizards, wizard.getName(), context);
dialogShown = true;
} else {
if (Objects.areEqual(savedVersion, Preferences.appVersion.getDefaultValue())) {
// new start
startWizard(wizards, context);
dialogShown = true;
} else {
if (savedVersion < appVersion) {
final boolean showReleaseNotes = Preferences.Gui.showReleaseNotes.getPreference(preferences);
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;
}
}
}
}
preferences.registerOnSharedPreferenceChangeListener(this); //Log.d(this.getClass().getName(), "Application was opened " + appOpenedCounter + " time!");
if (!dialogShown) {
if (appOpenedCounter != null && appOpenedCounter > 30) {
dialogShown = showSpecialWindow(preferences, Preferences.Gui.feedbackWindowShown, R.layout.feedback, R.id.feedbackText, context);
}
}
}
}
Locator.getInstance().getPreferenceService().checkPreferredPreferences(false); private static boolean showSpecialWindow(@Nonnull SharedPreferences preferences, @Nonnull Preference<Boolean> specialWindowShownPref, int layoutId, int textViewId, @Nonnull Context context) {
boolean result = false;
if (CalculatorApplication.isMonkeyRunner(this)) { final Boolean specialWindowShown = specialWindowShownPref.getPreference(preferences);
Locator.getInstance().getKeyboard().buttonPressed("123"); if (specialWindowShown != null && !specialWindowShown) {
Locator.getInstance().getKeyboard().buttonPressed("+"); final LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);
Locator.getInstance().getKeyboard().buttonPressed("321"); final View view = layoutInflater.inflate(layoutId, null);
}
}
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) final TextView feedbackTextView = (TextView) view.findViewById(textViewId);
private boolean hasPermanentMenuKey() { feedbackTextView.setMovementMethod(LinkMovementMethod.getInstance());
return ViewConfiguration.get(this).hasPermanentMenuKey();
}
private boolean isMultiPane() { final AlertDialog.Builder builder = new AlertDialog.Builder(context).setView(view);
return findViewById(R.id.main_second_pane) != null; builder.setPositiveButton(android.R.string.ok, null);
} builder.create().show();
@Nonnull result = true;
private AndroidCalculator getCalculator() { specialWindowShownPref.putPreference(preferences, true);
return ((AndroidCalculator) Locator.getInstance().getCalculator()); }
}
private static void firstTimeInit(@Nonnull SharedPreferences preferences, @Nonnull Context context) { return result;
final Integer appOpenedCounter = Preferences.appOpenedCounter.getPreference(preferences); }
if (appOpenedCounter != null) {
Preferences.appOpenedCounter.putPreference(preferences, appOpenedCounter + 1);
}
final Integer savedVersion = Preferences.appVersion.getPreference(preferences); /**
* Called when the activity is first created.
*/
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
final Preferences.Gui.Layout layout = Preferences.Gui.layout.getPreferenceNoError(preferences);
ui.setLayoutId(layout.getLayoutId());
final int appVersion = Android.getAppVersionCode(context); super.onCreate(savedInstanceState);
Preferences.appVersion.putPreference(preferences, appVersion); if (isMultiPane()) {
ui.addTab(this, CalculatorFragmentType.history, null, R.id.main_second_pane);
ui.addTab(this, CalculatorFragmentType.saved_history, null, R.id.main_second_pane);
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())) {
actionBar.hide();
} else {
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
}
}
if (!CalculatorApplication.isMonkeyRunner(context)) { FragmentUtils.createFragment(this, CalculatorEditorFragment.class, R.id.editorContainer, "editor");
FragmentUtils.createFragment(this, CalculatorDisplayFragment.class, R.id.displayContainer, "display");
FragmentUtils.createFragment(this, CalculatorKeyboardFragment.class, R.id.keyboardContainer, "keyboard");
boolean dialogShown = false; this.useBackAsPrev = Preferences.Gui.usePrevAsBack.getPreference(preferences);
final Wizards wizards = CalculatorApplication.getInstance().getWizards(); if (savedInstanceState == null) {
final Wizard wizard = wizards.getWizard(CalculatorWizards.FIRST_TIME_WIZARD); firstTimeInit(preferences, this);
if (wizard.isStarted() && !wizard.isFinished()) { }
continueWizard(wizards, wizard.getName(), context);
dialogShown = true;
} else {
if (Objects.areEqual(savedVersion, Preferences.appVersion.getDefaultValue())) {
// new start
startWizard(wizards, context);
dialogShown = true;
} else {
if (savedVersion < appVersion) {
final boolean showReleaseNotes = Preferences.Gui.showReleaseNotes.getPreference(preferences);
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;
}
}
}
}
//Log.d(this.getClass().getName(), "Application was opened " + appOpenedCounter + " time!"); toggleOrientationChange(preferences);
if (!dialogShown) {
if (appOpenedCounter != null && appOpenedCounter > 30) {
dialogShown = showSpecialWindow(preferences, Preferences.Gui.feedbackWindowShown, R.layout.feedback, R.id.feedbackText, context);
}
}
}
}
private static boolean showSpecialWindow(@Nonnull SharedPreferences preferences, @Nonnull Preference<Boolean> specialWindowShownPref, int layoutId, int textViewId, @Nonnull Context context) { preferences.registerOnSharedPreferenceChangeListener(this);
boolean result = false;
final Boolean specialWindowShown = specialWindowShownPref.getPreference(preferences); Locator.getInstance().getPreferenceService().checkPreferredPreferences(false);
if (specialWindowShown != null && !specialWindowShown) {
final LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE);
final View view = layoutInflater.inflate(layoutId, null);
final TextView feedbackTextView = (TextView) view.findViewById(textViewId); if (CalculatorApplication.isMonkeyRunner(this)) {
feedbackTextView.setMovementMethod(LinkMovementMethod.getInstance()); Locator.getInstance().getKeyboard().buttonPressed("123");
Locator.getInstance().getKeyboard().buttonPressed("+");
Locator.getInstance().getKeyboard().buttonPressed("321");
}
}
final AlertDialog.Builder builder = new AlertDialog.Builder(context).setView(view); @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
builder.setPositiveButton(android.R.string.ok, null); private boolean hasPermanentMenuKey() {
builder.create().show(); return ViewConfiguration.get(this).hasPermanentMenuKey();
}
result = true; private boolean isMultiPane() {
specialWindowShownPref.putPreference(preferences, true); return findViewById(R.id.main_second_pane) != null;
} }
return result; @Nonnull
} private AndroidCalculator getCalculator() {
return ((AndroidCalculator) Locator.getInstance().getCalculator());
}
@Override @Override
public boolean onKeyDown(int keyCode, KeyEvent event) { public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) { if (keyCode == KeyEvent.KEYCODE_BACK) {
if (useBackAsPrev) { if (useBackAsPrev) {
getCalculator().doHistoryAction(HistoryAction.undo); getCalculator().doHistoryAction(HistoryAction.undo);
return true; return true;
} }
} }
return super.onKeyDown(keyCode, event); return super.onKeyDown(keyCode, event);
} }
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
final Preferences.Gui.Layout newLayout = Preferences.Gui.layout.getPreference(preferences); final Preferences.Gui.Layout newLayout = Preferences.Gui.layout.getPreference(preferences);
if (newLayout != ui.getLayout()) { if (newLayout != ui.getLayout()) {
Activities.restartActivity(this); Activities.restartActivity(this);
} }
final Window window = getWindow(); final Window window = getWindow();
if (preventScreenFromFading.getPreference(preferences)) { if (preventScreenFromFading.getPreference(preferences)) {
window.addFlags(FLAG_KEEP_SCREEN_ON); window.addFlags(FLAG_KEEP_SCREEN_ON);
} else { } else {
window.clearFlags(FLAG_KEEP_SCREEN_ON); window.clearFlags(FLAG_KEEP_SCREEN_ON);
} }
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this); PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this);
super.onDestroy(); super.onDestroy();
} }
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences preferences, @Nullable String key) { public void onSharedPreferenceChanged(SharedPreferences preferences, @Nullable String key) {
if (Preferences.Gui.usePrevAsBack.getKey().equals(key)) { if (Preferences.Gui.usePrevAsBack.getKey().equals(key)) {
useBackAsPrev = Preferences.Gui.usePrevAsBack.getPreference(preferences); useBackAsPrev = Preferences.Gui.usePrevAsBack.getPreference(preferences);
} }
if (Preferences.Gui.autoOrientation.getKey().equals(key)) { if (Preferences.Gui.autoOrientation.getKey().equals(key)) {
toggleOrientationChange(preferences); toggleOrientationChange(preferences);
} }
} }
private void toggleOrientationChange(@Nullable SharedPreferences preferences) { private void toggleOrientationChange(@Nullable SharedPreferences preferences) {
preferences = preferences == null ? PreferenceManager.getDefaultSharedPreferences(this) : preferences; preferences = preferences == null ? PreferenceManager.getDefaultSharedPreferences(this) : preferences;
if (Preferences.Gui.autoOrientation.getPreference(preferences)) { if (Preferences.Gui.autoOrientation.getPreference(preferences)) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
} else { } else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} }
} }
@Override @Override
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) { public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
switch (calculatorEventType) { switch (calculatorEventType) {
case plot_graph: case plot_graph:
Threads.tryRunOnUiThread(this, new Runnable() { Threads.tryRunOnUiThread(this, new Runnable() {
@Override @Override
public void run() { public void run() {
if (isMultiPane()) { if (isMultiPane()) {
final ActionBar.Tab selectedTab = getSupportActionBar().getSelectedTab(); final ActionBar.Tab selectedTab = getSupportActionBar().getSelectedTab();
if (selectedTab != null && CalculatorFragmentType.plotter.getFragmentTag().equals(selectedTab.getTag())) { if (selectedTab != null && CalculatorFragmentType.plotter.getFragmentTag().equals(selectedTab.getTag())) {
// do nothing - fragment shown and already registered for plot updates // do nothing - fragment shown and already registered for plot updates
} else { } else {
// otherwise - open fragment // otherwise - open fragment
ui.selectTab(CalculatorActivity.this, CalculatorFragmentType.plotter); ui.selectTab(CalculatorActivity.this, CalculatorFragmentType.plotter);
} }
} else { } else {
// start new activity // start new activity
CalculatorActivityLauncher.plotGraph(CalculatorActivity.this); CalculatorActivityLauncher.plotGraph(CalculatorActivity.this);
} }
} }
}); });
break; break;
} }
} }
} }

View File

@ -29,16 +29,20 @@ import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.net.Uri; import android.net.Uri;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import android.support.v7.app.ActionBarActivity;
import jscl.math.Generic;
import org.solovyev.android.Android; import org.solovyev.android.Android;
import org.solovyev.android.calculator.about.CalculatorAboutActivity; import org.solovyev.android.calculator.about.CalculatorAboutActivity;
import org.solovyev.android.calculator.function.FunctionEditDialogFragment; import org.solovyev.android.calculator.function.FunctionEditDialogFragment;
import org.solovyev.android.calculator.history.CalculatorHistoryActivity; import org.solovyev.android.calculator.history.CalculatorHistoryActivity;
import org.solovyev.android.calculator.math.edit.*; import org.solovyev.android.calculator.math.edit.CalculatorFunctionsActivity;
import org.solovyev.android.calculator.math.edit.CalculatorOperatorsActivity;
import org.solovyev.android.calculator.math.edit.CalculatorVarsActivity;
import org.solovyev.android.calculator.math.edit.CalculatorVarsFragment;
import org.solovyev.android.calculator.math.edit.VarEditDialogFragment;
import org.solovyev.android.calculator.matrix.CalculatorMatrixActivity; import org.solovyev.android.calculator.matrix.CalculatorMatrixActivity;
import org.solovyev.android.calculator.plot.CalculatorPlotActivity; import org.solovyev.android.calculator.plot.CalculatorPlotActivity;
import org.solovyev.android.calculator.plot.CalculatorPlotter; import org.solovyev.android.calculator.plot.CalculatorPlotter;
@ -47,9 +51,12 @@ import org.solovyev.common.msg.Message;
import org.solovyev.common.msg.MessageType; import org.solovyev.common.msg.MessageType;
import org.solovyev.common.text.Strings; import org.solovyev.common.text.Strings;
import java.util.List;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.List;
import jscl.math.Generic;
/** /**
* User: serso * User: serso
@ -58,235 +65,235 @@ import java.util.List;
*/ */
public final class CalculatorActivityLauncher implements CalculatorEventListener { public final class CalculatorActivityLauncher implements CalculatorEventListener {
public CalculatorActivityLauncher() { public CalculatorActivityLauncher() {
} }
public static void showHistory(@Nonnull final Context context) { public static void showHistory(@Nonnull final Context context) {
showHistory(context, false); showHistory(context, false);
} }
public static void showHistory(@Nonnull final Context context, boolean detached) { public static void showHistory(@Nonnull final Context context, boolean detached) {
final Intent intent = new Intent(context, CalculatorHistoryActivity.class); final Intent intent = new Intent(context, CalculatorHistoryActivity.class);
Android.addIntentFlags(intent, detached, context); Android.addIntentFlags(intent, detached, context);
context.startActivity(intent); context.startActivity(intent);
} }
public static void showSettings(@Nonnull final Context context) { public static void showSettings(@Nonnull final Context context) {
showSettings(context, false); showSettings(context, false);
} }
public static void showSettings(@Nonnull final Context context, boolean detached) { public static void showSettings(@Nonnull final Context context, boolean detached) {
final Intent intent = new Intent(context, PreferencesActivity.class); final Intent intent = new Intent(context, PreferencesActivity.class);
Android.addIntentFlags(intent, detached, context); Android.addIntentFlags(intent, detached, context);
context.startActivity(intent); context.startActivity(intent);
} }
public static void showAbout(@Nonnull final Context context) { public static void showAbout(@Nonnull final Context context) {
context.startActivity(new Intent(context, CalculatorAboutActivity.class)); context.startActivity(new Intent(context, CalculatorAboutActivity.class));
} }
public static void showFunctions(@Nonnull final Context context) { public static void showFunctions(@Nonnull final Context context) {
showFunctions(context, false); showFunctions(context, false);
} }
public static void showFunctions(@Nonnull final Context context, boolean detached) { public static void showFunctions(@Nonnull final Context context, boolean detached) {
final Intent intent = new Intent(context, CalculatorFunctionsActivity.class); final Intent intent = new Intent(context, CalculatorFunctionsActivity.class);
Android.addIntentFlags(intent, detached, context); Android.addIntentFlags(intent, detached, context);
context.startActivity(intent); context.startActivity(intent);
} }
public static void showOperators(@Nonnull final Context context) { public static void showOperators(@Nonnull final Context context) {
showOperators(context, false); showOperators(context, false);
} }
public static void showOperators(@Nonnull final Context context, boolean detached) { public static void showOperators(@Nonnull final Context context, boolean detached) {
final Intent intent = new Intent(context, CalculatorOperatorsActivity.class); final Intent intent = new Intent(context, CalculatorOperatorsActivity.class);
Android.addIntentFlags(intent, detached, context); Android.addIntentFlags(intent, detached, context);
context.startActivity(intent); context.startActivity(intent);
} }
public static void showVars(@Nonnull final Context context) { public static void showVars(@Nonnull final Context context) {
showVars(context, false); showVars(context, false);
} }
public static void showVars(@Nonnull final Context context, boolean detached) { public static void showVars(@Nonnull final Context context, boolean detached) {
final Intent intent = new Intent(context, CalculatorVarsActivity.class); final Intent intent = new Intent(context, CalculatorVarsActivity.class);
Android.addIntentFlags(intent, detached, context); Android.addIntentFlags(intent, detached, context);
context.startActivity(intent); context.startActivity(intent);
} }
public static void plotGraph(@Nonnull final Context context) { public static void plotGraph(@Nonnull final Context context) {
final Intent intent = new Intent(); final Intent intent = new Intent();
intent.setClass(context, CalculatorPlotActivity.class); intent.setClass(context, CalculatorPlotActivity.class);
Android.addIntentFlags(intent, false, context); Android.addIntentFlags(intent, false, context);
context.startActivity(intent); context.startActivity(intent);
} }
public static void tryCreateVar(@Nonnull final Context context) { public static void tryCreateVar(@Nonnull final Context context) {
final CalculatorDisplay display = Locator.getInstance().getDisplay(); final CalculatorDisplay display = Locator.getInstance().getDisplay();
final CalculatorDisplayViewState viewState = display.getViewState(); final CalculatorDisplayViewState viewState = display.getViewState();
if (viewState.isValid()) { if (viewState.isValid()) {
final String varValue = viewState.getText(); final String varValue = viewState.getText();
if (!Strings.isEmpty(varValue)) { if (!Strings.isEmpty(varValue)) {
if (CalculatorVarsFragment.isValidValue(varValue)) { if (CalculatorVarsFragment.isValidValue(varValue)) {
if (context instanceof ActionBarActivity) { if (context instanceof ActionBarActivity) {
VarEditDialogFragment.showDialog(VarEditDialogFragment.Input.newFromValue(varValue), ((ActionBarActivity) context).getSupportFragmentManager()); VarEditDialogFragment.showDialog(VarEditDialogFragment.Input.newFromValue(varValue), ((ActionBarActivity) context).getSupportFragmentManager());
} else { } else {
final Intent intent = new Intent(context, CalculatorVarsActivity.class); final Intent intent = new Intent(context, CalculatorVarsActivity.class);
intent.putExtra(CalculatorVarsFragment.CREATE_VAR_EXTRA_STRING, varValue); intent.putExtra(CalculatorVarsFragment.CREATE_VAR_EXTRA_STRING, varValue);
Android.addIntentFlags(intent, false, context); Android.addIntentFlags(intent, false, context);
context.startActivity(intent); context.startActivity(intent);
} }
} else { } else {
getNotifier().showMessage(R.string.c_value_is_not_a_number, MessageType.error); getNotifier().showMessage(R.string.c_value_is_not_a_number, MessageType.error);
} }
} else { } else {
getNotifier().showMessage(R.string.empty_var_error, MessageType.error); getNotifier().showMessage(R.string.empty_var_error, MessageType.error);
} }
} else { } else {
getNotifier().showMessage(R.string.not_valid_result, MessageType.error); getNotifier().showMessage(R.string.not_valid_result, MessageType.error);
} }
} }
public static void tryCreateFunction(@Nonnull final Context context) { public static void tryCreateFunction(@Nonnull final Context context) {
final CalculatorDisplay display = Locator.getInstance().getDisplay(); final CalculatorDisplay display = Locator.getInstance().getDisplay();
final CalculatorDisplayViewState viewState = display.getViewState(); final CalculatorDisplayViewState viewState = display.getViewState();
if (viewState.isValid()) { if (viewState.isValid()) {
final String functionValue = viewState.getText(); final String functionValue = viewState.getText();
if (!Strings.isEmpty(functionValue)) { if (!Strings.isEmpty(functionValue)) {
FunctionEditDialogFragment.showDialog(FunctionEditDialogFragment.Input.newFromDisplay(viewState), context); FunctionEditDialogFragment.showDialog(FunctionEditDialogFragment.Input.newFromDisplay(viewState), context);
} else { } else {
getNotifier().showMessage(R.string.empty_function_error, MessageType.error); getNotifier().showMessage(R.string.empty_function_error, MessageType.error);
} }
} else { } else {
getNotifier().showMessage(R.string.not_valid_result, MessageType.error); getNotifier().showMessage(R.string.not_valid_result, MessageType.error);
} }
} }
@Nonnull @Nonnull
private static CalculatorNotifier getNotifier() { private static CalculatorNotifier getNotifier() {
return Locator.getInstance().getNotifier(); return Locator.getInstance().getNotifier();
} }
public static void tryPlot() { public static void tryPlot() {
final CalculatorPlotter plotter = Locator.getInstance().getPlotter(); final CalculatorPlotter plotter = Locator.getInstance().getPlotter();
final CalculatorDisplay display = Locator.getInstance().getDisplay(); final CalculatorDisplay display = Locator.getInstance().getDisplay();
final CalculatorDisplayViewState viewState = display.getViewState(); final CalculatorDisplayViewState viewState = display.getViewState();
if (viewState.isValid()) { if (viewState.isValid()) {
final String functionValue = viewState.getText(); final String functionValue = viewState.getText();
final Generic expression = viewState.getResult(); final Generic expression = viewState.getResult();
if (!Strings.isEmpty(functionValue) && expression != null) { if (!Strings.isEmpty(functionValue) && expression != null) {
if (plotter.isPlotPossibleFor(expression)) { if (plotter.isPlotPossibleFor(expression)) {
plotter.plot(expression); plotter.plot(expression);
} else { } else {
getNotifier().showMessage(R.string.cpp_plot_too_many_variables, MessageType.error); getNotifier().showMessage(R.string.cpp_plot_too_many_variables, MessageType.error);
} }
} else { } else {
getNotifier().showMessage(R.string.cpp_plot_empty_function_error, MessageType.error); getNotifier().showMessage(R.string.cpp_plot_empty_function_error, MessageType.error);
} }
} else { } else {
getNotifier().showMessage(R.string.not_valid_result, MessageType.error); getNotifier().showMessage(R.string.not_valid_result, MessageType.error);
} }
} }
public static void openApp(@Nonnull Context context) { public static void openApp(@Nonnull Context context) {
final Intent intent = new Intent(context, CalculatorActivity.class); final Intent intent = new Intent(context, CalculatorActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent); context.startActivity(intent);
} }
public static void likeButtonPressed(@Nonnull final Context context) { public static void likeButtonPressed(@Nonnull final Context context) {
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(context.getString(R.string.cpp_share_link))); final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(context.getString(R.string.cpp_share_link)));
Android.addIntentFlags(intent, false, context); Android.addIntentFlags(intent, false, context);
context.startActivity(intent); context.startActivity(intent);
} }
public static void showCalculationMessagesDialog(@Nonnull Context context, @Nonnull List<Message> messages) { public static void showCalculationMessagesDialog(@Nonnull Context context, @Nonnull List<Message> messages) {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
if (Preferences.Calculations.showCalculationMessagesDialog.getPreference(prefs)) { if (Preferences.Calculations.showCalculationMessagesDialog.getPreference(prefs)) {
FixableMessagesDialog.showDialogForMessages(messages, context, true); FixableMessagesDialog.showDialogForMessages(messages, context, true);
} }
} }
@Override public static void showEvaluationError(@Nonnull Context context, @Nonnull final String errorMessage) {
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) { final LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
final Context context;
final Object source = calculatorEventData.getSource(); final View errorMessageView = layoutInflater.inflate(R.layout.display_error_message, null);
if (source instanceof Context) { ((TextView) errorMessageView.findViewById(R.id.error_message_text_view)).setText(errorMessage);
context = ((Context) source);
} else {
context = App.getApplication();
}
switch (calculatorEventType) { final AlertDialog.Builder builder = new AlertDialog.Builder(context)
case show_create_matrix_dialog: .setPositiveButton(R.string.c_cancel, null)
App.getUiThreadExecutor().execute(new Runnable() { .setView(errorMessageView);
@Override
public void run() {
final Intent intent = new Intent(context, CalculatorMatrixActivity.class);
Android.addIntentFlags(intent, false, context);
context.startActivity(intent);
}
});
break;
case show_create_var_dialog:
App.getUiThreadExecutor().execute(new Runnable() {
@Override
public void run() {
CalculatorActivityLauncher.tryCreateVar(context);
}
});
break;
case show_create_function_dialog:
App.getUiThreadExecutor().execute(new Runnable() {
@Override
public void run() {
CalculatorActivityLauncher.tryCreateFunction(context);
}
});
break;
case show_evaluation_error:
final String errorMessage = (String) data;
if (errorMessage != null) {
App.getUiThreadExecutor().execute(new Runnable() {
@Override
public void run() {
showEvaluationError(context, errorMessage);
}
});
}
break;
case show_message_dialog:
final DialogData dialogData = (DialogData) data;
if (dialogData != null) {
App.getUiThreadExecutor().execute(new Runnable() {
@Override
public void run() {
CalculatorDialogActivity.showDialog(context, dialogData);
}
});
}
break;
} builder.create().show();
} }
public static void showEvaluationError(@Nonnull Context context, @Nonnull final String errorMessage) { @Override
final LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE); public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
final Context context;
final View errorMessageView = layoutInflater.inflate(R.layout.display_error_message, null); final Object source = calculatorEventData.getSource();
((TextView) errorMessageView.findViewById(R.id.error_message_text_view)).setText(errorMessage); if (source instanceof Context) {
context = ((Context) source);
} else {
context = App.getApplication();
}
final AlertDialog.Builder builder = new AlertDialog.Builder(context) switch (calculatorEventType) {
.setPositiveButton(R.string.c_cancel, null) case show_create_matrix_dialog:
.setView(errorMessageView); App.getUiThreadExecutor().execute(new Runnable() {
@Override
public void run() {
final Intent intent = new Intent(context, CalculatorMatrixActivity.class);
Android.addIntentFlags(intent, false, context);
context.startActivity(intent);
}
});
break;
case show_create_var_dialog:
App.getUiThreadExecutor().execute(new Runnable() {
@Override
public void run() {
CalculatorActivityLauncher.tryCreateVar(context);
}
});
break;
case show_create_function_dialog:
App.getUiThreadExecutor().execute(new Runnable() {
@Override
public void run() {
CalculatorActivityLauncher.tryCreateFunction(context);
}
});
break;
case show_evaluation_error:
final String errorMessage = (String) data;
if (errorMessage != null) {
App.getUiThreadExecutor().execute(new Runnable() {
@Override
public void run() {
showEvaluationError(context, errorMessage);
}
});
}
break;
case show_message_dialog:
final DialogData dialogData = (DialogData) data;
if (dialogData != null) {
App.getUiThreadExecutor().execute(new Runnable() {
@Override
public void run() {
CalculatorDialogActivity.showDialog(context, dialogData);
}
});
}
break;
builder.create().show(); }
} }
} }

View File

@ -35,15 +35,15 @@ import javax.annotation.Nullable;
*/ */
public class CalculatorActivityMobile extends CalculatorActivity { public class CalculatorActivityMobile extends CalculatorActivity {
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
Preferences.Gui.layout.putPreference(prefs, Preferences.Gui.Layout.main_calculator_mobile); Preferences.Gui.layout.putPreference(prefs, Preferences.Gui.Layout.main_calculator_mobile);
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (!CalculatorApplication.isMonkeyRunner(this)) { if (!CalculatorApplication.isMonkeyRunner(this)) {
this.finish(); this.finish();
} }
} }
} }

View File

@ -55,34 +55,31 @@ import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ReportsCrashes(formKey = "", @ReportsCrashes(formKey = "",
formUri = "https://serso.cloudant.com/acra-cpp/_design/acra-storage/_update/report", formUri = "https://serso.cloudant.com/acra-cpp/_design/acra-storage/_update/report",
reportType = org.acra.sender.HttpSender.Type.JSON, reportType = org.acra.sender.HttpSender.Type.JSON,
httpMethod = org.acra.sender.HttpSender.Method.PUT, httpMethod = org.acra.sender.HttpSender.Method.PUT,
formUriBasicAuthLogin="timbeenterumisideffecird", formUriBasicAuthLogin = "timbeenterumisideffecird",
formUriBasicAuthPassword="ECL65PO2TH5quIFNAK4hQ5Ng", formUriBasicAuthPassword = "ECL65PO2TH5quIFNAK4hQ5Ng",
mode = ReportingInteractionMode.TOAST, mode = ReportingInteractionMode.TOAST,
resToastText = R.string.crashed) resToastText = R.string.crashed)
public class CalculatorApplication extends android.app.Application implements SharedPreferences.OnSharedPreferenceChangeListener { public class CalculatorApplication extends android.app.Application implements SharedPreferences.OnSharedPreferenceChangeListener {
/* /*
********************************************************************** **********************************************************************
* *
* CONSTANTS * CONSTANTS
* *
********************************************************************** **********************************************************************
*/ */
@Nonnull public static final String AD_FREE_PRODUCT_ID = "ad_free";
static final String MAIL = "se.solovyev@gmail.com"; public static final String AD_FREE_P_KEY = "org.solovyev.android.calculator_ad_free";
public static final String ADMOB = "ca-app-pub-2228934497384784/2916398892";
private static final String TAG = "C++"; @Nonnull
static final String MAIL = "se.solovyev@gmail.com";
public static final String AD_FREE_PRODUCT_ID = "ad_free"; private static final String TAG = "C++";
public static final String AD_FREE_P_KEY = "org.solovyev.android.calculator_ad_free"; @Nonnull
public static final String ADMOB = "ca-app-pub-2228934497384784/2916398892"; private static CalculatorApplication instance;
@Nonnull
private static CalculatorApplication instance;
/* /*
********************************************************************** **********************************************************************
@ -91,17 +88,14 @@ public class CalculatorApplication extends android.app.Application implements Sh
* *
********************************************************************** **********************************************************************
*/ */
@Nonnull
protected final Handler uiHandler = new Handler();
@Nonnull
private final List<CalculatorEventListener> listeners = new ArrayList<CalculatorEventListener>();
@Nonnull
private final Wizards wizards = new CalculatorWizards(this);
@Nonnull private Typeface typeFace;
private final List<CalculatorEventListener> listeners = new ArrayList<CalculatorEventListener>();
@Nonnull
protected final Handler uiHandler = new Handler();
@Nonnull
private final Wizards wizards = new CalculatorWizards(this);
private Typeface typeFace;
/* /*
********************************************************************** **********************************************************************
@ -111,9 +105,9 @@ public class CalculatorApplication extends android.app.Application implements Sh
********************************************************************** **********************************************************************
*/ */
public CalculatorApplication() { public CalculatorApplication() {
instance = this; instance = this;
} }
/* /*
********************************************************************** **********************************************************************
@ -123,131 +117,128 @@ public class CalculatorApplication extends android.app.Application implements Sh
********************************************************************** **********************************************************************
*/ */
@Override @Nonnull
public void onCreate() { public static CalculatorApplication getInstance() {
if (!BuildConfig.DEBUG) { return instance;
ACRA.init(this); }
} else {
LeakCanary.install(this);
}
if (!App.isInitialized()) { @Nonnull
App.init(this); public static SharedPreferences getPreferences() {
} return PreferenceManager.getDefaultSharedPreferences(getInstance());
}
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); public static boolean isMonkeyRunner(@Nonnull Context context) {
Preferences.setDefaultValues(preferences); // NOTE: this code is only for monkeyrunner
return context.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD) == PackageManager.PERMISSION_GRANTED;
}
preferences.registerOnSharedPreferenceChangeListener(this); @Override
public void onCreate() {
if (!BuildConfig.DEBUG) {
ACRA.init(this);
} else {
LeakCanary.install(this);
}
setTheme(preferences); if (!App.isInitialized()) {
setLanguageInitially(); App.init(this);
}
super.onCreate(); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
App.getLanguages().updateLanguage(this, true); Preferences.setDefaultValues(preferences);
if (!Preferences.Ga.initialReportDone.getPreference(preferences)) { preferences.registerOnSharedPreferenceChangeListener(this);
App.getGa().reportInitially(preferences);
Preferences.Ga.initialReportDone.putPreference(preferences, true);
}
final AndroidCalculator calculator = new AndroidCalculator(this); setTheme(preferences);
setLanguageInitially();
final EditorTextProcessor editorTextProcessor = new EditorTextProcessor(); super.onCreate();
App.getLanguages().updateLanguage(this, true);
Locator.getInstance().init(calculator, if (!Preferences.Ga.initialReportDone.getPreference(preferences)) {
new AndroidCalculatorEngine(this), App.getGa().reportInitially(preferences);
new AndroidCalculatorClipboard(this), Preferences.Ga.initialReportDone.putPreference(preferences, true);
new AndroidCalculatorNotifier(this), }
new AndroidCalculatorHistory(this, calculator),
new AndroidCalculatorLogger(),
new AndroidCalculatorPreferenceService(this),
new AndroidCalculatorKeyboard(this, new CalculatorKeyboardImpl(calculator)),
new AndroidCalculatorPlotter(this, new CalculatorPlotterImpl(calculator)),
editorTextProcessor);
editorTextProcessor.init(this); final AndroidCalculator calculator = new AndroidCalculator(this);
listeners.add(new CalculatorActivityLauncher()); final EditorTextProcessor editorTextProcessor = new EditorTextProcessor();
for (CalculatorEventListener listener : listeners) {
calculator.addCalculatorEventListener(listener);
}
calculator.addCalculatorEventListener(App.getBroadcaster()); Locator.getInstance().init(calculator,
new AndroidCalculatorEngine(this),
new AndroidCalculatorClipboard(this),
new AndroidCalculatorNotifier(this),
new AndroidCalculatorHistory(this, calculator),
new AndroidCalculatorLogger(),
new AndroidCalculatorPreferenceService(this),
new AndroidCalculatorKeyboard(this, new CalculatorKeyboardImpl(calculator)),
new AndroidCalculatorPlotter(this, new CalculatorPlotterImpl(calculator)),
editorTextProcessor);
Locator.getInstance().getCalculator().init(); editorTextProcessor.init(this);
new Thread(new Runnable() { listeners.add(new CalculatorActivityLauncher());
@Override for (CalculatorEventListener listener : listeners) {
public void run() { calculator.addCalculatorEventListener(listener);
try { }
// prepare engine
Locator.getInstance().getEngine().getMathEngine0().evaluate("1+1");
Locator.getInstance().getEngine().getMathEngine0().evaluate("1*1");
} catch (Throwable e) {
Log.e(TAG, e.getMessage(), e);
}
} calculator.addCalculatorEventListener(App.getBroadcaster());
}).start();
Locator.getInstance().getLogger().debug(TAG, "Application started!"); Locator.getInstance().getCalculator().init();
Locator.getInstance().getNotifier().showDebugMessage(TAG, "Application started!");
App.getUiThreadExecutor().execute(new Runnable() { new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
// we must update the widget when app starts try {
App.getBroadcaster().sendEditorStateChangedIntent(); // prepare engine
} Locator.getInstance().getEngine().getMathEngine0().evaluate("1+1");
}, 100, TimeUnit.MILLISECONDS); Locator.getInstance().getEngine().getMathEngine0().evaluate("1*1");
} } catch (Throwable e) {
Log.e(TAG, e.getMessage(), e);
}
private void setLanguageInitially() { }
// should be called before onCreate() }).start();
final Language language = App.getLanguages().getCurrent();
if (!language.isSystem() && !language.locale.equals(Locale.getDefault())) {
Locale.setDefault(language.locale);
}
}
private void setTheme(@Nonnull SharedPreferences preferences) { Locator.getInstance().getLogger().debug(TAG, "Application started!");
final Preferences.Gui.Theme theme = Preferences.Gui.getTheme(preferences); Locator.getInstance().getNotifier().showDebugMessage(TAG, "Application started!");
setTheme(theme.getThemeId());
}
@Nonnull App.getUiThreadExecutor().execute(new Runnable() {
public FragmentUi createFragmentHelper(int layoutId) { @Override
return new FragmentUi(layoutId); public void run() {
} // we must update the widget when app starts
App.getBroadcaster().sendEditorStateChangedIntent();
}
}, 100, TimeUnit.MILLISECONDS);
}
@Nonnull private void setLanguageInitially() {
public FragmentUi createFragmentHelper(int layoutId, int titleResId) { // should be called before onCreate()
return new FragmentUi(layoutId, titleResId); final Language language = App.getLanguages().getCurrent();
} if (!language.isSystem() && !language.locale.equals(Locale.getDefault())) {
Locale.setDefault(language.locale);
}
}
@Nonnull private void setTheme(@Nonnull SharedPreferences preferences) {
public FragmentUi createFragmentHelper(int layoutId, int titleResId, boolean listenersOnCreate) { final Preferences.Gui.Theme theme = Preferences.Gui.getTheme(preferences);
return new FragmentUi(layoutId, titleResId, listenersOnCreate); setTheme(theme.getThemeId());
} }
@Nonnull @Nonnull
public Handler getUiHandler() { public FragmentUi createFragmentHelper(int layoutId) {
return uiHandler; return new FragmentUi(layoutId);
} }
@Nonnull @Nonnull
public Wizards getWizards() { public FragmentUi createFragmentHelper(int layoutId, int titleResId) {
return wizards; return new FragmentUi(layoutId, titleResId);
} }
@Nonnull @Nonnull
public Typeface getTypeFace() { public FragmentUi createFragmentHelper(int layoutId, int titleResId, boolean listenersOnCreate) {
if (typeFace == null) { return new FragmentUi(layoutId, titleResId, listenersOnCreate);
typeFace = Typeface.createFromAsset(getAssets(), "fonts/Roboto-Regular.ttf"); }
}
return typeFace;
}
/* /*
********************************************************************** **********************************************************************
@ -257,27 +248,30 @@ public class CalculatorApplication extends android.app.Application implements Sh
********************************************************************** **********************************************************************
*/ */
@Nonnull @Nonnull
public static CalculatorApplication getInstance() { public Handler getUiHandler() {
return instance; return uiHandler;
} }
@Nonnull @Nonnull
public static SharedPreferences getPreferences() { public Wizards getWizards() {
return PreferenceManager.getDefaultSharedPreferences(getInstance()); return wizards;
} }
public static boolean isMonkeyRunner(@Nonnull Context context) { @Nonnull
// NOTE: this code is only for monkeyrunner public Typeface getTypeFace() {
return context.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD) == PackageManager.PERMISSION_GRANTED; if (typeFace == null) {
} typeFace = Typeface.createFromAsset(getAssets(), "fonts/Roboto-Regular.ttf");
}
return typeFace;
}
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (Preferences.Onscreen.showAppIcon.getKey().equals(key)) { if (Preferences.Onscreen.showAppIcon.getKey().equals(key)) {
boolean showAppIcon = Preferences.Onscreen.showAppIcon.getPreference(prefs); boolean showAppIcon = Preferences.Onscreen.showAppIcon.getPreference(prefs);
Android.toggleComponent(this, CalculatorOnscreenStartActivity.class, showAppIcon); Android.toggleComponent(this, CalculatorOnscreenStartActivity.class, showAppIcon);
Locator.getInstance().getNotifier().showMessage(R.string.cpp_this_change_may_require_reboot, MessageType.info); Locator.getInstance().getNotifier().showMessage(R.string.cpp_this_change_may_require_reboot, MessageType.info);
} }
} }
} }

View File

@ -9,48 +9,48 @@ import javax.annotation.Nullable;
public final class CalculatorBroadcaster implements CalculatorEventListener, SharedPreferences.OnSharedPreferenceChangeListener { public final class CalculatorBroadcaster implements CalculatorEventListener, SharedPreferences.OnSharedPreferenceChangeListener {
public static final String ACTION_INIT = "org.solovyev.android.calculator.INIT"; public static final String ACTION_INIT = "org.solovyev.android.calculator.INIT";
public static final String ACTION_EDITOR_STATE_CHANGED = "org.solovyev.android.calculator.EDITOR_STATE_CHANGED"; public static final String ACTION_EDITOR_STATE_CHANGED = "org.solovyev.android.calculator.EDITOR_STATE_CHANGED";
public static final String ACTION_DISPLAY_STATE_CHANGED = "org.solovyev.android.calculator.DISPLAY_STATE_CHANGED"; public static final String ACTION_DISPLAY_STATE_CHANGED = "org.solovyev.android.calculator.DISPLAY_STATE_CHANGED";
public static final String ACTION_THEME_CHANGED = "org.solovyev.android.calculator.THEME_CHANGED"; public static final String ACTION_THEME_CHANGED = "org.solovyev.android.calculator.THEME_CHANGED";
@Nonnull @Nonnull
private final Context context; private final Context context;
public CalculatorBroadcaster(@Nonnull Context context, @Nonnull SharedPreferences preferences) { public CalculatorBroadcaster(@Nonnull Context context, @Nonnull SharedPreferences preferences) {
this.context = context; this.context = context;
preferences.registerOnSharedPreferenceChangeListener(this); preferences.registerOnSharedPreferenceChangeListener(this);
} }
@Override @Override
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) { public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
switch (calculatorEventType) { switch (calculatorEventType) {
case editor_state_changed: case editor_state_changed:
case editor_state_changed_light: case editor_state_changed_light:
sendEditorStateChangedIntent(); sendEditorStateChangedIntent();
break; break;
case display_state_changed: case display_state_changed:
sendDisplayStateChanged(); sendDisplayStateChanged();
break; break;
} }
} }
public void sendDisplayStateChanged() { public void sendDisplayStateChanged() {
sendBroadcastIntent(ACTION_DISPLAY_STATE_CHANGED); sendBroadcastIntent(ACTION_DISPLAY_STATE_CHANGED);
} }
public void sendEditorStateChangedIntent() { public void sendEditorStateChangedIntent() {
sendBroadcastIntent(ACTION_EDITOR_STATE_CHANGED); sendBroadcastIntent(ACTION_EDITOR_STATE_CHANGED);
} }
public void sendBroadcastIntent(@Nonnull String action) { public void sendBroadcastIntent(@Nonnull String action) {
context.sendBroadcast(new Intent(action)); context.sendBroadcast(new Intent(action));
} }
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (Preferences.Gui.theme.isSameKey(key) || Preferences.Widget.theme.isSameKey(key)) { if (Preferences.Gui.theme.isSameKey(key) || Preferences.Widget.theme.isSameKey(key)) {
sendBroadcastIntent(ACTION_THEME_CHANGED); sendBroadcastIntent(ACTION_THEME_CHANGED);
} }
} }
} }

View File

@ -22,15 +22,19 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.content.Context;
import android.util.SparseArray; import android.util.SparseArray;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
import static org.solovyev.android.calculator.CalculatorSpecialButton.*; import static org.solovyev.android.calculator.CalculatorSpecialButton.cursor_left;
import static org.solovyev.android.calculator.CalculatorSpecialButton.cursor_right;
import static org.solovyev.android.calculator.CalculatorSpecialButton.functions_detached;
import static org.solovyev.android.calculator.CalculatorSpecialButton.history_detached;
import static org.solovyev.android.calculator.CalculatorSpecialButton.open_app;
import static org.solovyev.android.calculator.CalculatorSpecialButton.operators_detached;
import static org.solovyev.android.calculator.CalculatorSpecialButton.settings_detached;
import static org.solovyev.android.calculator.CalculatorSpecialButton.vars_detached;
/** /**
* User: serso * User: serso
@ -39,114 +43,111 @@ import static org.solovyev.android.calculator.CalculatorSpecialButton.*;
*/ */
public enum CalculatorButton { public enum CalculatorButton {
/*digits*/ /*digits*/
one(R.id.cpp_button_1, "1"), one(R.id.cpp_button_1, "1"),
two(R.id.cpp_button_2, "2"), two(R.id.cpp_button_2, "2"),
three(R.id.cpp_button_3, "3"), three(R.id.cpp_button_3, "3"),
four(R.id.cpp_button_4, "4"), four(R.id.cpp_button_4, "4"),
five(R.id.cpp_button_5, "5"), five(R.id.cpp_button_5, "5"),
six(R.id.cpp_button_6, "6"), six(R.id.cpp_button_6, "6"),
seven(R.id.cpp_button_7, "7"), seven(R.id.cpp_button_7, "7"),
eight(R.id.cpp_button_8, "8"), eight(R.id.cpp_button_8, "8"),
nine(R.id.cpp_button_9, "9"), nine(R.id.cpp_button_9, "9"),
zero(R.id.cpp_button_0, "0"), zero(R.id.cpp_button_0, "0"),
period(R.id.cpp_button_period, "."), period(R.id.cpp_button_period, "."),
brackets(R.id.cpp_button_round_brackets, "()"), brackets(R.id.cpp_button_round_brackets, "()"),
settings(R.id.cpp_button_settings, settings_detached), settings(R.id.cpp_button_settings, settings_detached),
like(R.id.cpp_button_like, CalculatorSpecialButton.like), like(R.id.cpp_button_like, CalculatorSpecialButton.like),
/*last row*/ /*last row*/
left(R.id.cpp_button_left, cursor_left), left(R.id.cpp_button_left, cursor_left),
right(R.id.cpp_button_right, cursor_right), right(R.id.cpp_button_right, cursor_right),
vars(R.id.cpp_button_vars, vars_detached), vars(R.id.cpp_button_vars, vars_detached),
functions(R.id.cpp_button_functions, functions_detached), functions(R.id.cpp_button_functions, functions_detached),
operators(R.id.cpp_button_operators, operators_detached), operators(R.id.cpp_button_operators, operators_detached),
app(R.id.cpp_button_app, open_app), app(R.id.cpp_button_app, open_app),
history(R.id.cpp_button_history, history_detached), history(R.id.cpp_button_history, history_detached),
/*operations*/ /*operations*/
multiplication(R.id.cpp_button_multiplication, "*"), multiplication(R.id.cpp_button_multiplication, "*"),
division(R.id.cpp_button_division, "/"), division(R.id.cpp_button_division, "/"),
plus(R.id.cpp_button_plus, "+"), plus(R.id.cpp_button_plus, "+"),
subtraction(R.id.cpp_button_subtraction, ""), subtraction(R.id.cpp_button_subtraction, ""),
percent(R.id.cpp_button_percent, "%"), percent(R.id.cpp_button_percent, "%"),
power(R.id.cpp_button_power, "^"), power(R.id.cpp_button_power, "^"),
/*last column*/ /*last column*/
clear(R.id.cpp_button_clear, CalculatorSpecialButton.clear), clear(R.id.cpp_button_clear, CalculatorSpecialButton.clear),
erase(R.id.cpp_button_erase, CalculatorSpecialButton.erase, CalculatorSpecialButton.clear), erase(R.id.cpp_button_erase, CalculatorSpecialButton.erase, CalculatorSpecialButton.clear),
copy(R.id.cpp_button_copy, CalculatorSpecialButton.copy), copy(R.id.cpp_button_copy, CalculatorSpecialButton.copy),
paste(R.id.cpp_button_paste, CalculatorSpecialButton.paste), paste(R.id.cpp_button_paste, CalculatorSpecialButton.paste),
/*equals*/ /*equals*/
equals(R.id.cpp_button_equals, CalculatorSpecialButton.equals); equals(R.id.cpp_button_equals, CalculatorSpecialButton.equals);
private final int buttonId; @Nonnull
private static SparseArray<CalculatorButton> buttonsByIds = new SparseArray<>();
private final int buttonId;
@Nonnull
private final String onClickText;
@Nullable
private final String onLongClickText;
@Nonnull CalculatorButton(int buttonId, @Nonnull CalculatorSpecialButton onClickButton, @Nullable CalculatorSpecialButton onLongClickButton) {
private final String onClickText; this(buttonId, onClickButton.getActionCode(), onLongClickButton == null ? null : onLongClickButton.getActionCode());
}
@Nullable CalculatorButton(int buttonId, @Nonnull CalculatorSpecialButton onClickButton) {
private final String onLongClickText; this(buttonId, onClickButton, null);
}
@Nonnull CalculatorButton(int buttonId, @Nonnull String onClickText, @Nullable String onLongClickText) {
private static SparseArray<CalculatorButton> buttonsByIds = new SparseArray<>(); this.buttonId = buttonId;
this.onClickText = onClickText;
this.onLongClickText = onLongClickText;
CalculatorButton(int buttonId, @Nonnull CalculatorSpecialButton onClickButton, @Nullable CalculatorSpecialButton onLongClickButton) { }
this(buttonId, onClickButton.getActionCode(), onLongClickButton == null ? null : onLongClickButton.getActionCode());
}
CalculatorButton(int buttonId, @Nonnull CalculatorSpecialButton onClickButton) { CalculatorButton(int buttonId, @Nonnull String onClickText) {
this(buttonId, onClickButton, null); this(buttonId, onClickText, null);
} }
CalculatorButton(int buttonId, @Nonnull String onClickText, @Nullable String onLongClickText) { @Nullable
this.buttonId = buttonId; public static CalculatorButton getById(int buttonId) {
this.onClickText = onClickText; initButtonsByIdsMap();
this.onLongClickText = onLongClickText;
} return buttonsByIds.get(buttonId);
}
CalculatorButton(int buttonId, @Nonnull String onClickText) { private static void initButtonsByIdsMap() {
this(buttonId, onClickText, null); if (buttonsByIds.size() == 0) {
} // if not initialized
public void onLongClick() { final CalculatorButton[] calculatorButtons = values();
if (onLongClickText != null) {
Locator.getInstance().getKeyboard().buttonPressed(onLongClickText);
}
}
public void onClick() { final SparseArray<CalculatorButton> localButtonsByIds = new SparseArray<>();
Locator.getInstance().getKeyboard().buttonPressed(onClickText); for (CalculatorButton calculatorButton : calculatorButtons) {
} localButtonsByIds.append(calculatorButton.getButtonId(), calculatorButton);
}
@Nullable buttonsByIds = localButtonsByIds;
public static CalculatorButton getById(int buttonId) { }
initButtonsByIdsMap(); }
return buttonsByIds.get(buttonId); public void onLongClick() {
} if (onLongClickText != null) {
Locator.getInstance().getKeyboard().buttonPressed(onLongClickText);
}
}
private static void initButtonsByIdsMap() { public void onClick() {
if (buttonsByIds.size() == 0) { Locator.getInstance().getKeyboard().buttonPressed(onClickText);
// if not initialized }
final CalculatorButton[] calculatorButtons = values(); public int getButtonId() {
return buttonId;
final SparseArray<CalculatorButton> localButtonsByIds = new SparseArray<>(); }
for (CalculatorButton calculatorButton : calculatorButtons) {
localButtonsByIds.append(calculatorButton.getButtonId(), calculatorButton);
}
buttonsByIds = localButtonsByIds;
}
}
public int getButtonId() {
return buttonId;
}
} }

View File

@ -33,22 +33,23 @@ import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.RemoteViews; import android.widget.RemoteViews;
import jscl.AngleUnit;
import jscl.NumeralBase;
import org.solovyev.android.Views; import org.solovyev.android.Views;
import org.solovyev.android.calculator.model.AndroidCalculatorEngine;
import org.solovyev.android.calculator.view.AngleUnitsButton;
import org.solovyev.android.calculator.view.NumeralBasesButton;
import org.solovyev.android.calculator.drag.DragButton; import org.solovyev.android.calculator.drag.DragButton;
import org.solovyev.android.calculator.drag.DragDirection; import org.solovyev.android.calculator.drag.DragDirection;
import org.solovyev.android.calculator.drag.SimpleDragListener; import org.solovyev.android.calculator.drag.SimpleDragListener;
import org.solovyev.android.calculator.model.AndroidCalculatorEngine;
import org.solovyev.android.calculator.view.AngleUnitsButton;
import org.solovyev.android.calculator.view.NumeralBasesButton;
import org.solovyev.android.calculator.view.ScreenMetrics; import org.solovyev.android.calculator.view.ScreenMetrics;
import org.solovyev.common.math.Point2d; import org.solovyev.common.math.Point2d;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import jscl.AngleUnit;
import jscl.NumeralBase;
/** /**
* User: serso * User: serso
* Date: 9/28/12 * Date: 9/28/12
@ -56,243 +57,243 @@ import javax.annotation.Nullable;
*/ */
public final class CalculatorButtons { public final class CalculatorButtons {
private CalculatorButtons() { private CalculatorButtons() {
} }
public static void fixButtonsTextSize(@Nonnull Preferences.Gui.Theme theme, public static void fixButtonsTextSize(@Nonnull Preferences.Gui.Theme theme,
@Nonnull Preferences.Gui.Layout layout, @Nonnull Preferences.Gui.Layout layout,
@Nonnull View root) { @Nonnull View root) {
if (!layout.isOptimized()) { if (!layout.isOptimized()) {
final ScreenMetrics metrics = App.getScreenMetrics(); final ScreenMetrics metrics = App.getScreenMetrics();
final boolean portrait = metrics.isInPortraitMode(); final boolean portrait = metrics.isInPortraitMode();
final int buttonsCount = portrait ? 5 : 4; final int buttonsCount = portrait ? 5 : 4;
final int buttonsWeight = portrait ? (2 + 1 + buttonsCount) : (2 + buttonsCount); final int buttonsWeight = portrait ? (2 + 1 + buttonsCount) : (2 + buttonsCount);
final int buttonSize = metrics.getHeightPxs() / buttonsWeight; final int buttonSize = metrics.getHeightPxs() / buttonsWeight;
final int textSize = 5 * buttonSize / 12; final int textSize = 5 * buttonSize / 12;
Views.processViewsOfType(root, DragButton.class, new Views.ViewProcessor<DragButton>() { Views.processViewsOfType(root, DragButton.class, new Views.ViewProcessor<DragButton>() {
@Override @Override
public void process(@Nonnull DragButton button) { public void process(@Nonnull DragButton button) {
button.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); button.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
} }
}); });
} }
} }
static void initMultiplicationButton(@Nonnull View root) { static void initMultiplicationButton(@Nonnull View root) {
final View multiplicationButton = root.findViewById(R.id.cpp_button_multiplication); final View multiplicationButton = root.findViewById(R.id.cpp_button_multiplication);
if (multiplicationButton instanceof Button) { if (multiplicationButton instanceof Button) {
((Button) multiplicationButton).setText(Locator.getInstance().getEngine().getMultiplicationSign()); ((Button) multiplicationButton).setText(Locator.getInstance().getEngine().getMultiplicationSign());
} }
} }
public static void initMultiplicationButton(@Nonnull RemoteViews views) { public static void initMultiplicationButton(@Nonnull RemoteViews views) {
views.setTextViewText(R.id.cpp_button_multiplication, Locator.getInstance().getEngine().getMultiplicationSign()); views.setTextViewText(R.id.cpp_button_multiplication, Locator.getInstance().getEngine().getMultiplicationSign());
} }
public static void toggleEqualsButton(@Nullable SharedPreferences preferences, public static void toggleEqualsButton(@Nullable SharedPreferences preferences,
@Nonnull Activity activity) { @Nonnull Activity activity) {
preferences = preferences == null ? PreferenceManager.getDefaultSharedPreferences(activity) : preferences; preferences = preferences == null ? PreferenceManager.getDefaultSharedPreferences(activity) : preferences;
final boolean large = App.isLargeScreen() && Preferences.Gui.getLayout(preferences).isOptimized(); final boolean large = App.isLargeScreen() && Preferences.Gui.getLayout(preferences).isOptimized();
if (!large) { if (!large) {
if (Views.getScreenOrientation(activity) == Configuration.ORIENTATION_PORTRAIT if (Views.getScreenOrientation(activity) == Configuration.ORIENTATION_PORTRAIT
|| !Preferences.Gui.autoOrientation.getPreference(preferences)) { || !Preferences.Gui.autoOrientation.getPreference(preferences)) {
final DragButton equalsButton = (DragButton) activity.findViewById(R.id.cpp_button_equals); final DragButton equalsButton = (DragButton) activity.findViewById(R.id.cpp_button_equals);
if (equalsButton != null) { if (equalsButton != null) {
if (Preferences.Gui.showEqualsButton.getPreference(preferences)) { if (Preferences.Gui.showEqualsButton.getPreference(preferences)) {
equalsButton.setVisibility(View.VISIBLE); equalsButton.setVisibility(View.VISIBLE);
} else { } else {
equalsButton.setVisibility(View.GONE); equalsButton.setVisibility(View.GONE);
} }
} }
} }
} }
} }
/* /*
********************************************************************** **********************************************************************
* *
* STATIC CLASSES * STATIC CLASSES
* *
********************************************************************** **********************************************************************
*/ */
static class RoundBracketsDragProcessor implements SimpleDragListener.DragProcessor { @Nonnull
private static CalculatorKeyboard getKeyboard() {
return Locator.getInstance().getKeyboard();
}
@Nonnull static class RoundBracketsDragProcessor implements SimpleDragListener.DragProcessor {
private final DigitButtonDragProcessor upDownProcessor = new DigitButtonDragProcessor(getKeyboard());
@Override @Nonnull
public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent) { private final DigitButtonDragProcessor upDownProcessor = new DigitButtonDragProcessor(getKeyboard());
final boolean result;
if (dragDirection == DragDirection.left) { @Override
App.getVibrator().vibrate(); public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent) {
getKeyboard().roundBracketsButtonPressed(); final boolean result;
result = true;
} else {
result = upDownProcessor.processDragEvent(dragDirection, dragButton, startPoint2d, motionEvent);
}
return result; if (dragDirection == DragDirection.left) {
} App.getVibrator().vibrate();
} getKeyboard().roundBracketsButtonPressed();
result = true;
} else {
result = upDownProcessor.processDragEvent(dragDirection, dragButton, startPoint2d, motionEvent);
}
@Nonnull return result;
private static CalculatorKeyboard getKeyboard() { }
return Locator.getInstance().getKeyboard(); }
}
static class VarsDragProcessor implements SimpleDragListener.DragProcessor { static class VarsDragProcessor implements SimpleDragListener.DragProcessor {
@Nonnull @Nonnull
private Context context; private Context context;
VarsDragProcessor(@Nonnull Context context) { VarsDragProcessor(@Nonnull Context context) {
this.context = context; this.context = context;
} }
@Override @Override
public boolean processDragEvent(@Nonnull DragDirection dragDirection, public boolean processDragEvent(@Nonnull DragDirection dragDirection,
@Nonnull DragButton dragButton, @Nonnull DragButton dragButton,
@Nonnull Point2d startPoint2d, @Nonnull Point2d startPoint2d,
@Nonnull MotionEvent motionEvent) { @Nonnull MotionEvent motionEvent) {
boolean result = false; boolean result = false;
if (dragDirection == DragDirection.up) { if (dragDirection == DragDirection.up) {
App.getVibrator().vibrate(); App.getVibrator().vibrate();
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_create_var_dialog, null, context); Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_create_var_dialog, null, context);
result = true; result = true;
}/* else if (dragDirection == DragDirection.down) { }/* else if (dragDirection == DragDirection.down) {
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_create_matrix_dialog, null, context); Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_create_matrix_dialog, null, context);
result = true; result = true;
}*/ }*/
return result; return result;
} }
} }
static class AngleUnitsChanger implements SimpleDragListener.DragProcessor { static class AngleUnitsChanger implements SimpleDragListener.DragProcessor {
@Nonnull @Nonnull
private final DigitButtonDragProcessor processor; private final DigitButtonDragProcessor processor;
@Nonnull @Nonnull
private final Context context; private final Context context;
AngleUnitsChanger(@Nonnull Context context) { AngleUnitsChanger(@Nonnull Context context) {
this.context = context; this.context = context;
this.processor = new DigitButtonDragProcessor(Locator.getInstance().getKeyboard()); this.processor = new DigitButtonDragProcessor(Locator.getInstance().getKeyboard());
} }
@Override @Override
public boolean processDragEvent(@Nonnull DragDirection dragDirection, public boolean processDragEvent(@Nonnull DragDirection dragDirection,
@Nonnull DragButton dragButton, @Nonnull DragButton dragButton,
@Nonnull Point2d startPoint2d, @Nonnull Point2d startPoint2d,
@Nonnull MotionEvent motionEvent) { @Nonnull MotionEvent motionEvent) {
boolean result = false; boolean result = false;
if (dragButton instanceof AngleUnitsButton) { if (dragButton instanceof AngleUnitsButton) {
if (dragDirection != DragDirection.left) { if (dragDirection != DragDirection.left) {
final String directionText = ((AngleUnitsButton) dragButton).getText(dragDirection); final String directionText = ((AngleUnitsButton) dragButton).getText(dragDirection);
if (directionText != null) { if (directionText != null) {
try { try {
final AngleUnit angleUnits = AngleUnit.valueOf(directionText); final AngleUnit angleUnits = AngleUnit.valueOf(directionText);
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
final AngleUnit oldAngleUnits = AndroidCalculatorEngine.Preferences.angleUnit.getPreference(preferences); final AngleUnit oldAngleUnits = AndroidCalculatorEngine.Preferences.angleUnit.getPreference(preferences);
if (oldAngleUnits != angleUnits) { if (oldAngleUnits != angleUnits) {
App.getVibrator().vibrate(); App.getVibrator().vibrate();
Locator.getInstance().getPreferenceService().setAngleUnits(angleUnits); Locator.getInstance().getPreferenceService().setAngleUnits(angleUnits);
} }
result = true; result = true;
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Log.d(this.getClass().getName(), "Unsupported angle units: " + directionText); Log.d(this.getClass().getName(), "Unsupported angle units: " + directionText);
} }
} }
} else if (dragDirection == DragDirection.left) { } else if (dragDirection == DragDirection.left) {
result = processor.processDragEvent(dragDirection, dragButton, startPoint2d, motionEvent); result = processor.processDragEvent(dragDirection, dragButton, startPoint2d, motionEvent);
} }
} }
return result; return result;
} }
} }
static class NumeralBasesChanger implements SimpleDragListener.DragProcessor { static class NumeralBasesChanger implements SimpleDragListener.DragProcessor {
@Nonnull @Nonnull
private final Context context; private final Context context;
NumeralBasesChanger(@Nonnull Context context) { NumeralBasesChanger(@Nonnull Context context) {
this.context = context; this.context = context;
} }
@Override @Override
public boolean processDragEvent(@Nonnull DragDirection dragDirection, public boolean processDragEvent(@Nonnull DragDirection dragDirection,
@Nonnull DragButton dragButton, @Nonnull DragButton dragButton,
@Nonnull Point2d startPoint2d, @Nonnull Point2d startPoint2d,
@Nonnull MotionEvent motionEvent) { @Nonnull MotionEvent motionEvent) {
boolean result = false; boolean result = false;
if (dragButton instanceof NumeralBasesButton) { if (dragButton instanceof NumeralBasesButton) {
final String directionText = ((NumeralBasesButton) dragButton).getText(dragDirection); final String directionText = ((NumeralBasesButton) dragButton).getText(dragDirection);
if (directionText != null) { if (directionText != null) {
try { try {
final NumeralBase numeralBase = NumeralBase.valueOf(directionText); final NumeralBase numeralBase = NumeralBase.valueOf(directionText);
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
final NumeralBase oldNumeralBase = AndroidCalculatorEngine.Preferences.numeralBase.getPreference(preferences); final NumeralBase oldNumeralBase = AndroidCalculatorEngine.Preferences.numeralBase.getPreference(preferences);
if (oldNumeralBase != numeralBase) { if (oldNumeralBase != numeralBase) {
App.getVibrator().vibrate(); App.getVibrator().vibrate();
Locator.getInstance().getPreferenceService().setNumeralBase(numeralBase); Locator.getInstance().getPreferenceService().setNumeralBase(numeralBase);
} }
result = true; result = true;
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Log.d(this.getClass().getName(), "Unsupported numeral base: " + directionText); Log.d(this.getClass().getName(), "Unsupported numeral base: " + directionText);
} }
} }
} }
return result; return result;
} }
} }
static class FunctionsDragProcessor implements SimpleDragListener.DragProcessor { static class FunctionsDragProcessor implements SimpleDragListener.DragProcessor {
@Nonnull @Nonnull
private Context context; private Context context;
FunctionsDragProcessor(@Nonnull Context context) { FunctionsDragProcessor(@Nonnull Context context) {
this.context = context; this.context = context;
} }
@Override @Override
public boolean processDragEvent(@Nonnull DragDirection dragDirection, public boolean processDragEvent(@Nonnull DragDirection dragDirection,
@Nonnull DragButton dragButton, @Nonnull DragButton dragButton,
@Nonnull Point2d startPoint2d, @Nonnull Point2d startPoint2d,
@Nonnull MotionEvent motionEvent) { @Nonnull MotionEvent motionEvent) {
boolean result = false; boolean result = false;
if (dragDirection == DragDirection.up) { if (dragDirection == DragDirection.up) {
App.getVibrator().vibrate(); App.getVibrator().vibrate();
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_create_function_dialog, null, context); Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_create_function_dialog, null, context);
result = true; result = true;
} }
return result; return result;
} }
} }
} }

View File

@ -26,21 +26,20 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcelable; import android.os.Parcelable;
import android.support.v7.app.ActionBarActivity;
import android.text.method.ScrollingMovementMethod; import android.text.method.ScrollingMovementMethod;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.TextView; import android.widget.TextView;
import android.support.v7.app.ActionBarActivity;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.solovyev.android.Android; import org.solovyev.android.Android;
import org.solovyev.android.fragments.FragmentUtils; import org.solovyev.android.fragments.FragmentUtils;
import org.solovyev.common.msg.MessageType; import org.solovyev.common.msg.MessageType;
import org.solovyev.common.text.Strings; import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* User: serso * User: serso
* Date: 1/20/13 * Date: 1/20/13
@ -48,106 +47,106 @@ import org.solovyev.common.text.Strings;
*/ */
public class CalculatorDialogActivity extends ActionBarActivity { public class CalculatorDialogActivity extends ActionBarActivity {
@Nonnull @Nonnull
private static final String TAG = CalculatorDialogActivity.class.getSimpleName(); private static final String TAG = CalculatorDialogActivity.class.getSimpleName();
@Nonnull @Nonnull
private static final String DIALOG_DATA_EXTRA = "dialog_data"; private static final String DIALOG_DATA_EXTRA = "dialog_data";
public static void showDialog(@Nonnull Context context, @Nonnull DialogData dialogData) { public static void showDialog(@Nonnull Context context, @Nonnull DialogData dialogData) {
final Intent intent = new Intent(); final Intent intent = new Intent();
intent.setClass(context, CalculatorDialogActivity.class); intent.setClass(context, CalculatorDialogActivity.class);
intent.putExtra(DIALOG_DATA_EXTRA, ParcelableDialogData.wrap(dialogData)); intent.putExtra(DIALOG_DATA_EXTRA, ParcelableDialogData.wrap(dialogData));
Android.addIntentFlags(intent, false, context); Android.addIntentFlags(intent, false, context);
context.startActivity(intent); context.startActivity(intent);
} }
@Override @Nullable
protected void onCreate(@Nullable Bundle in) { private static DialogData readDialogData(@Nullable Intent in) {
super.onCreate(in); if (in != null) {
final Parcelable parcelable = in.getParcelableExtra(DIALOG_DATA_EXTRA);
if (parcelable instanceof DialogData) {
return (DialogData) parcelable;
}
}
final DialogData dialogData = readDialogData(getIntent()); return null;
if (dialogData == null) { }
Locator.getInstance().getLogger().error(TAG, "Dialog data is null!");
this.finish();
} else {
setContentView(R.layout.cpp_dialog);
final String title = dialogData.getTitle(); @Nullable
if (!Strings.isEmpty(title)) { private static DialogData readDialogData(@Nullable Bundle in) {
setTitle(title); if (in != null) {
} final Parcelable parcelable = in.getParcelable(DIALOG_DATA_EXTRA);
if (parcelable instanceof DialogData) {
return (DialogData) parcelable;
}
}
return null;
}
@Override
protected void onCreate(@Nullable Bundle in) {
super.onCreate(in);
final DialogData dialogData = readDialogData(getIntent());
if (dialogData == null) {
Locator.getInstance().getLogger().error(TAG, "Dialog data is null!");
this.finish();
} else {
setContentView(R.layout.cpp_dialog);
final String title = dialogData.getTitle();
if (!Strings.isEmpty(title)) {
setTitle(title);
}
final Bundle args = new Bundle(); final Bundle args = new Bundle();
args.putParcelable(DIALOG_DATA_EXTRA, ParcelableDialogData.wrap(dialogData)); args.putParcelable(DIALOG_DATA_EXTRA, ParcelableDialogData.wrap(dialogData));
FragmentUtils.createFragment(this, CalculatorDialogFragment.class, R.id.dialog_layout, "dialog", args); FragmentUtils.createFragment(this, CalculatorDialogFragment.class, R.id.dialog_layout, "dialog", args);
} }
} }
@Nullable public static class CalculatorDialogFragment extends CalculatorFragment {
private static DialogData readDialogData(@Nullable Intent in) {
if (in != null) {
final Parcelable parcelable = in.getParcelableExtra(DIALOG_DATA_EXTRA);
if (parcelable instanceof DialogData) {
return (DialogData) parcelable;
}
}
return null; public CalculatorDialogFragment() {
} super(CalculatorFragmentType.dialog);
}
@Nullable @Override
private static DialogData readDialogData(@Nullable Bundle in) { public void onViewCreated(@Nonnull View root, Bundle savedInstanceState) {
if (in != null) { super.onViewCreated(root, savedInstanceState);
final Parcelable parcelable = in.getParcelable(DIALOG_DATA_EXTRA);
if (parcelable instanceof DialogData) {
return (DialogData) parcelable;
}
}
return null; final DialogData dialogData = readDialogData(getArguments());
}
public static class CalculatorDialogFragment extends CalculatorFragment { if (dialogData != null) {
final TextView messageTextView = (TextView) root.findViewById(R.id.cpp_dialog_message_textview);
messageTextView.setMovementMethod(ScrollingMovementMethod.getInstance());
messageTextView.setText(dialogData.getMessage());
public CalculatorDialogFragment() { if (dialogData.getMessageLevel() == MessageType.error || dialogData.getMessageLevel() == MessageType.warning) {
super(CalculatorFragmentType.dialog); final Button copyButton = (Button) root.findViewById(R.id.cpp_copy_button);
} copyButton.setVisibility(View.VISIBLE);
copyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Locator.getInstance().getClipboard().setText(dialogData.getMessage());
Locator.getInstance().getNotifier().showMessage(CalculatorMessage.newInfoMessage(CalculatorMessages.text_copied));
}
});
@Override }
public void onViewCreated(@Nonnull View root, Bundle savedInstanceState) { }
super.onViewCreated(root, savedInstanceState);
final DialogData dialogData = readDialogData(getArguments()); root.findViewById(R.id.cpp_ok_button).setOnClickListener(new View.OnClickListener() {
@Override
if (dialogData != null) { public void onClick(View v) {
final TextView messageTextView = (TextView) root.findViewById(R.id.cpp_dialog_message_textview); getActivity().finish();
messageTextView.setMovementMethod(ScrollingMovementMethod.getInstance()); }
messageTextView.setText(dialogData.getMessage()); });
}
if (dialogData.getMessageLevel() == MessageType.error || dialogData.getMessageLevel() == MessageType.warning) { }
final Button copyButton = (Button) root.findViewById(R.id.cpp_copy_button);
copyButton.setVisibility(View.VISIBLE);
copyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Locator.getInstance().getClipboard().setText(dialogData.getMessage());
Locator.getInstance().getNotifier().showMessage(CalculatorMessage.newInfoMessage(CalculatorMessages.text_copied));
}
});
}
}
root.findViewById(R.id.cpp_ok_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getActivity().finish();
}
});
}
}
} }

View File

@ -25,12 +25,11 @@ package org.solovyev.android.calculator;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.support.v4.app.Fragment;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
/** /**
@ -40,72 +39,72 @@ import javax.annotation.Nonnull;
*/ */
public class CalculatorDisplayFragment extends Fragment { public class CalculatorDisplayFragment extends Fragment {
@Nonnull @Nonnull
private FragmentUi fragmentUi; private FragmentUi fragmentUi;
@Nonnull @Nonnull
private AndroidCalculatorDisplayView displayView; private AndroidCalculatorDisplayView displayView;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this.getActivity()); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this.getActivity());
final Preferences.Gui.Layout layout = Preferences.Gui.getLayout(prefs); final Preferences.Gui.Layout layout = Preferences.Gui.getLayout(prefs);
if (!layout.isOptimized()) { if (!layout.isOptimized()) {
fragmentUi = CalculatorApplication.getInstance().createFragmentHelper(R.layout.cpp_app_display_mobile, R.string.result); fragmentUi = CalculatorApplication.getInstance().createFragmentHelper(R.layout.cpp_app_display_mobile, R.string.result);
} else { } else {
fragmentUi = CalculatorApplication.getInstance().createFragmentHelper(R.layout.cpp_app_display, R.string.result); fragmentUi = CalculatorApplication.getInstance().createFragmentHelper(R.layout.cpp_app_display, R.string.result);
} }
fragmentUi.onCreate(this); fragmentUi.onCreate(this);
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return fragmentUi.onCreateView(this, inflater, container); return fragmentUi.onCreateView(this, inflater, container);
} }
@Override @Override
public void onViewCreated(View root, Bundle savedInstanceState) { public void onViewCreated(View root, Bundle savedInstanceState) {
super.onViewCreated(root, savedInstanceState); super.onViewCreated(root, savedInstanceState);
displayView = (AndroidCalculatorDisplayView) root.findViewById(R.id.calculator_display); displayView = (AndroidCalculatorDisplayView) root.findViewById(R.id.calculator_display);
displayView.init(getActivity()); displayView.init(getActivity());
Locator.getInstance().getDisplay().setView(displayView); Locator.getInstance().getDisplay().setView(displayView);
fragmentUi.onViewCreated(this, root); fragmentUi.onViewCreated(this, root);
} }
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
} }
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
fragmentUi.onResume(this); fragmentUi.onResume(this);
} }
@Override @Override
public void onPause() { public void onPause() {
fragmentUi.onPause(this); fragmentUi.onPause(this);
super.onPause(); super.onPause();
} }
@Override @Override
public void onDestroyView() { public void onDestroyView() {
Locator.getInstance().getDisplay().clearView(displayView); Locator.getInstance().getDisplay().clearView(displayView);
fragmentUi.onDestroyView(this); fragmentUi.onDestroyView(this);
super.onDestroyView(); super.onDestroyView();
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
fragmentUi.onDestroy(this); fragmentUi.onDestroy(this);
super.onDestroy(); super.onDestroy();
} }
} }

View File

@ -23,7 +23,7 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.content.Context; import android.content.Context;
import jscl.math.Generic;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.plot.CalculatorPlotter; import org.solovyev.android.calculator.plot.CalculatorPlotter;
import org.solovyev.android.calculator.view.NumeralBaseConverterDialog; import org.solovyev.android.calculator.view.NumeralBaseConverterDialog;
@ -31,6 +31,8 @@ import org.solovyev.android.menu.LabeledMenuItem;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import jscl.math.Generic;
/** /**
* User: Solovyev_S * User: Solovyev_S
* Date: 21.09.12 * Date: 21.09.12
@ -38,99 +40,99 @@ import javax.annotation.Nonnull;
*/ */
public enum CalculatorDisplayMenuItem implements LabeledMenuItem<CalculatorDisplayViewState> { public enum CalculatorDisplayMenuItem implements LabeledMenuItem<CalculatorDisplayViewState> {
copy(R.string.c_copy) { copy(R.string.c_copy) {
@Override @Override
public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) { public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) {
Locator.getInstance().getKeyboard().copyButtonPressed(); Locator.getInstance().getKeyboard().copyButtonPressed();
} }
}, },
convert_to_bin(R.string.convert_to_bin) { convert_to_bin(R.string.convert_to_bin) {
@Override @Override
public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) { public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) {
ConversionMenuItem.convert_to_bin.onClick(data, context); ConversionMenuItem.convert_to_bin.onClick(data, context);
} }
@Override @Override
protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) { protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) {
return ConversionMenuItem.convert_to_bin.isItemVisibleFor(generic, operation); return ConversionMenuItem.convert_to_bin.isItemVisibleFor(generic, operation);
} }
}, },
convert_to_dec(R.string.convert_to_dec) { convert_to_dec(R.string.convert_to_dec) {
@Override @Override
public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) { public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) {
ConversionMenuItem.convert_to_dec.onClick(data, context); ConversionMenuItem.convert_to_dec.onClick(data, context);
} }
@Override @Override
protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) { protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) {
return ConversionMenuItem.convert_to_dec.isItemVisibleFor(generic, operation); return ConversionMenuItem.convert_to_dec.isItemVisibleFor(generic, operation);
} }
}, },
convert_to_hex(R.string.convert_to_hex) { convert_to_hex(R.string.convert_to_hex) {
@Override @Override
public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) { public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) {
ConversionMenuItem.convert_to_hex.onClick(data, context); ConversionMenuItem.convert_to_hex.onClick(data, context);
} }
@Override @Override
protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) { protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) {
return ConversionMenuItem.convert_to_hex.isItemVisibleFor(generic, operation); return ConversionMenuItem.convert_to_hex.isItemVisibleFor(generic, operation);
} }
}, },
convert(R.string.c_convert) { convert(R.string.c_convert) {
@Override @Override
public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) { public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) {
final Generic result = data.getResult(); final Generic result = data.getResult();
if (result != null) { if (result != null) {
new NumeralBaseConverterDialog(result.toString()).show(context); new NumeralBaseConverterDialog(result.toString()).show(context);
} }
} }
@Override @Override
protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) { protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) {
return operation == JsclOperation.numeric && generic.getConstants().isEmpty(); return operation == JsclOperation.numeric && generic.getConstants().isEmpty();
} }
}, },
plot(R.string.c_plot) { plot(R.string.c_plot) {
@Override @Override
public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) { public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) {
final Generic expression = data.getResult(); final Generic expression = data.getResult();
if (expression == null) throw new AssertionError(); if (expression == null) throw new AssertionError();
final CalculatorPlotter plotter = Locator.getInstance().getPlotter(); final CalculatorPlotter plotter = Locator.getInstance().getPlotter();
plotter.plot(expression); plotter.plot(expression);
} }
@Override @Override
protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) { protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) {
return Locator.getInstance().getPlotter().isPlotPossibleFor(generic); return Locator.getInstance().getPlotter().isPlotPossibleFor(generic);
} }
}; };
private final int captionId; private final int captionId;
CalculatorDisplayMenuItem(int captionId) { CalculatorDisplayMenuItem(int captionId) {
this.captionId = captionId; this.captionId = captionId;
} }
public final boolean isItemVisible(@Nonnull CalculatorDisplayViewState displayViewState) { public final boolean isItemVisible(@Nonnull CalculatorDisplayViewState displayViewState) {
//noinspection ConstantConditions //noinspection ConstantConditions
return displayViewState.isValid() && displayViewState.getResult() != null && isItemVisibleFor(displayViewState.getResult(), displayViewState.getOperation()); return displayViewState.isValid() && displayViewState.getResult() != null && isItemVisibleFor(displayViewState.getResult(), displayViewState.getOperation());
} }
protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) { protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) {
return true; return true;
} }
@Nonnull @Nonnull
@Override @Override
public String getCaption(@Nonnull Context context) { public String getCaption(@Nonnull Context context) {
return context.getString(captionId); return context.getString(captionId);
} }
} }

View File

@ -25,14 +25,14 @@ package org.solovyev.android.calculator;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import android.view.View; import android.view.View;
import javax.annotation.Nonnull;
import org.solovyev.android.menu.ContextMenuBuilder; import org.solovyev.android.menu.ContextMenuBuilder;
import org.solovyev.android.menu.ListContextMenu; import org.solovyev.android.menu.ListContextMenu;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
/** /**
* User: Solovyev_S * User: Solovyev_S
* Date: 21.09.12 * Date: 21.09.12
@ -40,38 +40,38 @@ import java.util.List;
*/ */
public class CalculatorDisplayOnClickListener implements View.OnClickListener { public class CalculatorDisplayOnClickListener implements View.OnClickListener {
@Nonnull @Nonnull
private final FragmentActivity activity; private final FragmentActivity activity;
public CalculatorDisplayOnClickListener(@Nonnull FragmentActivity activity) { public CalculatorDisplayOnClickListener(@Nonnull FragmentActivity activity) {
this.activity = activity; this.activity = activity;
} }
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (v instanceof CalculatorDisplayView) { if (v instanceof CalculatorDisplayView) {
final CalculatorDisplay cd = Locator.getInstance().getDisplay(); final CalculatorDisplay cd = Locator.getInstance().getDisplay();
final CalculatorDisplayViewState displayViewState = cd.getViewState(); final CalculatorDisplayViewState displayViewState = cd.getViewState();
if (displayViewState.isValid()) { if (displayViewState.isValid()) {
final List<CalculatorDisplayMenuItem> filteredMenuItems = new ArrayList<CalculatorDisplayMenuItem>(CalculatorDisplayMenuItem.values().length); final List<CalculatorDisplayMenuItem> filteredMenuItems = new ArrayList<CalculatorDisplayMenuItem>(CalculatorDisplayMenuItem.values().length);
for (CalculatorDisplayMenuItem menuItem : CalculatorDisplayMenuItem.values()) { for (CalculatorDisplayMenuItem menuItem : CalculatorDisplayMenuItem.values()) {
if (menuItem.isItemVisible(displayViewState)) { if (menuItem.isItemVisible(displayViewState)) {
filteredMenuItems.add(menuItem); filteredMenuItems.add(menuItem);
} }
} }
if (!filteredMenuItems.isEmpty()) { if (!filteredMenuItems.isEmpty()) {
ContextMenuBuilder.newInstance(activity, "display-menu", ListContextMenu.newInstance(filteredMenuItems)).build(displayViewState).show(); ContextMenuBuilder.newInstance(activity, "display-menu", ListContextMenu.newInstance(filteredMenuItems)).build(displayViewState).show();
} }
} else { } else {
final String errorMessage = displayViewState.getErrorMessage(); final String errorMessage = displayViewState.getErrorMessage();
if (errorMessage != null) { if (errorMessage != null) {
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_evaluation_error, errorMessage, activity); Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_evaluation_error, errorMessage, activity);
} }
} }
} }
} }
} }

View File

@ -27,7 +27,13 @@ import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.view.*; import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import org.solovyev.android.menu.ActivityMenu; import org.solovyev.android.menu.ActivityMenu;
import org.solovyev.android.menu.AndroidMenuHelper; import org.solovyev.android.menu.AndroidMenuHelper;
import org.solovyev.android.menu.ListActivityMenu; import org.solovyev.android.menu.ListActivityMenu;
@ -41,105 +47,105 @@ import javax.annotation.Nonnull;
*/ */
public class CalculatorEditorFragment extends Fragment { public class CalculatorEditorFragment extends Fragment {
@Nonnull @Nonnull
private FragmentUi fragmentUi; private FragmentUi fragmentUi;
@Nonnull @Nonnull
private ActivityMenu<Menu, MenuItem> menu = ListActivityMenu.fromEnum(CalculatorMenu.class, AndroidMenuHelper.getInstance()); private ActivityMenu<Menu, MenuItem> menu = ListActivityMenu.fromEnum(CalculatorMenu.class, AndroidMenuHelper.getInstance());
@Nonnull @Nonnull
private AndroidCalculatorEditorView editorView; private AndroidCalculatorEditorView editorView;
public CalculatorEditorFragment() { public CalculatorEditorFragment() {
} }
@Override @Override
public void onViewCreated(View view, Bundle savedInstanceState) { public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
fragmentUi.onViewCreated(this, view); fragmentUi.onViewCreated(this, view);
editorView = (AndroidCalculatorEditorView) view.findViewById(R.id.calculator_editor); editorView = (AndroidCalculatorEditorView) view.findViewById(R.id.calculator_editor);
editorView.init(); editorView.init();
Locator.getInstance().getEditor().setView(editorView); Locator.getInstance().getEditor().setView(editorView);
} }
@Override @Override
public void onAttach(Activity activity) { public void onAttach(Activity activity) {
super.onAttach(activity); super.onAttach(activity);
} }
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this.getActivity()); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this.getActivity());
final Preferences.Gui.Layout layout = Preferences.Gui.getLayout(prefs); final Preferences.Gui.Layout layout = Preferences.Gui.getLayout(prefs);
if (!layout.isOptimized()) { if (!layout.isOptimized()) {
fragmentUi = CalculatorApplication.getInstance().createFragmentHelper(R.layout.cpp_app_editor_mobile, R.string.editor); fragmentUi = CalculatorApplication.getInstance().createFragmentHelper(R.layout.cpp_app_editor_mobile, R.string.editor);
} else { } else {
fragmentUi = CalculatorApplication.getInstance().createFragmentHelper(R.layout.cpp_app_editor, R.string.editor); fragmentUi = CalculatorApplication.getInstance().createFragmentHelper(R.layout.cpp_app_editor, R.string.editor);
} }
fragmentUi.onCreate(this); fragmentUi.onCreate(this);
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return fragmentUi.onCreateView(this, inflater, container); return fragmentUi.onCreateView(this, inflater, container);
} }
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
this.fragmentUi.onResume(this); this.fragmentUi.onResume(this);
} }
@Override @Override
public void onPause() { public void onPause() {
this.fragmentUi.onPause(this); this.fragmentUi.onPause(this);
super.onPause(); super.onPause();
} }
@Override @Override
public void onDestroyView() { public void onDestroyView() {
Locator.getInstance().getEditor().clearView(editorView); Locator.getInstance().getEditor().clearView(editorView);
fragmentUi.onDestroyView(this); fragmentUi.onDestroyView(this);
super.onDestroyView(); super.onDestroyView();
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
fragmentUi.onDestroy(this); fragmentUi.onDestroy(this);
super.onDestroy(); super.onDestroy();
} }
@Override @Override
public void onDetach() { public void onDetach() {
super.onDetach(); super.onDetach();
} }
/* /*
********************************************************************** **********************************************************************
* *
* MENU * MENU
* *
********************************************************************** **********************************************************************
*/ */
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
this.menu.onCreateOptionsMenu(this.getActivity(), menu); this.menu.onCreateOptionsMenu(this.getActivity(), menu);
} }
@Override @Override
public void onPrepareOptionsMenu(Menu menu) { public void onPrepareOptionsMenu(Menu menu) {
this.menu.onPrepareOptionsMenu(this.getActivity(), menu); this.menu.onPrepareOptionsMenu(this.getActivity(), menu);
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
return this.menu.onOptionsItemSelected(this.getActivity(), item); return this.menu.onOptionsItemSelected(this.getActivity(), item);
} }
} }

View File

@ -24,12 +24,11 @@ package org.solovyev.android.calculator;
import android.app.Activity; import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.support.v4.app.Fragment;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
/** /**
@ -39,77 +38,77 @@ import javax.annotation.Nonnull;
*/ */
public abstract class CalculatorFragment extends Fragment { public abstract class CalculatorFragment extends Fragment {
@Nonnull @Nonnull
private final FragmentUi fragmentUi; private final FragmentUi fragmentUi;
protected CalculatorFragment(int layoutResId, int titleResId) { protected CalculatorFragment(int layoutResId, int titleResId) {
fragmentUi = CalculatorApplication.getInstance().createFragmentHelper(layoutResId, titleResId); fragmentUi = CalculatorApplication.getInstance().createFragmentHelper(layoutResId, titleResId);
} }
protected CalculatorFragment(@Nonnull CalculatorFragmentType fragmentType) { protected CalculatorFragment(@Nonnull CalculatorFragmentType fragmentType) {
fragmentUi = CalculatorApplication.getInstance().createFragmentHelper(fragmentType.getDefaultLayoutId(), fragmentType.getDefaultTitleResId()); fragmentUi = CalculatorApplication.getInstance().createFragmentHelper(fragmentType.getDefaultLayoutId(), fragmentType.getDefaultTitleResId());
} }
protected CalculatorFragment(@Nonnull FragmentUi fragmentUi) { protected CalculatorFragment(@Nonnull FragmentUi fragmentUi) {
this.fragmentUi = fragmentUi; this.fragmentUi = fragmentUi;
} }
@Override @Override
public void onAttach(Activity activity) { public void onAttach(Activity activity) {
super.onAttach(activity); super.onAttach(activity);
} }
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
fragmentUi.onCreate(this); fragmentUi.onCreate(this);
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return fragmentUi.onCreateView(this, inflater, container); return fragmentUi.onCreateView(this, inflater, container);
} }
@Override @Override
public void onViewCreated(View view, Bundle savedInstanceState) { public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
fragmentUi.onViewCreated(this, view); fragmentUi.onViewCreated(this, view);
} }
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
this.fragmentUi.onResume(this); this.fragmentUi.onResume(this);
} }
@Override @Override
public void onPause() { public void onPause() {
this.fragmentUi.onPause(this); this.fragmentUi.onPause(this);
super.onPause(); super.onPause();
} }
@Override @Override
public void onDestroyView() { public void onDestroyView() {
fragmentUi.onDestroyView(this); fragmentUi.onDestroyView(this);
super.onDestroyView(); super.onDestroyView();
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
fragmentUi.onDestroy(this); fragmentUi.onDestroy(this);
super.onDestroy(); super.onDestroy();
} }
@Override @Override
public void onDetach() { public void onDetach() {
super.onDetach(); super.onDetach();
} }
public boolean isPaneFragment() { public boolean isPaneFragment() {
return fragmentUi.isPane(this); return fragmentUi.isPane(this);
} }
} }

View File

@ -46,64 +46,62 @@ import javax.annotation.Nonnull;
*/ */
public enum CalculatorFragmentType { public enum CalculatorFragmentType {
editor(CalculatorEditorFragment.class, R.layout.cpp_app_editor, R.string.editor), editor(CalculatorEditorFragment.class, R.layout.cpp_app_editor, R.string.editor),
//display(CalculatorHistoryFragment.class, "history", R.layout.history_fragment, R.string.c_history), //display(CalculatorHistoryFragment.class, "history", R.layout.history_fragment, R.string.c_history),
//keyboard(CalculatorHistoryFragment.class, "history", R.layout.history_fragment, R.string.c_history), //keyboard(CalculatorHistoryFragment.class, "history", R.layout.history_fragment, R.string.c_history),
history(HistoryFragment.class, R.layout.history_fragment, R.string.c_history), history(HistoryFragment.class, R.layout.history_fragment, R.string.c_history),
saved_history(SavedHistoryFragment.class, R.layout.history_fragment, R.string.c_saved_history), saved_history(SavedHistoryFragment.class, R.layout.history_fragment, R.string.c_saved_history),
variables(CalculatorVarsFragment.class, R.layout.vars_fragment, R.string.c_vars), variables(CalculatorVarsFragment.class, R.layout.vars_fragment, R.string.c_vars),
functions(CalculatorFunctionsFragment.class, R.layout.math_entities_fragment, R.string.c_functions), functions(CalculatorFunctionsFragment.class, R.layout.math_entities_fragment, R.string.c_functions),
operators(CalculatorOperatorsFragment.class, R.layout.math_entities_fragment, R.string.c_operators), operators(CalculatorOperatorsFragment.class, R.layout.math_entities_fragment, R.string.c_operators),
plotter(PlotterFragment.class, R.layout.cpp_plotter_fragment, R.string.c_graph), plotter(PlotterFragment.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_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_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), plotter_range(CalculatorPlotRangeActivity.CalculatorPlotRangeFragment.class, R.layout.cpp_plot_range_fragment, R.string.cpp_plot_range),
purchase_dialog(CalculatorPlotRangeActivity.CalculatorPlotRangeFragment.class, R.layout.cpp_purchase_dialog_fragment, R.string.cpp_purchase_title), purchase_dialog(CalculatorPlotRangeActivity.CalculatorPlotRangeFragment.class, R.layout.cpp_purchase_dialog_fragment, R.string.cpp_purchase_title),
dialog(CalculatorDialogActivity.CalculatorDialogFragment.class, R.layout.cpp_dialog_fragment, R.string.cpp_message), dialog(CalculatorDialogActivity.CalculatorDialogFragment.class, R.layout.cpp_dialog_fragment, R.string.cpp_message),
about(CalculatorAboutFragment.class, R.layout.about_fragment, R.string.c_about), about(CalculatorAboutFragment.class, R.layout.about_fragment, R.string.c_about),
// todo serso: strings // todo serso: strings
matrix_edit(CalculatorMatrixEditFragment.class, R.layout.matrix_edit_fragment, R.string.c_release_notes), matrix_edit(CalculatorMatrixEditFragment.class, R.layout.matrix_edit_fragment, R.string.c_release_notes),
release_notes(CalculatorReleaseNotesFragment.class, R.layout.release_notes_fragment, R.string.c_release_notes); release_notes(CalculatorReleaseNotesFragment.class, R.layout.release_notes_fragment, R.string.c_release_notes);
@Nonnull private final int defaultLayoutId;
private Class<? extends Fragment> fragmentClass; @Nonnull
private Class<? extends Fragment> fragmentClass;
private int defaultTitleResId;
private final int defaultLayoutId; private CalculatorFragmentType(@Nonnull Class<? extends Fragment> fragmentClass,
int defaultLayoutId,
int defaultTitleResId) {
this.fragmentClass = fragmentClass;
this.defaultLayoutId = defaultLayoutId;
this.defaultTitleResId = defaultTitleResId;
}
private int defaultTitleResId; @Nonnull
public String getFragmentTag() {
return this.name();
}
private CalculatorFragmentType(@Nonnull Class<? extends Fragment> fragmentClass, public int getDefaultTitleResId() {
int defaultLayoutId, return defaultTitleResId;
int defaultTitleResId) { }
this.fragmentClass = fragmentClass;
this.defaultLayoutId = defaultLayoutId;
this.defaultTitleResId = defaultTitleResId;
}
@Nonnull @Nonnull
public String getFragmentTag() { public Class<? extends Fragment> getFragmentClass() {
return this.name(); return fragmentClass;
} }
public int getDefaultTitleResId() { public int getDefaultLayoutId() {
return defaultTitleResId; return defaultLayoutId;
} }
@Nonnull @Nonnull
public Class<? extends Fragment> getFragmentClass() { public String createSubFragmentTag(@Nonnull String subFragmentTag) {
return fragmentClass; return this.getFragmentTag() + "_" + subFragmentTag;
} }
public int getDefaultLayoutId() {
return defaultLayoutId;
}
@Nonnull
public String createSubFragmentTag(@Nonnull String subFragmentTag) {
return this.getFragmentTag() + "_" + subFragmentTag;
}
} }

View File

@ -24,10 +24,10 @@ package org.solovyev.android.calculator;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.support.v4.app.Fragment;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -44,82 +44,82 @@ import static org.solovyev.android.calculator.model.AndroidCalculatorEngine.Pref
*/ */
public class CalculatorKeyboardFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener { public class CalculatorKeyboardFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener {
@Nonnull @Nonnull
private FragmentUi ui; private FragmentUi ui;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
final SharedPreferences preferences = App.getPreferences(); final SharedPreferences preferences = App.getPreferences();
final Preferences.Gui.Layout layout = Preferences.Gui.getLayout(preferences); final Preferences.Gui.Layout layout = Preferences.Gui.getLayout(preferences);
if (!layout.isOptimized()) { if (!layout.isOptimized()) {
ui = CalculatorApplication.getInstance().createFragmentHelper(R.layout.cpp_app_keyboard_mobile); ui = CalculatorApplication.getInstance().createFragmentHelper(R.layout.cpp_app_keyboard_mobile);
} else { } else {
ui = CalculatorApplication.getInstance().createFragmentHelper(R.layout.cpp_app_keyboard); ui = CalculatorApplication.getInstance().createFragmentHelper(R.layout.cpp_app_keyboard);
} }
ui.onCreate(this); ui.onCreate(this);
preferences.registerOnSharedPreferenceChangeListener(this); preferences.registerOnSharedPreferenceChangeListener(this);
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return ui.onCreateView(this, inflater, container); return ui.onCreateView(this, inflater, container);
} }
@Override @Override
public void onViewCreated(View root, Bundle savedInstanceState) { public void onViewCreated(View root, Bundle savedInstanceState) {
super.onViewCreated(root, savedInstanceState); super.onViewCreated(root, savedInstanceState);
ui.onViewCreated(this, root); ui.onViewCreated(this, root);
} }
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
this.ui.onResume(this); this.ui.onResume(this);
} }
@Override @Override
public void onPause() { public void onPause() {
this.ui.onPause(this); this.ui.onPause(this);
super.onPause(); super.onPause();
} }
@Override @Override
public void onDestroyView() { public void onDestroyView() {
ui.onDestroyView(this); ui.onDestroyView(this);
super.onDestroyView(); super.onDestroyView();
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
ui.onDestroy(this); ui.onDestroy(this);
App.getPreferences().unregisterOnSharedPreferenceChangeListener(this); App.getPreferences().unregisterOnSharedPreferenceChangeListener(this);
} }
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
} }
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (numeralBase.isSameKey(key) || hideNumeralBaseDigits.isSameKey(key)) { if (numeralBase.isSameKey(key) || hideNumeralBaseDigits.isSameKey(key)) {
toggleNumericDigits(this.getActivity(), preferences); toggleNumericDigits(this.getActivity(), preferences);
} }
if (showEqualsButton.isSameKey(key)) { if (showEqualsButton.isSameKey(key)) {
CalculatorButtons.toggleEqualsButton(preferences, this.getActivity()); CalculatorButtons.toggleEqualsButton(preferences, this.getActivity());
} }
if (multiplicationSign.isSameKey(key)) { if (multiplicationSign.isSameKey(key)) {
CalculatorButtons.initMultiplicationButton(getView()); CalculatorButtons.initMultiplicationButton(getView());
} }
} }
} }

View File

@ -24,12 +24,11 @@ package org.solovyev.android.calculator;
import android.app.Activity; import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.support.v4.app.ListFragment;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
/** /**
@ -39,72 +38,72 @@ import javax.annotation.Nonnull;
*/ */
public abstract class CalculatorListFragment extends ListFragment { public abstract class CalculatorListFragment extends ListFragment {
@Nonnull @Nonnull
private final FragmentUi ui; private final FragmentUi ui;
protected CalculatorListFragment(int layoutResId, int titleResId) { protected CalculatorListFragment(int layoutResId, int titleResId) {
ui = CalculatorApplication.getInstance().createFragmentHelper(layoutResId, titleResId); ui = CalculatorApplication.getInstance().createFragmentHelper(layoutResId, titleResId);
} }
protected CalculatorListFragment(@Nonnull CalculatorFragmentType fragmentType) { protected CalculatorListFragment(@Nonnull CalculatorFragmentType fragmentType) {
ui = CalculatorApplication.getInstance().createFragmentHelper(fragmentType.getDefaultLayoutId(), fragmentType.getDefaultTitleResId()); ui = CalculatorApplication.getInstance().createFragmentHelper(fragmentType.getDefaultLayoutId(), fragmentType.getDefaultTitleResId());
} }
protected CalculatorListFragment(@Nonnull FragmentUi ui) { protected CalculatorListFragment(@Nonnull FragmentUi ui) {
this.ui = ui; this.ui = ui;
} }
@Override @Override
public void onAttach(Activity activity) { public void onAttach(Activity activity) {
super.onAttach(activity); super.onAttach(activity);
} }
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
ui.onCreate(this); ui.onCreate(this);
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return ui.onCreateView(this, inflater, container); return ui.onCreateView(this, inflater, container);
} }
@Override @Override
public void onViewCreated(View view, Bundle savedInstanceState) { public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
ui.onViewCreated(this, view); ui.onViewCreated(this, view);
} }
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
this.ui.onResume(this); this.ui.onResume(this);
} }
@Override @Override
public void onPause() { public void onPause() {
this.ui.onPause(this); this.ui.onPause(this);
super.onPause(); super.onPause();
} }
@Override @Override
public void onDestroyView() { public void onDestroyView() {
ui.onDestroyView(this); ui.onDestroyView(this);
super.onDestroyView(); super.onDestroyView();
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
ui.onDestroy(this); ui.onDestroy(this);
super.onDestroy(); super.onDestroy();
} }
@Override @Override
public void onDetach() { public void onDetach() {
super.onDetach(); super.onDetach();
} }
} }

View File

@ -25,14 +25,13 @@ package org.solovyev.android.calculator;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
import android.view.MenuItem; import android.view.MenuItem;
import javax.annotation.Nonnull;
import org.solovyev.android.calculator.view.NumeralBaseConverterDialog; import org.solovyev.android.calculator.view.NumeralBaseConverterDialog;
import org.solovyev.android.menu.LabeledMenuItem; import org.solovyev.android.menu.LabeledMenuItem;
import javax.annotation.Nonnull;
/** /**
* User: serso * User: serso
* Date: 4/23/12 * Date: 4/23/12
@ -40,61 +39,61 @@ import org.solovyev.android.menu.LabeledMenuItem;
*/ */
enum CalculatorMenu implements LabeledMenuItem<MenuItem> { enum CalculatorMenu implements LabeledMenuItem<MenuItem> {
settings(R.string.c_settings) { settings(R.string.c_settings) {
@Override @Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) { public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
CalculatorActivityLauncher.showSettings(context); CalculatorActivityLauncher.showSettings(context);
} }
}, },
history(R.string.c_history) { history(R.string.c_history) {
@Override @Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) { public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
CalculatorActivityLauncher.showHistory(context); CalculatorActivityLauncher.showHistory(context);
} }
}, },
plotter(R.string.cpp_plotter) { plotter(R.string.cpp_plotter) {
@Override @Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) { public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
Locator.getInstance().getPlotter().plot(); Locator.getInstance().getPlotter().plot();
} }
}, },
conversion_tool(R.string.c_conversion_tool) { conversion_tool(R.string.c_conversion_tool) {
@Override @Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) { public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
new NumeralBaseConverterDialog(null).show(context); new NumeralBaseConverterDialog(null).show(context);
} }
}, },
exit(R.string.c_exit) { exit(R.string.c_exit) {
@Override @Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) { public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
if (context instanceof Activity) { if (context instanceof Activity) {
((Activity) context).finish(); ((Activity) context).finish();
} else { } else {
Log.e(CalculatorActivity.TAG, "Activity menu used with context"); Log.e(CalculatorActivity.TAG, "Activity menu used with context");
} }
} }
}, },
about(R.string.c_about) { about(R.string.c_about) {
@Override @Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) { public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
CalculatorActivityLauncher.showAbout(context); CalculatorActivityLauncher.showAbout(context);
} }
}; };
private final int captionResId; private final int captionResId;
private CalculatorMenu(int captionResId) { private CalculatorMenu(int captionResId) {
this.captionResId = captionResId; this.captionResId = captionResId;
} }
@Nonnull @Nonnull
@Override @Override
public String getCaption(@Nonnull Context context) { public String getCaption(@Nonnull Context context) {
return context.getString(captionResId); return context.getString(captionResId);
} }
} }

View File

@ -8,28 +8,28 @@ import javax.annotation.Nonnull;
public final class CalculatorReceiver extends BroadcastReceiver { public final class CalculatorReceiver extends BroadcastReceiver {
public static final String ACTION_BUTTON_ID_EXTRA = "buttonId"; public static final String ACTION_BUTTON_ID_EXTRA = "buttonId";
public static final String ACTION_BUTTON_PRESSED = "org.solovyev.android.calculator.BUTTON_PRESSED"; public static final String ACTION_BUTTON_PRESSED = "org.solovyev.android.calculator.BUTTON_PRESSED";
@Override @Nonnull
public void onReceive(Context context, Intent intent) { public static Intent newButtonClickedIntent(@Nonnull Context context, @Nonnull CalculatorButton button) {
final String action = intent.getAction(); final Intent intent = new Intent(context, CalculatorReceiver.class);
intent.setAction(ACTION_BUTTON_PRESSED);
intent.putExtra(ACTION_BUTTON_ID_EXTRA, button.getButtonId());
return intent;
}
if (ACTION_BUTTON_PRESSED.equals(action)) { @Override
final int buttonId = intent.getIntExtra(ACTION_BUTTON_ID_EXTRA, 0); public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
final CalculatorButton button = CalculatorButton.getById(buttonId); if (ACTION_BUTTON_PRESSED.equals(action)) {
if (button != null) { final int buttonId = intent.getIntExtra(ACTION_BUTTON_ID_EXTRA, 0);
button.onClick();
}
}
}
@Nonnull final CalculatorButton button = CalculatorButton.getById(buttonId);
public static Intent newButtonClickedIntent(@Nonnull Context context, @Nonnull CalculatorButton button) { if (button != null) {
final Intent intent = new Intent(context, CalculatorReceiver.class); button.onClick();
intent.setAction(ACTION_BUTTON_PRESSED); }
intent.putExtra(ACTION_BUTTON_ID_EXTRA, button.getButtonId()); }
return intent; }
}
} }

View File

@ -31,21 +31,21 @@ import javax.annotation.Nonnull;
*/ */
public final class CalculatorSecurity { public final class CalculatorSecurity {
private CalculatorSecurity() { private CalculatorSecurity() {
} }
@Nonnull @Nonnull
public static String getPK() { public static String getPK() {
final StringBuilder result = new StringBuilder(); final StringBuilder result = new StringBuilder();
result.append("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A"); result.append("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A");
result.append("MIIBCgKCAQEAquP2a7dEhTaJEQeXtSyreH5dCmTDOd"); result.append("MIIBCgKCAQEAquP2a7dEhTaJEQeXtSyreH5dCmTDOd");
result.append("dElCfg0ijOeB8JTxBiJTXLWnLA0kMaT/sRXswUaYI61YCQOoik82"); result.append("dElCfg0ijOeB8JTxBiJTXLWnLA0kMaT/sRXswUaYI61YCQOoik82");
result.append("qrFH7W4+OFtiLb8WGX+YPEpQQ/IBZu9qm3xzS9Nolu79EBff0/CLa1FuT9RtjO"); result.append("qrFH7W4+OFtiLb8WGX+YPEpQQ/IBZu9qm3xzS9Nolu79EBff0/CLa1FuT9RtjO");
result.append("iTW8Q0VP9meQdJEkfqJEyVCgHain+MGoQaRXI45EzkYmkz8TBx6X6aJF5NBAXnAWeyD0wPX1"); result.append("iTW8Q0VP9meQdJEkfqJEyVCgHain+MGoQaRXI45EzkYmkz8TBx6X6aJF5NBAXnAWeyD0wPX1");
result.append("uedHH7+LgLcjnPVw82YjyJSzYnaaD2GX0Y7PGoFe6J5K4yJGGX5mih45pe2HWcG5lAkQhu1uX2hCcCBdF3"); result.append("uedHH7+LgLcjnPVw82YjyJSzYnaaD2GX0Y7PGoFe6J5K4yJGGX5mih45pe2HWcG5lAkQhu1uX2hCcCBdF3");
result.append("W7paRq9mJvCsbn+BNTh9gq8QKui0ltmiWpa5U+/9L+FQIDAQAB"); result.append("W7paRq9mJvCsbn+BNTh9gq8QKui0ltmiWpa5U+/9L+FQIDAQAB");
return result.toString(); return result.toString();
} }
} }

View File

@ -22,11 +22,11 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import org.solovyev.common.JPredicate;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.solovyev.common.JPredicate;
/** /**
* User: serso * User: serso
* Date: 10/3/11 * Date: 10/3/11
@ -34,22 +34,21 @@ import org.solovyev.common.JPredicate;
*/ */
public class CharacterAtPositionFinder implements JPredicate<Character> { public class CharacterAtPositionFinder implements JPredicate<Character> {
private int i; @Nonnull
private final String targetString;
private int i;
@Nonnull public CharacterAtPositionFinder(@Nonnull String targetString, int i) {
private final String targetString; this.targetString = targetString;
this.i = i;
}
public CharacterAtPositionFinder(@Nonnull String targetString, int i) { @Override
this.targetString = targetString; public boolean apply(@Nullable Character s) {
this.i = i; return s != null && s.equals(targetString.charAt(i));
} }
@Override public void setI(int i) {
public boolean apply(@Nullable Character s) { this.i = i;
return s != null && s.equals(targetString.charAt(i)); }
}
public void setI(int i) {
this.i = i;
}
} }

View File

@ -23,14 +23,15 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.content.Context; import android.content.Context;
import jscl.NumeralBase;
import jscl.math.Generic;
import javax.annotation.Nonnull;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.menu.AMenuItem; import org.solovyev.android.menu.AMenuItem;
import javax.annotation.Nonnull;
import jscl.NumeralBase;
import jscl.math.Generic;
/** /**
* User: serso * User: serso
* Date: 9/21/12 * Date: 9/21/12
@ -38,39 +39,39 @@ import org.solovyev.android.menu.AMenuItem;
*/ */
enum ConversionMenuItem implements AMenuItem<CalculatorDisplayViewState> { enum ConversionMenuItem implements AMenuItem<CalculatorDisplayViewState> {
convert_to_bin(NumeralBase.bin), convert_to_bin(NumeralBase.bin),
convert_to_dec(NumeralBase.dec), convert_to_dec(NumeralBase.dec),
convert_to_hex(NumeralBase.hex); convert_to_hex(NumeralBase.hex);
@Nonnull @Nonnull
private final NumeralBase toNumeralBase; private final NumeralBase toNumeralBase;
ConversionMenuItem(@Nonnull NumeralBase toNumeralBase) { ConversionMenuItem(@Nonnull NumeralBase toNumeralBase) {
this.toNumeralBase = toNumeralBase; this.toNumeralBase = toNumeralBase;
} }
protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) { protected boolean isItemVisibleFor(@Nonnull Generic generic, @Nonnull JsclOperation operation) {
boolean result = false; boolean result = false;
if (operation == JsclOperation.numeric) { if (operation == JsclOperation.numeric) {
if (generic.getConstants().isEmpty()) { if (generic.getConstants().isEmpty()) {
// conversion possible => return true // conversion possible => return true
final NumeralBase fromNumeralBase = Locator.getInstance().getEngine().getNumeralBase(); final NumeralBase fromNumeralBase = Locator.getInstance().getEngine().getNumeralBase();
if (fromNumeralBase != toNumeralBase) { if (fromNumeralBase != toNumeralBase) {
result = Locator.getInstance().getCalculator().isConversionPossible(generic, fromNumeralBase, this.toNumeralBase); result = Locator.getInstance().getCalculator().isConversionPossible(generic, fromNumeralBase, this.toNumeralBase);
} }
} }
} }
return result; return result;
} }
@Override @Override
public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) { public void onClick(@Nonnull CalculatorDisplayViewState data, @Nonnull Context context) {
final Generic result = data.getResult(); final Generic result = data.getResult();
if (result != null) { if (result != null) {
Locator.getInstance().getCalculator().convert(result, this.toNumeralBase); Locator.getInstance().getCalculator().convert(result, this.toNumeralBase);
} }
} }
} }

View File

@ -23,6 +23,7 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.view.MotionEvent; import android.view.MotionEvent;
import org.solovyev.android.calculator.drag.DirectionDragButton; import org.solovyev.android.calculator.drag.DirectionDragButton;
import org.solovyev.android.calculator.drag.DragButton; import org.solovyev.android.calculator.drag.DragButton;
import org.solovyev.android.calculator.drag.DragDirection; import org.solovyev.android.calculator.drag.DragDirection;
@ -38,26 +39,26 @@ import javax.annotation.Nonnull;
*/ */
public class CursorDragProcessor implements SimpleDragListener.DragProcessor { public class CursorDragProcessor implements SimpleDragListener.DragProcessor {
public CursorDragProcessor() { public CursorDragProcessor() {
} }
@Override @Override
public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent) { public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent) {
boolean result = false; boolean result = false;
if (dragButton instanceof DirectionDragButton) { if (dragButton instanceof DirectionDragButton) {
String text = ((DirectionDragButton) dragButton).getText(dragDirection); String text = ((DirectionDragButton) dragButton).getText(dragDirection);
if ("◁◁".equals(text)) { if ("◁◁".equals(text)) {
App.getVibrator().vibrate(); App.getVibrator().vibrate();
Locator.getInstance().getEditor().setCursorOnStart(); Locator.getInstance().getEditor().setCursorOnStart();
result = true; result = true;
} else if ("▷▷".equals(text)) { } else if ("▷▷".equals(text)) {
App.getVibrator().vibrate(); App.getVibrator().vibrate();
Locator.getInstance().getEditor().setCursorOnEnd(); Locator.getInstance().getEditor().setCursorOnEnd();
result = true; result = true;
} }
} }
return result; return result;
} }
} }

View File

@ -23,6 +23,7 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.view.MotionEvent; import android.view.MotionEvent;
import org.solovyev.android.calculator.drag.DirectionDragButton; import org.solovyev.android.calculator.drag.DirectionDragButton;
import org.solovyev.android.calculator.drag.DragButton; import org.solovyev.android.calculator.drag.DragButton;
import org.solovyev.android.calculator.drag.DragDirection; import org.solovyev.android.calculator.drag.DragDirection;
@ -38,19 +39,19 @@ import javax.annotation.Nonnull;
*/ */
public class DigitButtonDragProcessor implements SimpleDragListener.DragProcessor { public class DigitButtonDragProcessor implements SimpleDragListener.DragProcessor {
@Nonnull @Nonnull
private CalculatorKeyboard calculatorKeyboard; private CalculatorKeyboard calculatorKeyboard;
public DigitButtonDragProcessor(@Nonnull CalculatorKeyboard calculatorKeyboard) { public DigitButtonDragProcessor(@Nonnull CalculatorKeyboard calculatorKeyboard) {
this.calculatorKeyboard = calculatorKeyboard; this.calculatorKeyboard = calculatorKeyboard;
} }
@Override @Override
public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent) { public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent) {
if (!(dragButton instanceof DirectionDragButton)) throw new AssertionError(); if (!(dragButton instanceof DirectionDragButton)) throw new AssertionError();
final String text = ((DirectionDragButton) dragButton).getText(dragDirection); final String text = ((DirectionDragButton) dragButton).getText(dragDirection);
calculatorKeyboard.buttonPressed(text); calculatorKeyboard.buttonPressed(text);
return true; return true;
} }
} }

View File

@ -24,11 +24,11 @@ package org.solovyev.android.calculator;
public abstract class EmptyActivity extends BaseActivity { public abstract class EmptyActivity extends BaseActivity {
protected EmptyActivity() { protected EmptyActivity() {
this(R.layout.main_empty); this(R.layout.main_empty);
} }
protected EmptyActivity(int layoutResId) { protected EmptyActivity(int layoutResId) {
super(layoutResId); super(layoutResId);
} }
} }

View File

@ -24,14 +24,14 @@ package org.solovyev.android.calculator;
import android.view.MotionEvent; import android.view.MotionEvent;
import javax.annotation.Nonnull;
import org.solovyev.android.calculator.drag.DirectionDragButton; import org.solovyev.android.calculator.drag.DirectionDragButton;
import org.solovyev.android.calculator.drag.DragButton; import org.solovyev.android.calculator.drag.DragButton;
import org.solovyev.android.calculator.drag.DragDirection; import org.solovyev.android.calculator.drag.DragDirection;
import org.solovyev.android.calculator.drag.SimpleDragListener; import org.solovyev.android.calculator.drag.SimpleDragListener;
import org.solovyev.common.math.Point2d; import org.solovyev.common.math.Point2d;
import javax.annotation.Nonnull;
/** /**
* User: serso * User: serso
* Date: 10/24/11 * Date: 10/24/11
@ -39,28 +39,28 @@ import org.solovyev.common.math.Point2d;
*/ */
public class EqualsDragProcessor implements SimpleDragListener.DragProcessor { public class EqualsDragProcessor implements SimpleDragListener.DragProcessor {
public EqualsDragProcessor() { public EqualsDragProcessor() {
} }
@Override @Override
public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent) { public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent) {
boolean result = false; boolean result = false;
if (dragButton instanceof DirectionDragButton) { if (dragButton instanceof DirectionDragButton) {
if (dragDirection == DragDirection.down) { if (dragDirection == DragDirection.down) {
App.getVibrator().vibrate(); App.getVibrator().vibrate();
CalculatorActivityLauncher.tryPlot(); CalculatorActivityLauncher.tryPlot();
result = true; result = true;
} else { } else {
final String text = ((DirectionDragButton) dragButton).getText(dragDirection); final String text = ((DirectionDragButton) dragButton).getText(dragDirection);
if ("".equals(text)) { if ("".equals(text)) {
App.getVibrator().vibrate(); App.getVibrator().vibrate();
Locator.getInstance().getCalculator().simplify(); Locator.getInstance().getCalculator().simplify();
result = true; result = true;
} }
} }
} }
return result; return result;
} }
} }

View File

@ -24,6 +24,7 @@ package org.solovyev.android.calculator;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import org.solovyev.common.msg.Message; import org.solovyev.common.msg.Message;
import org.solovyev.common.msg.MessageType; import org.solovyev.common.msg.MessageType;
@ -37,75 +38,72 @@ import javax.annotation.Nullable;
*/ */
public class FixableMessage implements Parcelable { public class FixableMessage implements Parcelable {
public static final Creator<FixableMessage> CREATOR = new Creator<FixableMessage>() { public static final Creator<FixableMessage> CREATOR = new Creator<FixableMessage>() {
@Override @Override
public FixableMessage createFromParcel(@Nonnull Parcel in) { public FixableMessage createFromParcel(@Nonnull Parcel in) {
return FixableMessage.fromParcel(in); return FixableMessage.fromParcel(in);
} }
@Override @Override
public FixableMessage[] newArray(int size) { public FixableMessage[] newArray(int size) {
return new FixableMessage[size]; return new FixableMessage[size];
} }
}; };
@Nonnull
private final String message;
@Nonnull
private final MessageType messageType;
@Nullable
private final FixableError fixableError;
@Nonnull public FixableMessage(@Nonnull Message message) {
private static FixableMessage fromParcel(@Nonnull Parcel in) { this.message = message.getLocalizedMessage();
final String message = in.readString(); final int messageLevel = message.getMessageLevel().getMessageLevel();
final MessageType messageType = (MessageType) in.readSerializable(); this.messageType = CalculatorMessages.toMessageType(messageLevel);
final FixableError fixableError = (FixableError) in.readSerializable(); this.fixableError = CalculatorFixableError.getErrorByMessageCode(message.getMessageCode());
}
return new FixableMessage(message, messageType, fixableError); public FixableMessage(@Nonnull String message,
} @Nonnull MessageType messageType,
@Nullable FixableError fixableError) {
this.message = message;
this.messageType = messageType;
this.fixableError = fixableError;
}
@Nonnull @Nonnull
private final String message; private static FixableMessage fromParcel(@Nonnull Parcel in) {
final String message = in.readString();
final MessageType messageType = (MessageType) in.readSerializable();
final FixableError fixableError = (FixableError) in.readSerializable();
@Nonnull return new FixableMessage(message, messageType, fixableError);
private final MessageType messageType; }
@Nullable @Override
private final FixableError fixableError; public int describeContents() {
return 0;
}
public FixableMessage(@Nonnull Message message) { @Override
this.message = message.getLocalizedMessage(); public void writeToParcel(@Nonnull Parcel out, int flags) {
final int messageLevel = message.getMessageLevel().getMessageLevel(); out.writeString(message);
this.messageType = CalculatorMessages.toMessageType(messageLevel); out.writeSerializable(messageType);
this.fixableError = CalculatorFixableError.getErrorByMessageCode(message.getMessageCode()); out.writeSerializable(fixableError);
} }
public FixableMessage(@Nonnull String message, @Nonnull
@Nonnull MessageType messageType, public String getMessage() {
@Nullable FixableError fixableError) { return message;
this.message = message; }
this.messageType = messageType;
this.fixableError = fixableError;
}
@Override @Nonnull
public int describeContents() { public MessageType getMessageType() {
return 0; return messageType;
} }
@Override @Nullable
public void writeToParcel(@Nonnull Parcel out, int flags) { public FixableError getFixableError() {
out.writeString(message); return fixableError;
out.writeSerializable(messageType); }
out.writeSerializable(fixableError);
}
@Nonnull
public String getMessage() {
return message;
}
@Nonnull
public MessageType getMessageType() {
return messageType;
}
@Nullable
public FixableError getFixableError() {
return fixableError;
}
} }

View File

@ -36,14 +36,16 @@ import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.TextView; import android.widget.TextView;
import org.solovyev.common.msg.Message; import org.solovyev.common.msg.Message;
import org.solovyev.common.text.Strings; import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
/** /**
* User: serso * User: serso
* Date: 11/17/12 * Date: 11/17/12
@ -51,226 +53,223 @@ import java.util.List;
*/ */
public class FixableMessagesDialog extends ActionBarActivity { public class FixableMessagesDialog extends ActionBarActivity {
private static final String INPUT = "input"; private static final String INPUT = "input";
@Nonnull @Nonnull
private Input input = new Input(Collections.<FixableMessage>emptyList(), false); private Input input = new Input(Collections.<FixableMessage>emptyList(), false);
public FixableMessagesDialog() { public FixableMessagesDialog() {
} }
@Override public static void showDialogForMessages(@Nonnull List<Message> messages,
protected void onCreate(Bundle savedInstanceState) { @Nonnull Context context,
super.onCreate(savedInstanceState); boolean showCheckbox) {
if (!messages.isEmpty()) {
final Intent intent = new Intent(context, FixableMessagesDialog.class);
setContentView(R.layout.cpp_fixable_messages_dialog); intent.putExtra(INPUT, Input.fromMessages(messages, showCheckbox));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
final Intent intent = getIntent(); context.startActivity(intent);
if (intent != null) { }
parseIntent(intent); }
}
final CheckBox doNotShowCalculationMessagesCheckbox = (CheckBox) findViewById(R.id.cpp_do_not_show_fixable_messages_checkbox); public static void showDialog(@Nonnull List<FixableMessage> messages,
if (input.isShowCheckbox()) { @Nonnull Context context,
doNotShowCalculationMessagesCheckbox.setVisibility(View.VISIBLE); boolean showCheckbox) {
} else { if (!messages.isEmpty()) {
doNotShowCalculationMessagesCheckbox.setVisibility(View.GONE); final Intent intent = new Intent(context, FixableMessagesDialog.class);
}
final Button closeButton = (Button) findViewById(R.id.close_button); intent.putExtra(INPUT, new Input(messages, showCheckbox));
closeButton.setOnClickListener(new View.OnClickListener() { intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@Override
public void onClick(View v) {
if (doNotShowCalculationMessagesCheckbox.isChecked()) {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(FixableMessagesDialog.this);
Preferences.Calculations.showCalculationMessagesDialog.putPreference(prefs, false);
}
FixableMessagesDialog.this.finish(); context.startActivity(intent);
} }
}); }
}
private void parseIntent(@Nonnull Intent intent) { @Override
final Input input = intent.getParcelableExtra(INPUT); protected void onCreate(Bundle savedInstanceState) {
if (input != null) { super.onCreate(savedInstanceState);
this.input = input;
onInputChanged();
}
}
private void onInputChanged() { setContentView(R.layout.cpp_fixable_messages_dialog);
final ViewGroup viewGroup = (ViewGroup) findViewById(R.id.cpp_fixable_messages_container);
viewGroup.removeAllViews();
final LayoutInflater layoutInflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); final Intent intent = getIntent();
if (intent != null) {
parseIntent(intent);
}
final List<FixableMessage> messages = input.getMessages(); final CheckBox doNotShowCalculationMessagesCheckbox = (CheckBox) findViewById(R.id.cpp_do_not_show_fixable_messages_checkbox);
for (final FixableMessage message : messages) { if (input.isShowCheckbox()) {
final View view = layoutInflater.inflate(R.layout.cpp_fixable_messages_dialog_message, null); doNotShowCalculationMessagesCheckbox.setVisibility(View.VISIBLE);
} else {
doNotShowCalculationMessagesCheckbox.setVisibility(View.GONE);
}
final TextView calculationMessagesTextView = (TextView) view.findViewById(R.id.cpp_fixable_messages_text_view); final Button closeButton = (Button) findViewById(R.id.close_button);
calculationMessagesTextView.setText(message.getMessage()); closeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (doNotShowCalculationMessagesCheckbox.isChecked()) {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(FixableMessagesDialog.this);
Preferences.Calculations.showCalculationMessagesDialog.putPreference(prefs, false);
}
final Button fixButton = (Button) view.findViewById(R.id.cpp_fix_button); FixableMessagesDialog.this.finish();
final FixableError fixableError = message.getFixableError(); }
if (fixableError == null) { });
fixButton.setVisibility(View.GONE); }
fixButton.setOnClickListener(null);
} else {
fixButton.setVisibility(View.VISIBLE);
fixButton.setOnClickListener(new FixErrorOnClickListener(messages, message));
final CharSequence fixCaption = fixableError.getFixCaption(); private void parseIntent(@Nonnull Intent intent) {
if (!Strings.isEmpty(fixCaption)) { final Input input = intent.getParcelableExtra(INPUT);
fixButton.setText(fixCaption); if (input != null) {
} this.input = input;
} onInputChanged();
}
}
viewGroup.addView(view, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
}
@Override
protected void onNewIntent(@Nonnull Intent intent) {
super.onNewIntent(intent);
parseIntent(intent);
}
/* /*
********************************************************************** **********************************************************************
* *
* STATIC * STATIC
* *
********************************************************************** **********************************************************************
*/ */
public static void showDialogForMessages(@Nonnull List<Message> messages, private void onInputChanged() {
@Nonnull Context context, final ViewGroup viewGroup = (ViewGroup) findViewById(R.id.cpp_fixable_messages_container);
boolean showCheckbox) { viewGroup.removeAllViews();
if (!messages.isEmpty()) {
final Intent intent = new Intent(context, FixableMessagesDialog.class);
intent.putExtra(INPUT, Input.fromMessages(messages, showCheckbox)); final LayoutInflater layoutInflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent); final List<FixableMessage> messages = input.getMessages();
} for (final FixableMessage message : messages) {
} final View view = layoutInflater.inflate(R.layout.cpp_fixable_messages_dialog_message, null);
public static void showDialog(@Nonnull List<FixableMessage> messages, final TextView calculationMessagesTextView = (TextView) view.findViewById(R.id.cpp_fixable_messages_text_view);
@Nonnull Context context, calculationMessagesTextView.setText(message.getMessage());
boolean showCheckbox) {
if (!messages.isEmpty()) {
final Intent intent = new Intent(context, FixableMessagesDialog.class);
intent.putExtra(INPUT, new Input(messages, showCheckbox)); final Button fixButton = (Button) view.findViewById(R.id.cpp_fix_button);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); final FixableError fixableError = message.getFixableError();
if (fixableError == null) {
fixButton.setVisibility(View.GONE);
fixButton.setOnClickListener(null);
} else {
fixButton.setVisibility(View.VISIBLE);
fixButton.setOnClickListener(new FixErrorOnClickListener(messages, message));
context.startActivity(intent); final CharSequence fixCaption = fixableError.getFixCaption();
} if (!Strings.isEmpty(fixCaption)) {
} fixButton.setText(fixCaption);
}
private static final class Input implements Parcelable { }
public static final Creator<Input> CREATOR = new Creator<Input>() {
@Override
public Input createFromParcel(@Nonnull Parcel in) {
return Input.fromParcel(in);
}
@Override
public Input[] newArray(int size) {
return new Input[size];
}
};
@Nonnull
private static Input fromParcel(@Nonnull Parcel in) {
final List<FixableMessage> messages = new ArrayList<FixableMessage>();
boolean showCheckbox = in.readInt() == 1;
in.readTypedList(messages, FixableMessage.CREATOR);
return new Input(messages, showCheckbox);
}
@Nonnull viewGroup.addView(view, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
private List<FixableMessage> messages = new ArrayList<FixableMessage>(); }
private boolean showCheckbox; }
private Input(@Nonnull List<FixableMessage> messages, boolean showCheckbox) { @Override
this.messages = messages; protected void onNewIntent(@Nonnull Intent intent) {
this.showCheckbox = showCheckbox; super.onNewIntent(intent);
} parseIntent(intent);
}
@Nonnull private static final class Input implements Parcelable {
public List<FixableMessage> getMessages() {
return messages;
}
@Override public static final Creator<Input> CREATOR = new Creator<Input>() {
public int describeContents() { @Override
return 0; public Input createFromParcel(@Nonnull Parcel in) {
} return Input.fromParcel(in);
}
@Override @Override
public void writeToParcel(@Nonnull Parcel out, int flags) { public Input[] newArray(int size) {
out.writeInt(showCheckbox ? 1 : 0); return new Input[size];
out.writeTypedList(messages); }
} };
@Nonnull
private List<FixableMessage> messages = new ArrayList<FixableMessage>();
private boolean showCheckbox;
@Nonnull private Input(@Nonnull List<FixableMessage> messages, boolean showCheckbox) {
public static Input fromMessages(@Nonnull List<Message> messages, boolean showCheckbox) { this.messages = messages;
final List<FixableMessage> stringMessages = new ArrayList<FixableMessage>(messages.size()); this.showCheckbox = showCheckbox;
for (Message message : messages) { }
stringMessages.add(new FixableMessage(message));
}
return new Input(stringMessages, showCheckbox); @Nonnull
} private static Input fromParcel(@Nonnull Parcel in) {
final List<FixableMessage> messages = new ArrayList<FixableMessage>();
boolean showCheckbox = in.readInt() == 1;
in.readTypedList(messages, FixableMessage.CREATOR);
return new Input(messages, showCheckbox);
}
public boolean isShowCheckbox() { @Nonnull
return showCheckbox; public static Input fromMessages(@Nonnull List<Message> messages, boolean showCheckbox) {
} final List<FixableMessage> stringMessages = new ArrayList<FixableMessage>(messages.size());
} for (Message message : messages) {
stringMessages.add(new FixableMessage(message));
}
private class FixErrorOnClickListener implements View.OnClickListener { return new Input(stringMessages, showCheckbox);
}
@Nonnull @Nonnull
private final List<FixableMessage> messages; public List<FixableMessage> getMessages() {
return messages;
}
@Nonnull @Override
private final FixableMessage currentMessage; public int describeContents() {
return 0;
}
public FixErrorOnClickListener(@Nonnull List<FixableMessage> messages, @Override
@Nonnull FixableMessage message) { public void writeToParcel(@Nonnull Parcel out, int flags) {
this.messages = messages; out.writeInt(showCheckbox ? 1 : 0);
this.currentMessage = message; out.writeTypedList(messages);
} }
@Override public boolean isShowCheckbox() {
public void onClick(View v) { return showCheckbox;
final List<FixableMessage> filteredMessages = new ArrayList<FixableMessage>(messages.size() - 1); }
for (FixableMessage message : messages) { }
if (message.getFixableError() == null) {
filteredMessages.add(message);
} else if (message.getFixableError() != currentMessage.getFixableError()) {
filteredMessages.add(message);
}
}
currentMessage.getFixableError().fix(); private class FixErrorOnClickListener implements View.OnClickListener {
if (!filteredMessages.isEmpty()) { @Nonnull
FixableMessagesDialog.this.input = new Input(filteredMessages, FixableMessagesDialog.this.input.showCheckbox); private final List<FixableMessage> messages;
onInputChanged();
} else { @Nonnull
FixableMessagesDialog.this.finish(); private final FixableMessage currentMessage;
}
} public FixErrorOnClickListener(@Nonnull List<FixableMessage> messages,
} @Nonnull FixableMessage message) {
this.messages = messages;
this.currentMessage = message;
}
@Override
public void onClick(View v) {
final List<FixableMessage> filteredMessages = new ArrayList<FixableMessage>(messages.size() - 1);
for (FixableMessage message : messages) {
if (message.getFixableError() == null) {
filteredMessages.add(message);
} else if (message.getFixableError() != currentMessage.getFixableError()) {
filteredMessages.add(message);
}
}
currentMessage.getFixableError().fix();
if (!filteredMessages.isEmpty()) {
FixableMessagesDialog.this.input = new Input(filteredMessages, FixableMessagesDialog.this.input.showCheckbox);
onInputChanged();
} else {
FixableMessagesDialog.this.finish();
}
}
}
} }

View File

@ -27,7 +27,6 @@ import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.TextView; import android.widget.TextView;
import org.solovyev.android.checkout.ActivityCheckout; import org.solovyev.android.checkout.ActivityCheckout;
@ -47,151 +46,151 @@ import javax.annotation.Nullable;
*/ */
public class FragmentUi extends BaseUi { public class FragmentUi extends BaseUi {
private ActivityCheckout checkout; private ActivityCheckout checkout;
@Nullable @Nullable
private AdView adView; private AdView adView;
private int layoutId; private int layoutId;
private int titleResId = -1; private int titleResId = -1;
private boolean listenersOnCreate = true; private boolean listenersOnCreate = true;
@Nullable @Nullable
private Boolean adFree = null; private Boolean adFree = null;
public FragmentUi(int layoutId) { public FragmentUi(int layoutId) {
this.layoutId = layoutId; this.layoutId = layoutId;
} }
public FragmentUi(int layoutId, int titleResId) { public FragmentUi(int layoutId, int titleResId) {
this.layoutId = layoutId; this.layoutId = layoutId;
this.titleResId = titleResId; this.titleResId = titleResId;
} }
public FragmentUi(int layoutId, int titleResId, boolean listenersOnCreate) { public FragmentUi(int layoutId, int titleResId, boolean listenersOnCreate) {
this.layoutId = layoutId; this.layoutId = layoutId;
this.titleResId = titleResId; this.titleResId = titleResId;
this.listenersOnCreate = listenersOnCreate; this.listenersOnCreate = listenersOnCreate;
} }
public boolean isPane(@Nonnull Fragment fragment) { public boolean isPane(@Nonnull Fragment fragment) {
return fragment.getActivity() instanceof CalculatorActivity; return fragment.getActivity() instanceof CalculatorActivity;
} }
public void setPaneTitle(@Nonnull Fragment fragment, int titleResId) { public void setPaneTitle(@Nonnull Fragment fragment, int titleResId) {
final TextView fragmentTitle = (TextView) fragment.getView().findViewById(R.id.fragment_title); final TextView fragmentTitle = (TextView) fragment.getView().findViewById(R.id.fragment_title);
if (fragmentTitle != null) { if (fragmentTitle != null) {
if (!isPane(fragment)) { if (!isPane(fragment)) {
fragmentTitle.setVisibility(View.GONE); fragmentTitle.setVisibility(View.GONE);
} else { } else {
fragmentTitle.setText(fragment.getString(titleResId).toUpperCase(Locale.getDefault())); fragmentTitle.setText(fragment.getString(titleResId).toUpperCase(Locale.getDefault()));
} }
} }
} }
public void onCreate(@Nonnull Fragment fragment) { public void onCreate(@Nonnull Fragment fragment) {
final FragmentActivity activity = fragment.getActivity(); final FragmentActivity activity = fragment.getActivity();
super.onCreate(activity); super.onCreate(activity);
checkout = Checkout.forActivity(activity, App.getBilling(), App.getProducts()); checkout = Checkout.forActivity(activity, App.getBilling(), App.getProducts());
if (listenersOnCreate) { if (listenersOnCreate) {
if (fragment instanceof CalculatorEventListener) { if (fragment instanceof CalculatorEventListener) {
Locator.getInstance().getCalculator().addCalculatorEventListener((CalculatorEventListener) fragment); Locator.getInstance().getCalculator().addCalculatorEventListener((CalculatorEventListener) fragment);
} }
} }
checkout.start(); checkout.start();
} }
public void onResume(@Nonnull Fragment fragment) { public void onResume(@Nonnull Fragment fragment) {
if (adView != null) { if (adView != null) {
adView.resume(); adView.resume();
} }
if (!listenersOnCreate) { if (!listenersOnCreate) {
if (fragment instanceof CalculatorEventListener) { if (fragment instanceof CalculatorEventListener) {
Locator.getInstance().getCalculator().addCalculatorEventListener((CalculatorEventListener) fragment); Locator.getInstance().getCalculator().addCalculatorEventListener((CalculatorEventListener) fragment);
} }
} }
checkout.loadInventory().whenLoaded(new Inventory.Listener() { checkout.loadInventory().whenLoaded(new Inventory.Listener() {
@Override @Override
public void onLoaded(@Nonnull Inventory.Products products) { public void onLoaded(@Nonnull Inventory.Products products) {
adFree = products.get(ProductTypes.IN_APP).isPurchased("ad_free"); adFree = products.get(ProductTypes.IN_APP).isPurchased("ad_free");
updateAdViewState(); updateAdViewState();
} }
}); });
} }
private void updateAdViewState() { private void updateAdViewState() {
if(adFree == null || adView == null) { if (adFree == null || adView == null) {
return; return;
} }
if (adFree) { if (adFree) {
adView.hide(); adView.hide();
} else { } else {
adView.show(); adView.show();
} }
} }
public void onPause(@Nonnull Fragment fragment) { public void onPause(@Nonnull Fragment fragment) {
adFree = null; adFree = null;
if (adView != null) { if (adView != null) {
adView.pause(); adView.pause();
} }
if (!listenersOnCreate) { if (!listenersOnCreate) {
if (fragment instanceof CalculatorEventListener) { if (fragment instanceof CalculatorEventListener) {
Locator.getInstance().getCalculator().removeCalculatorEventListener((CalculatorEventListener) fragment); Locator.getInstance().getCalculator().removeCalculatorEventListener((CalculatorEventListener) fragment);
} }
} }
} }
public void onViewCreated(@Nonnull Fragment fragment, @Nonnull View root) { public void onViewCreated(@Nonnull Fragment fragment, @Nonnull View root) {
adView = (AdView) root.findViewById(R.id.ad); adView = (AdView) root.findViewById(R.id.ad);
final ViewGroup mainFragmentLayout = (ViewGroup) root.findViewById(R.id.main_fragment_layout); final ViewGroup mainFragmentLayout = (ViewGroup) root.findViewById(R.id.main_fragment_layout);
if (fragment instanceof CalculatorDisplayFragment || fragment instanceof CalculatorEditorFragment || fragment instanceof CalculatorKeyboardFragment) { if (fragment instanceof CalculatorDisplayFragment || fragment instanceof CalculatorEditorFragment || fragment instanceof CalculatorKeyboardFragment) {
// no ads in those fragments // no ads in those fragments
} else { } else {
if (adView != null) { if (adView != null) {
updateAdViewState(); updateAdViewState();
} else if (mainFragmentLayout != null) { } else if (mainFragmentLayout != null) {
} }
} }
if (fragment instanceof CalculatorKeyboardFragment) { if (fragment instanceof CalculatorKeyboardFragment) {
processButtons(fragment.getActivity(), root); processButtons(fragment.getActivity(), root);
} }
fixFonts(root); fixFonts(root);
if (titleResId >= 0) { if (titleResId >= 0) {
this.setPaneTitle(fragment, titleResId); this.setPaneTitle(fragment, titleResId);
} }
} }
public void onDestroy(@Nonnull Fragment fragment) { public void onDestroy(@Nonnull Fragment fragment) {
if (listenersOnCreate) { if (listenersOnCreate) {
if (fragment instanceof CalculatorEventListener) { if (fragment instanceof CalculatorEventListener) {
Locator.getInstance().getCalculator().removeCalculatorEventListener((CalculatorEventListener) fragment); Locator.getInstance().getCalculator().removeCalculatorEventListener((CalculatorEventListener) fragment);
} }
} }
checkout.stop(); checkout.stop();
super.onDestroy(fragment.getActivity()); super.onDestroy(fragment.getActivity());
} }
@Nonnull @Nonnull
public View onCreateView(@Nonnull Fragment fragment, @Nonnull LayoutInflater inflater, @Nullable ViewGroup container) { public View onCreateView(@Nonnull Fragment fragment, @Nonnull LayoutInflater inflater, @Nullable ViewGroup container) {
return inflater.inflate(layoutId, container, false); return inflater.inflate(layoutId, container, false);
} }
public void onDestroyView(@Nonnull Fragment fragment) { public void onDestroyView(@Nonnull Fragment fragment) {
if (adView != null) { if (adView != null) {
adView.destroy(); adView.destroy();
adView = null; adView = null;
} }
} }
} }

View File

@ -24,11 +24,10 @@ package org.solovyev.android.calculator;
import android.app.Activity; import android.app.Activity;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import jscl.NumeralBase;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import org.solovyev.android.calculator.model.AndroidCalculatorEngine; import jscl.NumeralBase;
import static jscl.NumeralBase.hex; import static jscl.NumeralBase.hex;
import static org.solovyev.android.calculator.Preferences.Gui.hideNumeralBaseDigits; import static org.solovyev.android.calculator.Preferences.Gui.hideNumeralBaseDigits;
@ -41,23 +40,23 @@ import static org.solovyev.android.calculator.model.AndroidCalculatorEngine.Pref
*/ */
public class NumeralBaseButtons { public class NumeralBaseButtons {
public static void toggleNumericDigits(@Nonnull Activity activity, @Nonnull NumeralBase currentNumeralBase) { public static void toggleNumericDigits(@Nonnull Activity activity, @Nonnull NumeralBase currentNumeralBase) {
for (NumeralBase numeralBase : NumeralBase.values()) { for (NumeralBase numeralBase : NumeralBase.values()) {
if (currentNumeralBase != numeralBase) { if (currentNumeralBase != numeralBase) {
AndroidNumeralBase.valueOf(numeralBase).toggleButtons(false, activity); AndroidNumeralBase.valueOf(numeralBase).toggleButtons(false, activity);
} }
} }
AndroidNumeralBase.valueOf(currentNumeralBase).toggleButtons(true, activity); AndroidNumeralBase.valueOf(currentNumeralBase).toggleButtons(true, activity);
} }
public static void toggleNumericDigits(@Nonnull Activity activity, @Nonnull SharedPreferences preferences) { public static void toggleNumericDigits(@Nonnull Activity activity, @Nonnull SharedPreferences preferences) {
if (hideNumeralBaseDigits.getPreference(preferences)) { if (hideNumeralBaseDigits.getPreference(preferences)) {
final NumeralBase nb = numeralBase.getPreference(preferences); final NumeralBase nb = numeralBase.getPreference(preferences);
toggleNumericDigits(activity, nb); toggleNumericDigits(activity, nb);
} else { } else {
// set HEX to show all digits // set HEX to show all digits
AndroidNumeralBase.valueOf(hex).toggleButtons(true, activity); AndroidNumeralBase.valueOf(hex).toggleButtons(true, activity);
} }
} }
} }

View File

@ -24,6 +24,7 @@ package org.solovyev.android.calculator;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import org.solovyev.common.msg.MessageLevel; import org.solovyev.common.msg.MessageLevel;
import org.solovyev.common.msg.MessageType; import org.solovyev.common.msg.MessageType;
@ -38,24 +39,24 @@ import javax.annotation.Nullable;
public final class ParcelableDialogData implements DialogData, Parcelable { public final class ParcelableDialogData implements DialogData, Parcelable {
/* /*
********************************************************************** **********************************************************************
* *
* STATIC * STATIC
* *
********************************************************************** **********************************************************************
*/ */
public final static Creator<ParcelableDialogData> CREATOR = new Creator<ParcelableDialogData>() { public final static Creator<ParcelableDialogData> CREATOR = new Creator<ParcelableDialogData>() {
@Override @Override
public ParcelableDialogData createFromParcel(@Nonnull Parcel in) { public ParcelableDialogData createFromParcel(@Nonnull Parcel in) {
return fromParcel(in); return fromParcel(in);
} }
@Override @Override
public ParcelableDialogData[] newArray(int size) { public ParcelableDialogData[] newArray(int size) {
return new ParcelableDialogData[size]; return new ParcelableDialogData[size];
} }
}; };
/* /*
********************************************************************** **********************************************************************
@ -65,8 +66,8 @@ public final class ParcelableDialogData implements DialogData, Parcelable {
********************************************************************** **********************************************************************
*/ */
@Nonnull @Nonnull
private DialogData nestedData; private DialogData nestedData;
/* /*
********************************************************************** **********************************************************************
@ -76,54 +77,54 @@ public final class ParcelableDialogData implements DialogData, Parcelable {
********************************************************************** **********************************************************************
*/ */
public ParcelableDialogData(@Nonnull DialogData nestedData) { public ParcelableDialogData(@Nonnull DialogData nestedData) {
this.nestedData = nestedData; this.nestedData = nestedData;
} }
@Nonnull @Nonnull
public static ParcelableDialogData wrap(@Nonnull DialogData nestedData) { public static ParcelableDialogData wrap(@Nonnull DialogData nestedData) {
if (nestedData instanceof ParcelableDialogData) { if (nestedData instanceof ParcelableDialogData) {
return ((ParcelableDialogData) nestedData); return ((ParcelableDialogData) nestedData);
} else { } else {
return new ParcelableDialogData(nestedData); return new ParcelableDialogData(nestedData);
} }
} }
@Nonnull @Nonnull
public static ParcelableDialogData fromParcel(@Nonnull Parcel in) { public static ParcelableDialogData fromParcel(@Nonnull Parcel in) {
final String message = in.readString(); final String message = in.readString();
final MessageType messageType = CalculatorMessages.toMessageType(in.readInt()); final MessageType messageType = CalculatorMessages.toMessageType(in.readInt());
final String title = in.readString(); final String title = in.readString();
return wrap(StringDialogData.newInstance(message, messageType, title)); return wrap(StringDialogData.newInstance(message, messageType, title));
} }
@Nonnull @Nonnull
@Override @Override
public String getMessage() { public String getMessage() {
return nestedData.getMessage(); return nestedData.getMessage();
} }
@Nonnull @Nonnull
@Override @Override
public MessageLevel getMessageLevel() { public MessageLevel getMessageLevel() {
return nestedData.getMessageLevel(); return nestedData.getMessageLevel();
} }
@Nullable @Nullable
@Override @Override
public String getTitle() { public String getTitle() {
return nestedData.getTitle(); return nestedData.getTitle();
} }
@Override @Override
public int describeContents() { public int describeContents() {
return 0; return 0;
} }
@Override @Override
public void writeToParcel(@Nonnull Parcel out, int flags) { public void writeToParcel(@Nonnull Parcel out, int flags) {
out.writeString(this.getMessage()); out.writeString(this.getMessage());
out.writeInt(this.getMessageLevel().getMessageLevel()); out.writeInt(this.getMessageLevel().getMessageLevel());
out.writeString(this.getTitle()); out.writeString(this.getTitle());
} }
} }

View File

@ -61,347 +61,345 @@ import static org.solovyev.android.DeviceModel.samsung_galaxy_s_2;
public final class Preferences { public final class Preferences {
private Preferences() { public static final Preference<Integer> appVersion = IntegerPreference.of("application.version", -1);
throw new AssertionError(); public static final Preference<Integer> appOpenedCounter = IntegerPreference.of("app_opened_counter", 0);
} private Preferences() {
throw new AssertionError();
public static final Preference<Integer> appVersion = IntegerPreference.of("application.version", -1); }
public static final Preference<Integer> appOpenedCounter = IntegerPreference.of("app_opened_counter", 0);
static void setDefaultValues(@Nonnull SharedPreferences preferences) {
public enum SimpleTheme {
if (!AndroidCalculatorEngine.Preferences.groupingSeparator.isSet(preferences)) {
default_theme(0, 0, null), final Locale locale = Locale.getDefault();
metro_blue_theme(R.layout.onscreen_layout, R.layout.widget_layout, Gui.Theme.metro_blue_theme), if (locale != null) {
material_theme(R.layout.onscreen_layout_material, R.layout.widget_layout_material, Gui.Theme.material_theme), final DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols(locale);
material_light_theme(R.layout.onscreen_layout_material_light, R.layout.widget_layout_material_light, Gui.Theme.material_light_theme); int index = MathType.grouping_separator.getTokens().indexOf(String.valueOf(decimalFormatSymbols.getGroupingSeparator()));
final String groupingSeparator;
@LayoutRes if (index >= 0) {
private final int onscreenLayout; groupingSeparator = MathType.grouping_separator.getTokens().get(index);
} else {
@LayoutRes groupingSeparator = " ";
private final int widgetLayout; }
@Nullable AndroidCalculatorEngine.Preferences.groupingSeparator.putPreference(preferences, groupingSeparator);
private final Gui.Theme appTheme; }
}
@Nonnull
private final Map<Gui.Theme, SimpleTheme> cache = new EnumMap<>(Gui.Theme.class); if (!AndroidCalculatorEngine.Preferences.angleUnit.isSet(preferences)) {
AndroidCalculatorEngine.Preferences.angleUnit.putDefault(preferences);
SimpleTheme(int onscreenLayout, int widgetLayout, @Nullable Gui.Theme appTheme) { }
this.onscreenLayout = onscreenLayout;
this.widgetLayout = widgetLayout; if (!AndroidCalculatorEngine.Preferences.numeralBase.isSet(preferences)) {
this.appTheme = appTheme; AndroidCalculatorEngine.Preferences.numeralBase.putDefault(preferences);
} }
public int getOnscreenLayout(@Nonnull Gui.Theme appTheme) { if (!AndroidCalculatorEngine.Preferences.multiplicationSign.isSet(preferences)) {
return resolveThemeFor(appTheme).onscreenLayout; if (isPhoneModel(samsung_galaxy_s) || isPhoneModel(samsung_galaxy_s_2)) {
} // workaround ofr samsung galaxy s phones
AndroidCalculatorEngine.Preferences.multiplicationSign.putPreference(preferences, "*");
public int getWidgetLayout(@Nonnull Gui.Theme appTheme) { }
return resolveThemeFor(appTheme).widgetLayout; }
}
applyDefaultPreference(preferences, Gui.theme);
@Nonnull applyDefaultPreference(preferences, Gui.layout);
public SimpleTheme resolveThemeFor(@Nonnull Gui.Theme appTheme) { if (Gui.layout.getPreference(preferences) == Gui.Layout.main_cellphone) {
if (this == default_theme) { Gui.layout.putDefault(preferences);
SimpleTheme theme = cache.get(appTheme); }
if (theme == null) { applyDefaultPreference(preferences, Gui.feedbackWindowShown);
theme = lookUpThemeFor(appTheme); applyDefaultPreference(preferences, Gui.showReleaseNotes);
cache.put(appTheme, theme); applyDefaultPreference(preferences, Gui.usePrevAsBack);
} applyDefaultPreference(preferences, Gui.showEqualsButton);
return theme; applyDefaultPreference(preferences, Gui.autoOrientation);
} applyDefaultPreference(preferences, Gui.hideNumeralBaseDigits);
return this; applyDefaultPreference(preferences, Gui.preventScreenFromFading);
} applyDefaultPreference(preferences, Gui.language);
@Nonnull applyDefaultPreference(preferences, Graph.plotImag);
private SimpleTheme lookUpThemeFor(@Nonnull Gui.Theme appTheme) { applyDefaultPreference(preferences, History.showIntermediateCalculations);
Check.isTrue(this == default_theme); applyDefaultPreference(preferences, History.showDatetime);
// find direct match applyDefaultPreference(preferences, Calculations.calculateOnFly);
for (SimpleTheme theme : values()) { applyDefaultPreference(preferences, Calculations.preferredAngleUnits);
if (theme.appTheme == appTheme) { applyDefaultPreference(preferences, Calculations.preferredNumeralBase);
return theme;
} applyDefaultPreference(preferences, Onscreen.showAppIcon);
} applyDefaultPreference(preferences, Onscreen.startOnBoot);
applyDefaultPreference(preferences, Onscreen.theme);
// for metro themes return metro theme
if (appTheme == Gui.Theme.metro_green_theme || appTheme == Gui.Theme.metro_purple_theme) { applyDefaultPreference(preferences, Widget.theme);
return metro_blue_theme;
} applyDefaultPreference(preferences, Ga.initialReportDone);
// for old themes return dark material
return material_theme; // renew value after each application start
} Calculations.showCalculationMessagesDialog.putDefault(preferences);
Calculations.lastPreferredPreferencesCheck.putDefault(preferences);
@Nullable
public Gui.Theme getAppTheme() { if (!Gui.hapticFeedback.isSet(preferences)) {
return appTheme; final Preference<Boolean> hfEnabled = Gui.hapticFeedbackEnabled;
} final boolean enabled = !hfEnabled.isSet(preferences) ? true : hfEnabled.getPreference(preferences);
} if (enabled) {
final Preference<Long> hfDuration = Gui.hapticFeedbackDuration;
public static class Widget { final long duration = !hfDuration.isSet(preferences) ? 60L : hfDuration.getPreference(preferences);
public static final Preference<SimpleTheme> theme = StringPreference.ofEnum("widget.theme", SimpleTheme.default_theme, SimpleTheme.class); Gui.hapticFeedback.putPreference(preferences, duration);
} else {
@Nonnull Gui.hapticFeedback.putPreference(preferences, 0L);
public static SimpleTheme getTheme(@Nonnull SharedPreferences preferences) { }
return theme.getPreferenceNoError(preferences); }
} }
} private static void applyDefaultPreference(@Nonnull SharedPreferences preferences, @Nonnull Preference<?> preference) {
public static class Onscreen { preference.tryPutDefault(preferences);
public static final Preference<Boolean> startOnBoot = BooleanPreference.of("onscreen_start_on_boot", false); }
public static final Preference<Boolean> showAppIcon = BooleanPreference.of("onscreen_show_app_icon", true);
public static final Preference<SimpleTheme> theme = StringPreference.ofEnum("onscreen.theme", SimpleTheme.default_theme, SimpleTheme.class); public enum SimpleTheme {
@Nonnull default_theme(0, 0, null),
public static SimpleTheme getTheme(@Nonnull SharedPreferences preferences) { metro_blue_theme(R.layout.onscreen_layout, R.layout.widget_layout, Gui.Theme.metro_blue_theme),
return theme.getPreferenceNoError(preferences); material_theme(R.layout.onscreen_layout_material, R.layout.widget_layout_material, Gui.Theme.material_theme),
} material_light_theme(R.layout.onscreen_layout_material_light, R.layout.widget_layout_material_light, Gui.Theme.material_light_theme);
}
@LayoutRes
public static class Calculations { private final int onscreenLayout;
public static final Preference<Boolean> calculateOnFly = BooleanPreference.of("calculations_calculate_on_fly", true); @LayoutRes
public static final Preference<Boolean> showCalculationMessagesDialog = BooleanPreference.of("show_calculation_messages_dialog", true); private final int widgetLayout;
public static final Preference<NumeralBase> preferredNumeralBase = StringPreference.ofEnum("preferred_numeral_base", AndroidCalculatorEngine.Preferences.numeralBase.getDefaultValue(), NumeralBase.class); @Nullable
public static final Preference<AngleUnit> preferredAngleUnits = StringPreference.ofEnum("preferred_angle_units", AndroidCalculatorEngine.Preferences.angleUnit.getDefaultValue(), AngleUnit.class); private final Gui.Theme appTheme;
public static final Preference<Long> lastPreferredPreferencesCheck = LongPreference.of("preferred_preferences_check_time", 0L);
@Nonnull
} private final Map<Gui.Theme, SimpleTheme> cache = new EnumMap<>(Gui.Theme.class);
public static class Ga { SimpleTheme(int onscreenLayout, int widgetLayout, @Nullable Gui.Theme appTheme) {
public static final Preference<Boolean> initialReportDone = BooleanPreference.of("ga.initial_report_done", false); this.onscreenLayout = onscreenLayout;
} this.widgetLayout = widgetLayout;
this.appTheme = appTheme;
public static class Gui { }
public static final Preference<Theme> theme = StringPreference.ofEnum("org.solovyev.android.calculator.CalculatorActivity_calc_theme", Theme.material_theme, Theme.class); public int getOnscreenLayout(@Nonnull Gui.Theme appTheme) {
public static final Preference<Layout> layout = StringPreference.ofEnum("org.solovyev.android.calculator.CalculatorActivity_calc_layout", Layout.simple, Layout.class); return resolveThemeFor(appTheme).onscreenLayout;
public static final Preference<String> language = StringPreference.of("gui.language", Languages.SYSTEM_LANGUAGE_CODE); }
public static final Preference<Boolean> feedbackWindowShown = BooleanPreference.of("feedback_window_shown", false);
public static final Preference<Boolean> showReleaseNotes = BooleanPreference.of("org.solovyev.android.calculator.CalculatorActivity_show_release_notes", true); public int getWidgetLayout(@Nonnull Gui.Theme appTheme) {
public static final Preference<Boolean> usePrevAsBack = BooleanPreference.of("org.solovyev.android.calculator.CalculatorActivity_use_back_button_as_prev", false); return resolveThemeFor(appTheme).widgetLayout;
public static final Preference<Boolean> showEqualsButton = BooleanPreference.of("showEqualsButton", true); }
public static final Preference<Boolean> autoOrientation = BooleanPreference.of("autoOrientation", true);
public static final Preference<Boolean> hideNumeralBaseDigits = BooleanPreference.of("hideNumeralBaseDigits", true); @Nonnull
public static final Preference<Boolean> preventScreenFromFading = BooleanPreference.of("preventScreenFromFading", true); public SimpleTheme resolveThemeFor(@Nonnull Gui.Theme appTheme) {
public static final Preference<Boolean> colorDisplay = BooleanPreference.of("org.solovyev.android.calculator.CalculatorModel_color_display", true); if (this == default_theme) {
public static final Preference<Long> hapticFeedback = NumberToStringPreference.of("hapticFeedback", 60L, Long.class); SimpleTheme theme = cache.get(appTheme);
if (theme == null) {
private static final Preference<Boolean> hapticFeedbackEnabled = BooleanPreference.of("org.solovyev.android.calculator.CalculatorModel_haptic_feedback", false); theme = lookUpThemeFor(appTheme);
private static final Preference<Long> hapticFeedbackDuration = NumberToStringPreference.of("org.solovyev.android.calculator.CalculatorActivity_calc_haptic_feedback_duration_key", 60L, Long.class); cache.put(appTheme, theme);
}
@Nonnull return theme;
public static Theme getTheme(@Nonnull SharedPreferences preferences) { }
return theme.getPreferenceNoError(preferences); return this;
} }
@Nonnull @Nonnull
public static Layout getLayout(@Nonnull SharedPreferences preferences) { private SimpleTheme lookUpThemeFor(@Nonnull Gui.Theme appTheme) {
return layout.getPreferenceNoError(preferences); Check.isTrue(this == default_theme);
} // find direct match
for (SimpleTheme theme : values()) {
public enum Theme { if (theme.appTheme == appTheme) {
return theme;
default_theme(R.style.Cpp_Theme_Gray), }
violet_theme(R.style.Cpp_Theme_Violet), }
light_blue_theme(R.style.Cpp_Theme_Blue),
metro_blue_theme(R.style.cpp_metro_blue_theme), // for metro themes return metro theme
metro_purple_theme(R.style.cpp_metro_purple_theme), if (appTheme == Gui.Theme.metro_green_theme || appTheme == Gui.Theme.metro_purple_theme) {
metro_green_theme(R.style.cpp_metro_green_theme), return metro_blue_theme;
material_theme(R.style.Cpp_Theme_Material), }
material_light_theme(R.style.Cpp_Theme_Material_Light, R.style.Cpp_Theme_Wizard_Light, R.style.Cpp_Theme_Dialog_Material_Light),
; // for old themes return dark material
return material_theme;
private static final SparseArray<TextColor> textColors = new SparseArray<>(); }
private final int themeId; @Nullable
private final int wizardThemeId; public Gui.Theme getAppTheme() {
private final int dialogThemeId; return appTheme;
}
Theme(@StyleRes int themeId) { }
this(themeId, R.style.Cpp_Theme_Wizard, R.style.Cpp_Theme_Dialog_Material);
} public static class Widget {
public static final Preference<SimpleTheme> theme = StringPreference.ofEnum("widget.theme", SimpleTheme.default_theme, SimpleTheme.class);
Theme(@StyleRes int themeId, @StyleRes int wizardThemeId, int dialogThemeId) {
this.themeId = themeId; @Nonnull
this.wizardThemeId = wizardThemeId; public static SimpleTheme getTheme(@Nonnull SharedPreferences preferences) {
this.dialogThemeId = dialogThemeId; return theme.getPreferenceNoError(preferences);
} }
public int getThemeId() { }
return getThemeId(null);
} public static class Onscreen {
public static final Preference<Boolean> startOnBoot = BooleanPreference.of("onscreen_start_on_boot", false);
public int getThemeId(@Nullable Context context) { public static final Preference<Boolean> showAppIcon = BooleanPreference.of("onscreen_show_app_icon", true);
if (context instanceof WizardActivity) { public static final Preference<SimpleTheme> theme = StringPreference.ofEnum("onscreen.theme", SimpleTheme.default_theme, SimpleTheme.class);
return wizardThemeId;
} @Nonnull
if (context instanceof PurchaseDialogActivity) { public static SimpleTheme getTheme(@Nonnull SharedPreferences preferences) {
return dialogThemeId; return theme.getPreferenceNoError(preferences);
} }
return themeId; }
}
public static class Calculations {
@Nonnull
public TextColor getTextColor(@Nonnull Context context) { public static final Preference<Boolean> calculateOnFly = BooleanPreference.of("calculations_calculate_on_fly", true);
final int themeId = getThemeId(context); public static final Preference<Boolean> showCalculationMessagesDialog = BooleanPreference.of("show_calculation_messages_dialog", true);
TextColor textColor = textColors.get(themeId);
if (textColor == null) { public static final Preference<NumeralBase> preferredNumeralBase = StringPreference.ofEnum("preferred_numeral_base", AndroidCalculatorEngine.Preferences.numeralBase.getDefaultValue(), NumeralBase.class);
final ContextThemeWrapper themeContext = new ContextThemeWrapper(context, themeId); public static final Preference<AngleUnit> preferredAngleUnits = StringPreference.ofEnum("preferred_angle_units", AndroidCalculatorEngine.Preferences.angleUnit.getDefaultValue(), AngleUnit.class);
final TypedArray a = themeContext.obtainStyledAttributes(themeId, new int[]{R.attr.cpp_text_color, R.attr.cpp_text_color_error}); public static final Preference<Long> lastPreferredPreferencesCheck = LongPreference.of("preferred_preferences_check_time", 0L);
final int normal = a.getColor(0, Color.BLACK);
final int error = a.getColor(1, Color.WHITE); }
a.recycle();
textColor = new TextColor(normal, error); public static class Ga {
textColors.append(themeId, textColor); public static final Preference<Boolean> initialReportDone = BooleanPreference.of("ga.initial_report_done", false);
} }
return textColor;
} public static class Gui {
public boolean isLight() { public static final Preference<Theme> theme = StringPreference.ofEnum("org.solovyev.android.calculator.CalculatorActivity_calc_theme", Theme.material_theme, Theme.class);
return themeId == R.style.Cpp_Theme_Material_Light; public static final Preference<Layout> layout = StringPreference.ofEnum("org.solovyev.android.calculator.CalculatorActivity_calc_layout", Layout.simple, Layout.class);
} public static final Preference<String> language = StringPreference.of("gui.language", Languages.SYSTEM_LANGUAGE_CODE);
} public static final Preference<Boolean> feedbackWindowShown = BooleanPreference.of("feedback_window_shown", false);
public static final Preference<Boolean> showReleaseNotes = BooleanPreference.of("org.solovyev.android.calculator.CalculatorActivity_show_release_notes", true);
public static final class TextColor { public static final Preference<Boolean> usePrevAsBack = BooleanPreference.of("org.solovyev.android.calculator.CalculatorActivity_use_back_button_as_prev", false);
public final int normal; public static final Preference<Boolean> showEqualsButton = BooleanPreference.of("showEqualsButton", true);
public final int error; public static final Preference<Boolean> autoOrientation = BooleanPreference.of("autoOrientation", true);
public static final Preference<Boolean> hideNumeralBaseDigits = BooleanPreference.of("hideNumeralBaseDigits", true);
TextColor(int normal, int error) { public static final Preference<Boolean> preventScreenFromFading = BooleanPreference.of("preventScreenFromFading", true);
this.normal = normal; public static final Preference<Boolean> colorDisplay = BooleanPreference.of("org.solovyev.android.calculator.CalculatorModel_color_display", true);
this.error = error; public static final Preference<Long> hapticFeedback = NumberToStringPreference.of("hapticFeedback", 60L, Long.class);
}
} private static final Preference<Boolean> hapticFeedbackEnabled = BooleanPreference.of("org.solovyev.android.calculator.CalculatorModel_haptic_feedback", false);
private static final Preference<Long> hapticFeedbackDuration = NumberToStringPreference.of("org.solovyev.android.calculator.CalculatorActivity_calc_haptic_feedback_duration_key", 60L, Long.class);
public static enum Layout {
main_calculator(R.layout.main_calculator, R.string.p_layout_calculator, true), @Nonnull
main_calculator_mobile(R.layout.main_calculator_mobile, R.string.p_layout_calculator_mobile, false), public static Theme getTheme(@Nonnull SharedPreferences preferences) {
return theme.getPreferenceNoError(preferences);
// not used anymore }
@Deprecated
main_cellphone(R.layout.main_calculator, 0, true), @Nonnull
public static Layout getLayout(@Nonnull SharedPreferences preferences) {
simple(R.layout.main_calculator, R.string.p_layout_simple, true), return layout.getPreferenceNoError(preferences);
simple_mobile(R.layout.main_calculator_mobile, R.string.p_layout_simple_mobile, false); }
private final int layoutId; public enum Theme {
private final int nameResId;
private final boolean optimized; default_theme(R.style.Cpp_Theme_Gray),
violet_theme(R.style.Cpp_Theme_Violet),
Layout(int layoutId, int nameResId, boolean optimized) { light_blue_theme(R.style.Cpp_Theme_Blue),
this.layoutId = layoutId; metro_blue_theme(R.style.cpp_metro_blue_theme),
this.nameResId = nameResId; metro_purple_theme(R.style.cpp_metro_purple_theme),
this.optimized = optimized; metro_green_theme(R.style.cpp_metro_green_theme),
} material_theme(R.style.Cpp_Theme_Material),
material_light_theme(R.style.Cpp_Theme_Material_Light, R.style.Cpp_Theme_Wizard_Light, R.style.Cpp_Theme_Dialog_Material_Light),;
public int getLayoutId() {
return layoutId; private static final SparseArray<TextColor> textColors = new SparseArray<>();
}
private final int themeId;
public int getNameResId() { private final int wizardThemeId;
return nameResId; private final int dialogThemeId;
}
Theme(@StyleRes int themeId) {
public boolean isOptimized() { this(themeId, R.style.Cpp_Theme_Wizard, R.style.Cpp_Theme_Dialog_Material);
return optimized; }
}
} Theme(@StyleRes int themeId, @StyleRes int wizardThemeId, int dialogThemeId) {
} this.themeId = themeId;
this.wizardThemeId = wizardThemeId;
public static class Graph { this.dialogThemeId = dialogThemeId;
public static final Preference<Boolean> plotImag = BooleanPreference.of("graph_plot_imag", false); }
}
public int getThemeId() {
public static class History { return getThemeId(null);
public static final Preference<Boolean> showIntermediateCalculations = BooleanPreference.of("history_show_intermediate_calculations", false); }
public static final Preference<Boolean> showDatetime = BooleanPreference.of("history_show_datetime", true);
} public int getThemeId(@Nullable Context context) {
if (context instanceof WizardActivity) {
return wizardThemeId;
static void setDefaultValues(@Nonnull SharedPreferences preferences) { }
if (context instanceof PurchaseDialogActivity) {
if (!AndroidCalculatorEngine.Preferences.groupingSeparator.isSet(preferences)) { return dialogThemeId;
final Locale locale = Locale.getDefault(); }
if (locale != null) { return themeId;
final DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols(locale); }
int index = MathType.grouping_separator.getTokens().indexOf(String.valueOf(decimalFormatSymbols.getGroupingSeparator()));
final String groupingSeparator; @Nonnull
if (index >= 0) { public TextColor getTextColor(@Nonnull Context context) {
groupingSeparator = MathType.grouping_separator.getTokens().get(index); final int themeId = getThemeId(context);
} else { TextColor textColor = textColors.get(themeId);
groupingSeparator = " "; if (textColor == null) {
} final ContextThemeWrapper themeContext = new ContextThemeWrapper(context, themeId);
final TypedArray a = themeContext.obtainStyledAttributes(themeId, new int[]{R.attr.cpp_text_color, R.attr.cpp_text_color_error});
AndroidCalculatorEngine.Preferences.groupingSeparator.putPreference(preferences, groupingSeparator); final int normal = a.getColor(0, Color.BLACK);
} final int error = a.getColor(1, Color.WHITE);
} a.recycle();
textColor = new TextColor(normal, error);
if (!AndroidCalculatorEngine.Preferences.angleUnit.isSet(preferences)) { textColors.append(themeId, textColor);
AndroidCalculatorEngine.Preferences.angleUnit.putDefault(preferences); }
} return textColor;
}
if (!AndroidCalculatorEngine.Preferences.numeralBase.isSet(preferences)) {
AndroidCalculatorEngine.Preferences.numeralBase.putDefault(preferences); public boolean isLight() {
} return themeId == R.style.Cpp_Theme_Material_Light;
}
if (!AndroidCalculatorEngine.Preferences.multiplicationSign.isSet(preferences)) { }
if (isPhoneModel(samsung_galaxy_s) || isPhoneModel(samsung_galaxy_s_2)) {
// workaround ofr samsung galaxy s phones public static enum Layout {
AndroidCalculatorEngine.Preferences.multiplicationSign.putPreference(preferences, "*"); main_calculator(R.layout.main_calculator, R.string.p_layout_calculator, true),
} main_calculator_mobile(R.layout.main_calculator_mobile, R.string.p_layout_calculator_mobile, false),
}
// not used anymore
applyDefaultPreference(preferences, Gui.theme); @Deprecated
applyDefaultPreference(preferences, Gui.layout); main_cellphone(R.layout.main_calculator, 0, true),
if (Gui.layout.getPreference(preferences) == Gui.Layout.main_cellphone) {
Gui.layout.putDefault(preferences); simple(R.layout.main_calculator, R.string.p_layout_simple, true),
} simple_mobile(R.layout.main_calculator_mobile, R.string.p_layout_simple_mobile, false);
applyDefaultPreference(preferences, Gui.feedbackWindowShown);
applyDefaultPreference(preferences, Gui.showReleaseNotes); private final int layoutId;
applyDefaultPreference(preferences, Gui.usePrevAsBack); private final int nameResId;
applyDefaultPreference(preferences, Gui.showEqualsButton); private final boolean optimized;
applyDefaultPreference(preferences, Gui.autoOrientation);
applyDefaultPreference(preferences, Gui.hideNumeralBaseDigits); Layout(int layoutId, int nameResId, boolean optimized) {
applyDefaultPreference(preferences, Gui.preventScreenFromFading); this.layoutId = layoutId;
applyDefaultPreference(preferences, Gui.language); this.nameResId = nameResId;
this.optimized = optimized;
applyDefaultPreference(preferences, Graph.plotImag); }
applyDefaultPreference(preferences, History.showIntermediateCalculations);
applyDefaultPreference(preferences, History.showDatetime); public int getLayoutId() {
applyDefaultPreference(preferences, Calculations.calculateOnFly); return layoutId;
applyDefaultPreference(preferences, Calculations.preferredAngleUnits); }
applyDefaultPreference(preferences, Calculations.preferredNumeralBase);
public int getNameResId() {
applyDefaultPreference(preferences, Onscreen.showAppIcon); return nameResId;
applyDefaultPreference(preferences, Onscreen.startOnBoot); }
applyDefaultPreference(preferences, Onscreen.theme);
public boolean isOptimized() {
applyDefaultPreference(preferences, Widget.theme); return optimized;
}
applyDefaultPreference(preferences, Ga.initialReportDone); }
public static final class TextColor {
// renew value after each application start public final int normal;
Calculations.showCalculationMessagesDialog.putDefault(preferences); public final int error;
Calculations.lastPreferredPreferencesCheck.putDefault(preferences);
TextColor(int normal, int error) {
if (!Gui.hapticFeedback.isSet(preferences)) { this.normal = normal;
final Preference<Boolean> hfEnabled = Gui.hapticFeedbackEnabled; this.error = error;
final boolean enabled = !hfEnabled.isSet(preferences) ? true : hfEnabled.getPreference(preferences); }
if (enabled) { }
final Preference<Long> hfDuration = Gui.hapticFeedbackDuration; }
final long duration = !hfDuration.isSet(preferences) ? 60L : hfDuration.getPreference(preferences);
Gui.hapticFeedback.putPreference(preferences, duration); public static class Graph {
} else { public static final Preference<Boolean> plotImag = BooleanPreference.of("graph_plot_imag", false);
Gui.hapticFeedback.putPreference(preferences, 0L); }
}
} public static class History {
} public static final Preference<Boolean> showIntermediateCalculations = BooleanPreference.of("history_show_intermediate_calculations", false);
public static final Preference<Boolean> showDatetime = BooleanPreference.of("history_show_datetime", true);
private static void applyDefaultPreference(@Nonnull SharedPreferences preferences, @Nonnull Preference<?> preference) { }
preference.tryPutDefault(preferences);
}
} }

View File

@ -8,35 +8,35 @@ import javax.annotation.Nonnull;
public final class Vibrator implements SharedPreferences.OnSharedPreferenceChangeListener { public final class Vibrator implements SharedPreferences.OnSharedPreferenceChangeListener {
@Nonnull @Nonnull
private final android.os.Vibrator service; private final android.os.Vibrator service;
private long time = 0; private long time = 0;
public Vibrator(@Nonnull Context context, @Nonnull SharedPreferences preferences) { public Vibrator(@Nonnull Context context, @Nonnull SharedPreferences preferences) {
service = (android.os.Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); service = (android.os.Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
preferences.registerOnSharedPreferenceChangeListener(this); preferences.registerOnSharedPreferenceChangeListener(this);
updateTime(preferences); updateTime(preferences);
} }
private void updateTime(@Nonnull SharedPreferences preferences) { private void updateTime(@Nonnull SharedPreferences preferences) {
time = Preferences.Gui.hapticFeedback.getPreference(preferences) / 2; time = Preferences.Gui.hapticFeedback.getPreference(preferences) / 2;
} }
public void vibrate() { public void vibrate() {
try { try {
if (time > 0) { if (time > 0) {
service.vibrate(time); service.vibrate(time);
} }
} catch (SecurityException e) { } catch (SecurityException e) {
Log.e("Vibrator", e.getMessage(), e); Log.e("Vibrator", e.getMessage(), e);
} }
} }
@Override @Override
public void onSharedPreferenceChanged(@Nonnull SharedPreferences preferences, String key) { public void onSharedPreferenceChanged(@Nonnull SharedPreferences preferences, String key) {
if (Preferences.Gui.hapticFeedback.isSameKey(key)) { if (Preferences.Gui.hapticFeedback.isSameKey(key)) {
updateTime(preferences); updateTime(preferences);
} }
} }
} }

View File

@ -23,8 +23,9 @@
package org.solovyev.android.calculator.about; package org.solovyev.android.calculator.about;
import android.os.Bundle; import android.os.Bundle;
import org.solovyev.android.calculator.EmptyActivity;
import org.solovyev.android.calculator.CalculatorFragmentType; import org.solovyev.android.calculator.CalculatorFragmentType;
import org.solovyev.android.calculator.EmptyActivity;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -36,11 +37,11 @@ import javax.annotation.Nullable;
*/ */
public class CalculatorAboutActivity extends EmptyActivity { public class CalculatorAboutActivity extends EmptyActivity {
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
getUi().addTab(this, CalculatorFragmentType.about, null, R.id.main_layout); getUi().addTab(this, CalculatorFragmentType.about, null, R.id.main_layout);
getUi().addTab(this, CalculatorFragmentType.release_notes, null, R.id.main_layout); getUi().addTab(this, CalculatorFragmentType.release_notes, null, R.id.main_layout);
} }
} }

View File

@ -27,6 +27,7 @@ import android.text.method.LinkMovementMethod;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.solovyev.android.calculator.App; import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.CalculatorFragment; import org.solovyev.android.calculator.CalculatorFragment;
import org.solovyev.android.calculator.CalculatorFragmentType; import org.solovyev.android.calculator.CalculatorFragmentType;
@ -42,27 +43,27 @@ import static org.solovyev.common.text.Strings.isEmpty;
*/ */
public class CalculatorAboutFragment extends CalculatorFragment { public class CalculatorAboutFragment extends CalculatorFragment {
public CalculatorAboutFragment() { public CalculatorAboutFragment() {
super(CalculatorFragmentType.about); super(CalculatorFragmentType.about);
} }
@Override @Override
public void onViewCreated(View root, Bundle savedInstanceState) { public void onViewCreated(View root, Bundle savedInstanceState) {
super.onViewCreated(root, savedInstanceState); super.onViewCreated(root, savedInstanceState);
if (App.getTheme().isLight()) { if (App.getTheme().isLight()) {
final ImageView image = (ImageView) root.findViewById(R.id.about_image); final ImageView image = (ImageView) root.findViewById(R.id.about_image);
image.setImageResource(R.drawable.logo_wizard_light); image.setImageResource(R.drawable.logo_wizard_light);
} }
final TextView aboutTextView = (TextView) root.findViewById(R.id.cpp_about_textview); final TextView aboutTextView = (TextView) root.findViewById(R.id.cpp_about_textview);
aboutTextView.setMovementMethod(LinkMovementMethod.getInstance()); aboutTextView.setMovementMethod(LinkMovementMethod.getInstance());
final TextView translatorsTextTextView = (TextView) root.findViewById(R.id.cpp_about_translators_text); final TextView translatorsTextTextView = (TextView) root.findViewById(R.id.cpp_about_translators_text);
final TextView translatorsTextView = (TextView) root.findViewById(R.id.cpp_about_translators); final TextView translatorsTextView = (TextView) root.findViewById(R.id.cpp_about_translators);
if(isEmpty(translatorsTextView.getText())) { if (isEmpty(translatorsTextView.getText())) {
translatorsTextTextView.setVisibility(GONE); translatorsTextTextView.setVisibility(GONE);
translatorsTextView.setVisibility(GONE); translatorsTextView.setVisibility(GONE);
} }
} }
} }

View File

@ -27,6 +27,7 @@ import android.text.Html;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import org.solovyev.android.calculator.CalculatorFragment; import org.solovyev.android.calculator.CalculatorFragment;
import org.solovyev.android.calculator.CalculatorFragmentType; import org.solovyev.android.calculator.CalculatorFragmentType;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
@ -39,17 +40,17 @@ import org.solovyev.android.calculator.release.ReleaseNotes;
*/ */
public class CalculatorReleaseNotesFragment extends CalculatorFragment { public class CalculatorReleaseNotesFragment extends CalculatorFragment {
public CalculatorReleaseNotesFragment() { public CalculatorReleaseNotesFragment() {
super(CalculatorFragmentType.release_notes); super(CalculatorFragmentType.release_notes);
} }
@Override @Override
public void onViewCreated(View root, Bundle savedInstanceState) { public void onViewCreated(View root, Bundle savedInstanceState) {
super.onViewCreated(root, savedInstanceState); super.onViewCreated(root, savedInstanceState);
final TextView releaseNotes = (TextView) root.findViewById(R.id.releaseNotesTextView); final TextView releaseNotes = (TextView) root.findViewById(R.id.releaseNotesTextView);
releaseNotes.setMovementMethod(LinkMovementMethod.getInstance()); releaseNotes.setMovementMethod(LinkMovementMethod.getInstance());
releaseNotes.setText(Html.fromHtml(ReleaseNotes.getReleaseNotes(this.getActivity()))); releaseNotes.setText(Html.fromHtml(ReleaseNotes.getReleaseNotes(this.getActivity())));
} }
} }

View File

@ -34,28 +34,28 @@ import javax.annotation.Nullable;
*/ */
public class TextHelper { public class TextHelper {
@Nonnull @Nonnull
public String packageName; public String packageName;
@Nonnull @Nonnull
public Resources resources; public Resources resources;
public TextHelper(@Nonnull Resources resources, @Nonnull String packageName) { public TextHelper(@Nonnull Resources resources, @Nonnull String packageName) {
this.packageName = packageName; this.packageName = packageName;
this.resources = resources; this.resources = resources;
} }
@Nullable @Nullable
public String getText(@Nonnull String stringName) { public String getText(@Nonnull String stringName) {
final int stringId = this.resources.getIdentifier(stringName, "string", this.packageName); final int stringId = this.resources.getIdentifier(stringName, "string", this.packageName);
try { try {
if (stringId == 0) { if (stringId == 0) {
return null; return null;
} }
return resources.getString(stringId); return resources.getString(stringId);
} catch (Resources.NotFoundException e) { } catch (Resources.NotFoundException e) {
return null; return null;
} }
} }
} }

View File

@ -30,395 +30,388 @@ import android.graphics.Paint;
import android.text.TextPaint; import android.text.TextPaint;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import org.solovyev.common.math.Point2d; import org.solovyev.common.math.Point2d;
import org.solovyev.common.text.NumberParser; import org.solovyev.common.text.NumberParser;
import org.solovyev.common.text.StringCollections; import org.solovyev.common.text.StringCollections;
import org.solovyev.common.text.Strings; import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class DirectionDragButton extends DragButton { public class DirectionDragButton extends DragButton {
@Nonnull @Nonnull
private final static Float DEFAULT_DIRECTION_TEXT_SCALE_FLOAT = 0.33f; private final static Float DEFAULT_DIRECTION_TEXT_SCALE_FLOAT = 0.33f;
@Nonnull @Nonnull
private final static Integer DEFAULT_DIRECTION_TEXT_ALPHA = 140; private final static Integer DEFAULT_DIRECTION_TEXT_ALPHA = 140;
private final static int DEFAULT_DIRECTION_TEXT_COLOR = Color.WHITE; private final static int DEFAULT_DIRECTION_TEXT_COLOR = Color.WHITE;
@Nonnull @Nonnull
private final static String DEFAULT_DIRECTION_TEXT_SCALE = "0.33;0.33;0.33;0.33"; private final static String DEFAULT_DIRECTION_TEXT_SCALE = "0.33;0.33;0.33;0.33";
@Nonnull
protected static class DirectionTextData { private final Map<GuiDragDirection, DirectionTextData> textDataMap = new EnumMap<>(GuiDragDirection.class);
@Nonnull
@Nonnull protected String directionTextScale = DEFAULT_DIRECTION_TEXT_SCALE;
private final GuiDragDirection direction; @Nonnull
protected Integer directionTextAlpha = DEFAULT_DIRECTION_TEXT_ALPHA;
@Nonnull protected int directionTextColor = DEFAULT_DIRECTION_TEXT_COLOR;
private String text; private boolean initialized = false;
@Nonnull public DirectionDragButton(Context context, @Nonnull AttributeSet attrs) {
private Point2d position; super(context, attrs);
init(context, attrs);
@Nonnull }
private final TextPaint paint = new TextPaint();
private void init(@Nonnull Context context, @Nonnull AttributeSet attrs) {
@Nonnull
private Float scale = 0.5f; TypedArray a = context.obtainStyledAttributes(attrs, org.solovyev.android.view.R.styleable.DirectionDragButton);
private boolean show = true; for (int i = 0; i < a.getIndexCount(); i++) {
int attr = a.getIndex(i);
private DirectionTextData(@Nonnull GuiDragDirection direction, @Nonnull String text) {
this.direction = direction; if (a.hasValue(attr)) {
this.text = text; if (attr == org.solovyev.android.view.R.styleable.DirectionDragButton_directionTextColor) {
} this.directionTextColor = a.getColor(attr, DEFAULT_DIRECTION_TEXT_COLOR);
} else if (attr == org.solovyev.android.view.R.styleable.DirectionDragButton_directionTextScale) {
protected void init(@Nonnull Paint basePaint, this.directionTextScale = a.getString(attr);
int color, } else if (attr == org.solovyev.android.view.R.styleable.DirectionDragButton_directionTextAlpha) {
int alpha) { this.directionTextAlpha = a.getInt(attr, DEFAULT_DIRECTION_TEXT_ALPHA);
paint.set(basePaint); } else {
paint.setColor(color); // try drag direction text
paint.setAlpha(alpha); for (GuiDragDirection guiDragDirection : GuiDragDirection.values()) {
paint.setTextSize(basePaint.getTextSize() * scale); if (guiDragDirection.getAttributeId() == attr) {
} this.textDataMap.put(guiDragDirection, new DirectionTextData(guiDragDirection, a.getString(attr)));
break;
@Nonnull }
public GuiDragDirection getDirection() { }
return direction; }
} }
}
@Nonnull
public String getText() { a.recycle();
return text;
} for (Map.Entry<GuiDragDirection, Float> entry : getDirectionTextScales().entrySet()) {
final DirectionTextData td = textDataMap.get(entry.getKey());
@Nonnull if (td != null) {
public Point2d getPosition() { td.scale = entry.getValue();
return position; }
} }
@Nonnull initialized = true;
public TextPaint getPaint() { }
return paint;
} @Override
public void onSizeChanged(int w, int h, int oldW, int oldH) {
@Nonnull measureText();
public Float getScale() { }
return scale;
} @Override
protected void onTextChanged(CharSequence text, int start, int before, int after) {
public boolean isShow() { measureText();
return show; }
}
} protected void measureText() {
if (initialized) {
public static enum GuiDragDirection { final Paint basePaint = getPaint();
up(DragDirection.up, 0) { for (DirectionTextData textData : textDataMap.values()) {
@Override initDirectionTextPaint(basePaint, textData);
public int getAttributeId() { textData.position = textData.direction.getTextPosition(textData.paint, basePaint, textData.text, getText(), getWidth(), getHeight());
return org.solovyev.android.view.R.styleable.DirectionDragButton_textUp; }
} invalidate();
}
@Nonnull }
@Override
public Point2d getTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, @Nonnull CharSequence text, CharSequence baseText, int w, int h) { protected void initDirectionTextPaint(@Nonnull Paint basePaint, @Nonnull DirectionTextData textData) {
return getUpDownTextPosition(paint, basePaint, text, baseText, 1, w, h); textData.init(basePaint, directionTextColor, directionTextAlpha);
} }
},
down(DragDirection.down, 2) { @Override
@Override public void onDraw(Canvas canvas) {
public int getAttributeId() { super.onDraw(canvas);
return org.solovyev.android.view.R.styleable.DirectionDragButton_textDown;
} final TextPaint paint = getPaint();
for (DirectionTextData td : textDataMap.values()) {
@Nonnull if (td.show) {
@Override initDirectionTextPaint(paint, td);
public Point2d getTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, @Nonnull CharSequence text, CharSequence baseText, int w, int h) { final String text = td.text;
return getUpDownTextPosition(paint, basePaint, text, baseText, -1, w, h); final Point2d position = td.position;
} canvas.drawText(text, 0, text.length(), position.getX(), position.getY(), td.paint);
}, }
left(DragDirection.left, 3) { }
@Override }
public int getAttributeId() {
return org.solovyev.android.view.R.styleable.DirectionDragButton_textLeft; @SuppressWarnings("UnusedDeclaration")
} @Nullable
public String getTextUp() {
@Nonnull return getText(GuiDragDirection.up);
@Override }
public Point2d getTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, @Nonnull CharSequence text, CharSequence baseText, int w, int h) {
return getLeftRightTextPosition(paint, basePaint, text, baseText, w, h, true); @SuppressWarnings("UnusedDeclaration")
} @Nullable
}, public String getTextDown() {
return getText(GuiDragDirection.down);
right(DragDirection.right, 1) { }
@Override
public int getAttributeId() { @Nullable
return org.solovyev.android.view.R.styleable.DirectionDragButton_textRight; public String getText(@Nonnull DragDirection direction) {
} final GuiDragDirection guiDragDirection = GuiDragDirection.valueOf(direction);
return guiDragDirection == null ? null : getText(guiDragDirection);
@Nonnull }
@Override
public Point2d getTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, @Nonnull CharSequence text, CharSequence baseText, int w, int h) { @SuppressWarnings("UnusedDeclaration")
return getLeftRightTextPosition(paint, basePaint, text, baseText, w, h, false); public void showDirectionText(boolean show, @Nonnull DragDirection direction) {
} final GuiDragDirection guiDragDirection = GuiDragDirection.valueOf(direction);
}; final DirectionTextData td = this.textDataMap.get(guiDragDirection);
if (td != null) {
@Nonnull td.show = show;
private final DragDirection dragDirection; }
}
private final int attributePosition;
public void setText(@Nullable String text, @Nonnull GuiDragDirection direction) {
GuiDragDirection(@Nonnull DragDirection dragDirection, int attributePosition) { if (!TextUtils.isEmpty(text)) {
this.dragDirection = dragDirection; final DirectionTextData data = new DirectionTextData(direction, text);
this.attributePosition = attributePosition; initDirectionTextPaint(getPaint(), data);
} textDataMap.put(direction, data);
} else {
public abstract int getAttributeId(); textDataMap.remove(direction);
}
public int getAttributePosition() { measureText();
return attributePosition; }
}
@Nullable
@Nonnull private String getText(@Nonnull GuiDragDirection direction) {
public abstract Point2d getTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, @Nonnull CharSequence text, CharSequence baseText, int w, int h); DirectionTextData td = textDataMap.get(direction);
if (td == null) {
@Nonnull return null;
private static Point2d getLeftRightTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, CharSequence text, @Nonnull CharSequence baseText, int w, int h, boolean left) { } else {
final Point2d result = new Point2d(); if (td.show) {
return td.text;
if (left) { } else {
float width = paint.measureText(" "); return null;
result.setX(width); }
} else { }
float width = paint.measureText(text.toString() + " "); }
result.setX(w - width);
} @Nonnull
public String getDirectionTextScale() {
float selfHeight = paint.ascent() + paint.descent(); return directionTextScale;
}
basePaint.measureText(Strings.getNotEmpty(baseText, "|"));
@Nonnull
result.setY(h / 2 - selfHeight / 2); private Map<GuiDragDirection, Float> getDirectionTextScales() {
final List<Float> scales = StringCollections.split(getDirectionTextScale(), ";", NumberParser.of(Float.class));
return result;
} final Map<GuiDragDirection, Float> result = new HashMap<>();
for (GuiDragDirection direction : GuiDragDirection.values()) {
@Nonnull result.put(direction, DEFAULT_DIRECTION_TEXT_SCALE_FLOAT);
private static Point2d getUpDownTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, @Nonnull CharSequence text, CharSequence baseText, float direction, int w, int h) { }
final Point2d result = new Point2d();
if (scales.size() == 1) {
float width = paint.measureText(text.toString() + " "); final Float scale = scales.get(0);
result.setX(w - width); for (Map.Entry<GuiDragDirection, Float> entry : result.entrySet()) {
entry.setValue(scale);
float selfHeight = paint.ascent() + paint.descent(); }
} else {
basePaint.measureText(Strings.getNotEmpty(baseText, "|")); for (int i = 0; i < scales.size(); i++) {
for (GuiDragDirection direction : GuiDragDirection.values()) {
if (direction < 0) { if (direction.getAttributePosition() == i) {
result.setY(h / 2 + h / 3 - selfHeight / 2); result.put(direction, scales.get(i));
} else { }
result.setY(h / 2 - h / 3 - selfHeight / 2); }
} }
}
return result;
} return result;
}
@Nullable
public static GuiDragDirection valueOf(@Nonnull DragDirection dragDirection) {
for (GuiDragDirection guiDragDirection : values()) { public static enum GuiDragDirection {
if (guiDragDirection.dragDirection == dragDirection) { up(DragDirection.up, 0) {
return guiDragDirection; @Override
} public int getAttributeId() {
} return org.solovyev.android.view.R.styleable.DirectionDragButton_textUp;
return null; }
}
} @Nonnull
@Override
@Nonnull public Point2d getTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, @Nonnull CharSequence text, CharSequence baseText, int w, int h) {
private final Map<GuiDragDirection, DirectionTextData> textDataMap = new EnumMap<>(GuiDragDirection.class); return getUpDownTextPosition(paint, basePaint, text, baseText, 1, w, h);
}
@Nonnull },
protected String directionTextScale = DEFAULT_DIRECTION_TEXT_SCALE; down(DragDirection.down, 2) {
@Override
@Nonnull public int getAttributeId() {
protected Integer directionTextAlpha = DEFAULT_DIRECTION_TEXT_ALPHA; return org.solovyev.android.view.R.styleable.DirectionDragButton_textDown;
}
protected int directionTextColor = DEFAULT_DIRECTION_TEXT_COLOR;
@Nonnull
private boolean initialized = false; @Override
public Point2d getTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, @Nonnull CharSequence text, CharSequence baseText, int w, int h) {
public DirectionDragButton(Context context, @Nonnull AttributeSet attrs) { return getUpDownTextPosition(paint, basePaint, text, baseText, -1, w, h);
super(context, attrs); }
init(context, attrs); },
} left(DragDirection.left, 3) {
@Override
private void init(@Nonnull Context context, @Nonnull AttributeSet attrs) { public int getAttributeId() {
return org.solovyev.android.view.R.styleable.DirectionDragButton_textLeft;
TypedArray a = context.obtainStyledAttributes(attrs, org.solovyev.android.view.R.styleable.DirectionDragButton); }
for (int i = 0; i < a.getIndexCount(); i++) { @Nonnull
int attr = a.getIndex(i); @Override
public Point2d getTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, @Nonnull CharSequence text, CharSequence baseText, int w, int h) {
if (a.hasValue(attr)) { return getLeftRightTextPosition(paint, basePaint, text, baseText, w, h, true);
if (attr == org.solovyev.android.view.R.styleable.DirectionDragButton_directionTextColor) { }
this.directionTextColor = a.getColor(attr, DEFAULT_DIRECTION_TEXT_COLOR); },
} else if (attr == org.solovyev.android.view.R.styleable.DirectionDragButton_directionTextScale) {
this.directionTextScale = a.getString(attr); right(DragDirection.right, 1) {
} else if (attr == org.solovyev.android.view.R.styleable.DirectionDragButton_directionTextAlpha) { @Override
this.directionTextAlpha = a.getInt(attr, DEFAULT_DIRECTION_TEXT_ALPHA); public int getAttributeId() {
} else { return org.solovyev.android.view.R.styleable.DirectionDragButton_textRight;
// try drag direction text }
for (GuiDragDirection guiDragDirection : GuiDragDirection.values()) {
if (guiDragDirection.getAttributeId() == attr) { @Nonnull
this.textDataMap.put(guiDragDirection, new DirectionTextData(guiDragDirection, a.getString(attr))); @Override
break; public Point2d getTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, @Nonnull CharSequence text, CharSequence baseText, int w, int h) {
} return getLeftRightTextPosition(paint, basePaint, text, baseText, w, h, false);
} }
} };
}
} @Nonnull
private final DragDirection dragDirection;
a.recycle();
private final int attributePosition;
for (Map.Entry<GuiDragDirection, Float> entry : getDirectionTextScales().entrySet()) {
final DirectionTextData td = textDataMap.get(entry.getKey()); GuiDragDirection(@Nonnull DragDirection dragDirection, int attributePosition) {
if (td != null) { this.dragDirection = dragDirection;
td.scale = entry.getValue(); this.attributePosition = attributePosition;
} }
}
@Nonnull
initialized = true; private static Point2d getLeftRightTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, CharSequence text, @Nonnull CharSequence baseText, int w, int h, boolean left) {
} final Point2d result = new Point2d();
@Override if (left) {
public void onSizeChanged(int w, int h, int oldW, int oldH) { float width = paint.measureText(" ");
measureText(); result.setX(width);
} } else {
float width = paint.measureText(text.toString() + " ");
@Override result.setX(w - width);
protected void onTextChanged(CharSequence text, int start, int before, int after) { }
measureText();
} float selfHeight = paint.ascent() + paint.descent();
protected void measureText() { basePaint.measureText(Strings.getNotEmpty(baseText, "|"));
if (initialized) {
final Paint basePaint = getPaint(); result.setY(h / 2 - selfHeight / 2);
for (DirectionTextData textData : textDataMap.values()) {
initDirectionTextPaint(basePaint, textData); return result;
textData.position = textData.direction.getTextPosition(textData.paint, basePaint, textData.text, getText(), getWidth(), getHeight()); }
}
invalidate(); @Nonnull
} private static Point2d getUpDownTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, @Nonnull CharSequence text, CharSequence baseText, float direction, int w, int h) {
} final Point2d result = new Point2d();
protected void initDirectionTextPaint(@Nonnull Paint basePaint, @Nonnull DirectionTextData textData) { float width = paint.measureText(text.toString() + " ");
textData.init(basePaint, directionTextColor, directionTextAlpha); result.setX(w - width);
}
float selfHeight = paint.ascent() + paint.descent();
@Override
public void onDraw(Canvas canvas) { basePaint.measureText(Strings.getNotEmpty(baseText, "|"));
super.onDraw(canvas);
if (direction < 0) {
final TextPaint paint = getPaint(); result.setY(h / 2 + h / 3 - selfHeight / 2);
for (DirectionTextData td : textDataMap.values()) { } else {
if (td.show) { result.setY(h / 2 - h / 3 - selfHeight / 2);
initDirectionTextPaint(paint, td); }
final String text = td.text;
final Point2d position = td.position; return result;
canvas.drawText(text, 0, text.length(), position.getX(), position.getY(), td.paint); }
}
} @Nullable
} public static GuiDragDirection valueOf(@Nonnull DragDirection dragDirection) {
for (GuiDragDirection guiDragDirection : values()) {
@SuppressWarnings("UnusedDeclaration") if (guiDragDirection.dragDirection == dragDirection) {
@Nullable return guiDragDirection;
public String getTextUp() { }
return getText(GuiDragDirection.up); }
} return null;
}
@SuppressWarnings("UnusedDeclaration")
@Nullable public abstract int getAttributeId();
public String getTextDown() {
return getText(GuiDragDirection.down); public int getAttributePosition() {
} return attributePosition;
}
@Nullable
public String getText(@Nonnull DragDirection direction) { @Nonnull
final GuiDragDirection guiDragDirection = GuiDragDirection.valueOf(direction); public abstract Point2d getTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, @Nonnull CharSequence text, CharSequence baseText, int w, int h);
return guiDragDirection == null ? null : getText(guiDragDirection); }
}
protected static class DirectionTextData {
@SuppressWarnings("UnusedDeclaration")
public void showDirectionText(boolean show, @Nonnull DragDirection direction) { @Nonnull
final GuiDragDirection guiDragDirection = GuiDragDirection.valueOf(direction); private final GuiDragDirection direction;
final DirectionTextData td = this.textDataMap.get(guiDragDirection); @Nonnull
if (td != null) { private final TextPaint paint = new TextPaint();
td.show = show; @Nonnull
} private String text;
} @Nonnull
private Point2d position;
public void setText(@Nullable String text, @Nonnull GuiDragDirection direction) { @Nonnull
if (!TextUtils.isEmpty(text)) { private Float scale = 0.5f;
final DirectionTextData data = new DirectionTextData(direction, text);
initDirectionTextPaint(getPaint(), data); private boolean show = true;
textDataMap.put(direction, data);
} else { private DirectionTextData(@Nonnull GuiDragDirection direction, @Nonnull String text) {
textDataMap.remove(direction); this.direction = direction;
} this.text = text;
measureText(); }
}
protected void init(@Nonnull Paint basePaint,
@Nullable int color,
private String getText(@Nonnull GuiDragDirection direction) { int alpha) {
DirectionTextData td = textDataMap.get(direction); paint.set(basePaint);
if (td == null) { paint.setColor(color);
return null; paint.setAlpha(alpha);
} else { paint.setTextSize(basePaint.getTextSize() * scale);
if (td.show) { }
return td.text;
} else { @Nonnull
return null; public GuiDragDirection getDirection() {
} return direction;
} }
}
@Nonnull
public String getText() {
@Nonnull return text;
public String getDirectionTextScale() { }
return directionTextScale;
} @Nonnull
public Point2d getPosition() {
@Nonnull return position;
private Map<GuiDragDirection, Float> getDirectionTextScales() { }
final List<Float> scales = StringCollections.split(getDirectionTextScale(), ";", NumberParser.of(Float.class));
@Nonnull
final Map<GuiDragDirection, Float> result = new HashMap<>(); public TextPaint getPaint() {
for (GuiDragDirection direction : GuiDragDirection.values()) { return paint;
result.put(direction, DEFAULT_DIRECTION_TEXT_SCALE_FLOAT); }
}
@Nonnull
if (scales.size() == 1) { public Float getScale() {
final Float scale = scales.get(0); return scale;
for (Map.Entry<GuiDragDirection, Float> entry : result.entrySet()) { }
entry.setValue(scale);
} public boolean isShow() {
} else { return show;
for (int i = 0; i < scales.size(); i++) { }
for (GuiDragDirection direction : GuiDragDirection.values()) { }
if (direction.getAttributePosition() == i) {
result.put(direction, scales.get(i));
}
}
}
}
return result;
}
} }

View File

@ -25,9 +25,9 @@ package org.solovyev.android.calculator.drag;
import android.content.Context; import android.content.Context;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.widget.Button; import android.widget.Button;
import org.solovyev.android.view.AndroidViewUtils; import org.solovyev.android.view.AndroidViewUtils;
import org.solovyev.common.math.Point2d; import org.solovyev.common.math.Point2d;
import org.solovyev.common.text.Strings; import org.solovyev.common.text.Strings;
@ -37,96 +37,96 @@ import javax.annotation.Nullable;
public class DragButton extends Button { public class DragButton extends Button {
@Nullable @Nullable
private Point2d startPoint = null; private Point2d startPoint = null;
@Nullable @Nullable
private DragListener onDragListener; private DragListener onDragListener;
private boolean showText = true; private boolean showText = true;
@Nullable @Nullable
private CharSequence textBackup; private CharSequence textBackup;
public DragButton(@Nonnull Context context, @Nonnull AttributeSet attrs) { public DragButton(@Nonnull Context context, @Nonnull AttributeSet attrs) {
super(context, attrs); super(context, attrs);
} }
public void setOnDragListener(@Nullable DragListener onDragListener) { public void setOnDragListener(@Nullable DragListener onDragListener) {
this.onDragListener = onDragListener; this.onDragListener = onDragListener;
} }
@Override @Override
public boolean onTouchEvent(@Nonnull MotionEvent event) { public boolean onTouchEvent(@Nonnull MotionEvent event) {
boolean consumed = false; boolean consumed = false;
// in order to avoid possible NPEs // in order to avoid possible NPEs
final Point2d localStartPoint = startPoint; final Point2d localStartPoint = startPoint;
final DragListener localOnDragListener = onDragListener; final DragListener localOnDragListener = onDragListener;
if (localOnDragListener != null) { if (localOnDragListener != null) {
// only if onDrag() listener specified // only if onDrag() listener specified
switch (event.getAction()) { switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_DOWN:
// start tracking: set start point // start tracking: set start point
startPoint = new Point2d(event.getX(), event.getY()); startPoint = new Point2d(event.getX(), event.getY());
break; break;
case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: case MotionEvent.ACTION_UP:
// stop tracking // stop tracking
startPoint = null; startPoint = null;
if (localStartPoint != null) { if (localStartPoint != null) {
consumed = localOnDragListener.onDrag(DragButton.this, new DragEvent(localStartPoint, event)); consumed = localOnDragListener.onDrag(DragButton.this, new DragEvent(localStartPoint, event));
if (consumed && localOnDragListener.isSuppressOnClickEvent()) { if (consumed && localOnDragListener.isSuppressOnClickEvent()) {
final MotionEvent newEvent = MotionEvent.obtain(event); final MotionEvent newEvent = MotionEvent.obtain(event);
newEvent.setAction(MotionEvent.ACTION_CANCEL); newEvent.setAction(MotionEvent.ACTION_CANCEL);
super.onTouchEvent(newEvent); super.onTouchEvent(newEvent);
newEvent.recycle(); newEvent.recycle();
return true; return true;
} }
} }
break; break;
} }
} }
return super.onTouchEvent(event) || consumed; return super.onTouchEvent(event) || consumed;
} }
@Override @Override
public boolean dispatchTouchEvent(@Nonnull MotionEvent event) { public boolean dispatchTouchEvent(@Nonnull MotionEvent event) {
return super.dispatchTouchEvent(event); return super.dispatchTouchEvent(event);
} }
@Override @Override
protected void onDraw(Canvas canvas) { protected void onDraw(Canvas canvas) {
CharSequence text = getText(); CharSequence text = getText();
if (!Strings.isEmpty(text)) { if (!Strings.isEmpty(text)) {
super.onDraw(canvas); super.onDraw(canvas);
} else { } else {
if (!AndroidViewUtils.drawDrawables(canvas, this)) { if (!AndroidViewUtils.drawDrawables(canvas, this)) {
super.onDraw(canvas); super.onDraw(canvas);
} }
} }
} }
public boolean isShowText() { public boolean isShowText() {
return showText; return showText;
} }
public void setShowText(boolean showText) { public void setShowText(boolean showText) {
if (this.showText != showText) { if (this.showText != showText) {
if (showText) { if (showText) {
setText(textBackup); setText(textBackup);
textBackup = null; textBackup = null;
} else { } else {
textBackup = this.getText(); textBackup = this.getText();
setText(null); setText(null);
} }
this.showText = showText; this.showText = showText;
} }
} }
} }

View File

@ -24,8 +24,8 @@ package org.solovyev.android.calculator.drag;
public enum DragDirection { public enum DragDirection {
up, up,
down, down,
left, left,
right; right;
} }

View File

@ -23,38 +23,39 @@
package org.solovyev.android.calculator.drag; package org.solovyev.android.calculator.drag;
import android.view.MotionEvent; import android.view.MotionEvent;
import org.solovyev.common.math.Point2d; import org.solovyev.common.math.Point2d;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
public class DragEvent { public class DragEvent {
@Nonnull @Nonnull
private final Point2d startPoint; private final Point2d startPoint;
@Nonnull @Nonnull
private final MotionEvent motionEvent; private final MotionEvent motionEvent;
public DragEvent(@Nonnull Point2d startPoint, @Nonnull MotionEvent motionEvent) { public DragEvent(@Nonnull Point2d startPoint, @Nonnull MotionEvent motionEvent) {
this.startPoint = startPoint; this.startPoint = startPoint;
this.motionEvent = motionEvent; this.motionEvent = motionEvent;
} }
/** /**
* @return motion event started at start point * @return motion event started at start point
*/ */
@Nonnull @Nonnull
public MotionEvent getMotionEvent() { public MotionEvent getMotionEvent() {
return motionEvent; return motionEvent;
} }
/** /**
* @return start point of dragging * @return start point of dragging
*/ */
@Nonnull @Nonnull
public Point2d getStartPoint() { public Point2d getStartPoint() {
return startPoint; return startPoint;
} }
} }

View File

@ -22,22 +22,23 @@
package org.solovyev.android.calculator.drag; package org.solovyev.android.calculator.drag;
import javax.annotation.Nonnull;
import java.util.EventListener; import java.util.EventListener;
import javax.annotation.Nonnull;
public interface DragListener extends EventListener { public interface DragListener extends EventListener {
/** /**
* @return 'true': if drag event has taken place (i.e. onDrag() method returned true) then click action will be suppresed * @return 'true': if drag event has taken place (i.e. onDrag() method returned true) then click action will be suppresed
*/ */
boolean isSuppressOnClickEvent(); boolean isSuppressOnClickEvent();
/** /**
* @param dragButton drag button object for which onDrag listener was set * @param dragButton drag button object for which onDrag listener was set
* @param event drag event * @param event drag event
* @return 'true' if drag event occurred, 'false' otherwise * @return 'true' if drag event occurred, 'false' otherwise
*/ */
boolean onDrag(@Nonnull DragButton dragButton, @Nonnull DragEvent event); boolean onDrag(@Nonnull DragButton dragButton, @Nonnull DragEvent event);
} }

View File

@ -31,20 +31,20 @@ import javax.annotation.Nonnull;
*/ */
public class DragListenerWrapper implements DragListener { public class DragListenerWrapper implements DragListener {
@Nonnull @Nonnull
private final DragListener dragListener; private final DragListener dragListener;
public DragListenerWrapper(@Nonnull DragListener dragListener) { public DragListenerWrapper(@Nonnull DragListener dragListener) {
this.dragListener = dragListener; this.dragListener = dragListener;
} }
@Override @Override
public boolean isSuppressOnClickEvent() { public boolean isSuppressOnClickEvent() {
return this.dragListener.isSuppressOnClickEvent(); return this.dragListener.isSuppressOnClickEvent();
} }
@Override @Override
public boolean onDrag(@Nonnull DragButton dragButton, @Nonnull DragEvent event) { public boolean onDrag(@Nonnull DragButton dragButton, @Nonnull DragEvent event) {
return this.dragListener.onDrag(dragButton, event); return this.dragListener.onDrag(dragButton, event);
} }
} }

View File

@ -23,9 +23,7 @@
package org.solovyev.android.calculator.drag; package org.solovyev.android.calculator.drag;
import android.content.Context; import android.content.Context;
import android.support.v4.view.ViewConfigurationCompat;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.ViewConfiguration;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import org.solovyev.common.MutableObject; import org.solovyev.common.MutableObject;
@ -34,109 +32,109 @@ import org.solovyev.common.interval.Intervals;
import org.solovyev.common.math.Maths; import org.solovyev.common.math.Maths;
import org.solovyev.common.math.Point2d; import org.solovyev.common.math.Point2d;
import java.util.EnumMap;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.EnumMap;
public class SimpleDragListener implements DragListener { public class SimpleDragListener implements DragListener {
@Nonnull @Nonnull
private static final Point2d axis = new Point2d(0, 1); private static final Point2d axis = new Point2d(0, 1);
@Nonnull @Nonnull
private static final EnumMap<DragDirection, Interval<Float>> sAngleIntervals = new EnumMap<>(DragDirection.class); private static final EnumMap<DragDirection, Interval<Float>> sAngleIntervals = new EnumMap<>(DragDirection.class);
static { static {
for (DragDirection direction : DragDirection.values()) { for (DragDirection direction : DragDirection.values()) {
sAngleIntervals.put(direction, makeAngleInterval(direction, 0, 45)); sAngleIntervals.put(direction, makeAngleInterval(direction, 0, 45));
} }
} }
@Nonnull @Nonnull
private final DragProcessor processor; private final DragProcessor processor;
private final float minDistancePxs; private final float minDistancePxs;
public SimpleDragListener(@Nonnull DragProcessor processor, @Nonnull Context context) { public SimpleDragListener(@Nonnull DragProcessor processor, @Nonnull Context context) {
this.processor = processor; this.processor = processor;
this.minDistancePxs = context.getResources().getDimensionPixelSize(R.dimen.cpp_min_drag_distance); this.minDistancePxs = context.getResources().getDimensionPixelSize(R.dimen.cpp_min_drag_distance);
} }
@Override @Nonnull
public boolean onDrag(@Nonnull DragButton dragButton, @Nonnull DragEvent event) { private static Interval<Float> makeAngleInterval(@Nonnull DragDirection direction,
boolean consumed = false; float leftLimit,
float rightLimit) {
final Float newLeftLimit;
final Float newRightLimit;
switch (direction) {
case up:
newLeftLimit = 180f - rightLimit;
newRightLimit = 180f - leftLimit;
break;
case down:
newLeftLimit = leftLimit;
newRightLimit = rightLimit;
break;
case left:
newLeftLimit = 90f - rightLimit;
newRightLimit = 90f + rightLimit;
break;
case right:
newLeftLimit = 90f - rightLimit;
newRightLimit = 90f + rightLimit;
break;
default:
throw new AssertionError();
}
final MotionEvent motionEvent = event.getMotionEvent(); return Intervals.newClosedInterval(newLeftLimit, newRightLimit);
}
final Point2d start = event.getStartPoint(); @Override
final Point2d end = new Point2d(motionEvent.getX(), motionEvent.getY()); public boolean onDrag(@Nonnull DragButton dragButton, @Nonnull DragEvent event) {
final float distance = Maths.getDistance(start, end); boolean consumed = false;
final MutableObject<Boolean> right = new MutableObject<>(); final MotionEvent motionEvent = event.getMotionEvent();
final double angle = Math.toDegrees(Maths.getAngle(start, Maths.sum(start, axis), end, right));
final long duration = motionEvent.getEventTime() - motionEvent.getDownTime(); final Point2d start = event.getStartPoint();
final DragDirection direction = getDirection(distance, (float) angle, right.getObject()); final Point2d end = new Point2d(motionEvent.getX(), motionEvent.getY());
if (direction != null && duration > 40 && duration < 2500) { final float distance = Maths.getDistance(start, end);
consumed = processor.processDragEvent(direction, dragButton, start, motionEvent);
}
return consumed; final MutableObject<Boolean> right = new MutableObject<>();
} final double angle = Math.toDegrees(Maths.getAngle(start, Maths.sum(start, axis), end, right));
@Nullable final long duration = motionEvent.getEventTime() - motionEvent.getDownTime();
private DragDirection getDirection(float distance, float angle, boolean right) { final DragDirection direction = getDirection(distance, (float) angle, right.getObject());
if (distance > minDistancePxs) { if (direction != null && duration > 40 && duration < 2500) {
for (DragDirection direction : DragDirection.values()) { consumed = processor.processDragEvent(direction, dragButton, start, motionEvent);
final Interval<Float> angleInterval = sAngleIntervals.get(direction); }
final boolean wrongDirection = (direction == DragDirection.left && right) ||
(direction == DragDirection.right && !right);
if (!wrongDirection && angleInterval.contains(angle)) {
return direction;
}
}
}
return null;
}
@Override return consumed;
public boolean isSuppressOnClickEvent() { }
return true;
}
public interface DragProcessor { @Nullable
private DragDirection getDirection(float distance, float angle, boolean right) {
if (distance > minDistancePxs) {
for (DragDirection direction : DragDirection.values()) {
final Interval<Float> angleInterval = sAngleIntervals.get(direction);
final boolean wrongDirection = (direction == DragDirection.left && right) ||
(direction == DragDirection.right && !right);
if (!wrongDirection && angleInterval.contains(angle)) {
return direction;
}
}
}
return null;
}
boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent); @Override
} public boolean isSuppressOnClickEvent() {
return true;
}
@Nonnull public interface DragProcessor {
private static Interval<Float> makeAngleInterval(@Nonnull DragDirection direction,
float leftLimit,
float rightLimit) {
final Float newLeftLimit;
final Float newRightLimit;
switch (direction) {
case up:
newLeftLimit = 180f - rightLimit;
newRightLimit = 180f - leftLimit;
break;
case down:
newLeftLimit = leftLimit;
newRightLimit = rightLimit;
break;
case left:
newLeftLimit = 90f - rightLimit;
newRightLimit = 90f + rightLimit;
break;
case right:
newLeftLimit = 90f - rightLimit;
newRightLimit = 90f + rightLimit;
break;
default:
throw new AssertionError();
}
return Intervals.newClosedInterval(newLeftLimit, newRightLimit); boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent);
} }
} }

View File

@ -34,23 +34,33 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.EditText; import android.widget.EditText;
import jscl.math.Generic;
import jscl.math.function.Constant; import org.solovyev.android.calculator.App;
import jscl.math.function.CustomFunction; import org.solovyev.android.calculator.CalculatorDisplayViewState;
import jscl.math.function.Function; import org.solovyev.android.calculator.CalculatorEventData;
import jscl.math.function.IFunction; import org.solovyev.android.calculator.CalculatorEventListener;
import org.solovyev.android.calculator.*; import org.solovyev.android.calculator.CalculatorEventType;
import org.solovyev.android.calculator.CalculatorUtils;
import org.solovyev.android.calculator.Locator;
import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.math.edit.CalculatorFunctionsActivity; import org.solovyev.android.calculator.math.edit.CalculatorFunctionsActivity;
import org.solovyev.android.calculator.math.edit.CalculatorFunctionsFragment; import org.solovyev.android.calculator.math.edit.CalculatorFunctionsFragment;
import org.solovyev.android.calculator.math.edit.MathEntityRemover; import org.solovyev.android.calculator.math.edit.MathEntityRemover;
import org.solovyev.android.calculator.model.AFunction; import org.solovyev.android.calculator.model.AFunction;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.math.Generic;
import jscl.math.function.Constant;
import jscl.math.function.CustomFunction;
import jscl.math.function.Function;
import jscl.math.function.IFunction;
/** /**
* User: serso * User: serso
* Date: 11/13/12 * Date: 11/13/12
@ -58,306 +68,300 @@ import java.util.Set;
*/ */
public class FunctionEditDialogFragment extends DialogFragment implements CalculatorEventListener { public class FunctionEditDialogFragment extends DialogFragment implements CalculatorEventListener {
private static final String INPUT = "input"; private static final String INPUT = "input";
private Input input; private Input input;
public FunctionEditDialogFragment() { public FunctionEditDialogFragment() {
} }
@Nonnull @Nonnull
public static FunctionEditDialogFragment create(@Nonnull Input input) { public static FunctionEditDialogFragment create(@Nonnull Input input) {
final FunctionEditDialogFragment fragment = new FunctionEditDialogFragment(); final FunctionEditDialogFragment fragment = new FunctionEditDialogFragment();
fragment.input = input; fragment.input = input;
final Bundle args = new Bundle(); final Bundle args = new Bundle();
args.putParcelable("input", input); args.putParcelable("input", input);
fragment.setArguments(args); fragment.setArguments(args);
return fragment; return fragment;
} }
@Override public static void showDialog(@Nonnull Input input, @Nonnull Context context) {
public void onCreate(Bundle savedInstanceState) { if (context instanceof ActionBarActivity) {
super.onCreate(savedInstanceState); FunctionEditDialogFragment.showDialog(input, ((ActionBarActivity) context).getSupportFragmentManager());
} else {
final Intent intent = new Intent(context, CalculatorFunctionsActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(CalculatorFunctionsFragment.CREATE_FUNCTION_EXTRA, input);
context.startActivity(intent);
}
}
if (input == null) { public static void showDialog(@Nonnull Input input, @Nonnull FragmentManager fm) {
input = getArguments().getParcelable("input"); App.showDialog(create(input), "function-editor", fm);
if (input == null) throw new AssertionError(); }
}
}
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
final View result = inflater.inflate(R.layout.function_edit, container, false); super.onCreate(savedInstanceState);
if (savedInstanceState != null) { if (input == null) {
final Parcelable input = savedInstanceState.getParcelable(INPUT); input = getArguments().getParcelable("input");
if (input instanceof Input) { if (input == null) throw new AssertionError();
this.input = (Input) input; }
} }
}
return result; @Override
} public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View result = inflater.inflate(R.layout.function_edit, container, false);
@Override if (savedInstanceState != null) {
public void onViewCreated(@Nonnull View root, Bundle savedInstanceState) { final Parcelable input = savedInstanceState.getParcelable(INPUT);
super.onViewCreated(root, savedInstanceState); if (input instanceof Input) {
this.input = (Input) input;
}
}
final FunctionParamsView paramsView = (FunctionParamsView) root.findViewById(R.id.function_params_layout); return result;
}
final AFunction.Builder builder; @Override
final AFunction function = input.getFunction(); public void onViewCreated(@Nonnull View root, Bundle savedInstanceState) {
if (function != null) { super.onViewCreated(root, savedInstanceState);
builder = new AFunction.Builder(function);
} else {
builder = new AFunction.Builder();
}
final List<String> parameterNames = input.getParameterNames(); final FunctionParamsView paramsView = (FunctionParamsView) root.findViewById(R.id.function_params_layout);
if (parameterNames != null) {
paramsView.init(parameterNames);
} else {
paramsView.init();
}
final EditText editName = (EditText) root.findViewById(R.id.function_edit_name); final AFunction.Builder builder;
// show soft keyboard automatically final AFunction function = input.getFunction();
editName.requestFocus(); if (function != null) {
editName.setText(input.getName()); builder = new AFunction.Builder(function);
} else {
builder = new AFunction.Builder();
}
final EditText editDescription = (EditText) root.findViewById(R.id.function_edit_description); final List<String> parameterNames = input.getParameterNames();
editDescription.setText(input.getDescription()); if (parameterNames != null) {
paramsView.init(parameterNames);
} else {
paramsView.init();
}
final EditText editContent = (EditText) root.findViewById(R.id.function_edit_value); final EditText editName = (EditText) root.findViewById(R.id.function_edit_name);
editContent.setText(input.getContent()); // show soft keyboard automatically
editName.requestFocus();
editName.setText(input.getName());
root.findViewById(R.id.cancel_button).setOnClickListener(new View.OnClickListener() { final EditText editDescription = (EditText) root.findViewById(R.id.function_edit_description);
@Override editDescription.setText(input.getDescription());
public void onClick(View v) {
dismiss();
}
});
root.findViewById(R.id.save_button).setOnClickListener(new FunctionEditorSaver(builder, function, root, Locator.getInstance().getEngine().getFunctionsRegistry(), this)); final EditText editContent = (EditText) root.findViewById(R.id.function_edit_value);
editContent.setText(input.getContent());
if (function == null) { root.findViewById(R.id.cancel_button).setOnClickListener(new View.OnClickListener() {
// CREATE MODE @Override
getDialog().setTitle(R.string.function_create_function); public void onClick(View v) {
dismiss();
}
});
root.findViewById(R.id.remove_button).setVisibility(View.GONE); root.findViewById(R.id.save_button).setOnClickListener(new FunctionEditorSaver(builder, function, root, Locator.getInstance().getEngine().getFunctionsRegistry(), this));
} else {
// EDIT MODE
getDialog().setTitle(R.string.function_edit_function);
final Function customFunction = new CustomFunction.Builder(function).create(); if (function == null) {
root.findViewById(R.id.remove_button).setOnClickListener(MathEntityRemover.newFunctionRemover(customFunction, null, this.getActivity(), FunctionEditDialogFragment.this)); // CREATE MODE
} getDialog().setTitle(R.string.function_create_function);
}
@Override root.findViewById(R.id.remove_button).setVisibility(View.GONE);
public void onSaveInstanceState(@Nonnull Bundle out) { } else {
super.onSaveInstanceState(out); // EDIT MODE
getDialog().setTitle(R.string.function_edit_function);
out.putParcelable(INPUT, FunctionEditorSaver.readInput(input.getFunction(), getView())); final Function customFunction = new CustomFunction.Builder(function).create();
} root.findViewById(R.id.remove_button).setOnClickListener(MathEntityRemover.newFunctionRemover(customFunction, null, this.getActivity(), FunctionEditDialogFragment.this));
}
}
@Override @Override
public void onResume() { public void onSaveInstanceState(@Nonnull Bundle out) {
super.onResume(); super.onSaveInstanceState(out);
Locator.getInstance().getCalculator().addCalculatorEventListener(this); out.putParcelable(INPUT, FunctionEditorSaver.readInput(input.getFunction(), getView()));
} }
@Override @Override
public void onPause() { public void onResume() {
Locator.getInstance().getCalculator().removeCalculatorEventListener(this); super.onResume();
super.onPause(); Locator.getInstance().getCalculator().addCalculatorEventListener(this);
} }
@Override
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
switch (calculatorEventType) {
case function_removed:
case function_added:
case function_changed:
if (calculatorEventData.getSource() == FunctionEditDialogFragment.this) {
dismiss();
}
break;
}
}
/* /*
********************************************************************** **********************************************************************
* *
* STATIC * STATIC
* *
********************************************************************** **********************************************************************
*/ */
public static void showDialog(@Nonnull Input input, @Nonnull Context context) { @Override
if (context instanceof ActionBarActivity) { public void onPause() {
FunctionEditDialogFragment.showDialog(input, ((ActionBarActivity) context).getSupportFragmentManager()); Locator.getInstance().getCalculator().removeCalculatorEventListener(this);
} else {
final Intent intent = new Intent(context, CalculatorFunctionsActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(CalculatorFunctionsFragment.CREATE_FUNCTION_EXTRA, input);
context.startActivity(intent);
}
}
public static void showDialog(@Nonnull Input input, @Nonnull FragmentManager fm) { super.onPause();
App.showDialog(create(input), "function-editor", fm); }
}
public static class Input implements Parcelable { @Override
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
switch (calculatorEventType) {
case function_removed:
case function_added:
case function_changed:
if (calculatorEventData.getSource() == FunctionEditDialogFragment.this) {
dismiss();
}
break;
public static final Parcelable.Creator<Input> CREATOR = new Creator<Input>() { }
@Override }
public Input createFromParcel(@Nonnull Parcel in) {
return Input.fromParcel(in);
}
@Override public static class Input implements Parcelable {
public Input[] newArray(int size) {
return new Input[size];
}
};
private static final Parcelable.Creator<String> STRING_CREATOR = new Creator<String>() { private static final Parcelable.Creator<String> STRING_CREATOR = new Creator<String>() {
@Override @Override
public String createFromParcel(@Nonnull Parcel in) { public String createFromParcel(@Nonnull Parcel in) {
return in.readString(); return in.readString();
} }
@Override @Override
public String[] newArray(int size) { public String[] newArray(int size) {
return new String[size]; return new String[size];
} }
}; };
@Nullable
private AFunction function;
@Nullable
private String name;
@Nullable
private String content;
@Nullable
private String description;
@Nullable
private List<String> parameterNames;
public static final Parcelable.Creator<Input> CREATOR = new Creator<Input>() {
@Override
public Input createFromParcel(@Nonnull Parcel in) {
return Input.fromParcel(in);
}
@Nonnull @Override
private static Input fromParcel(@Nonnull Parcel in) { public Input[] newArray(int size) {
final Input result = new Input(); return new Input[size];
result.name = in.readString(); }
result.content = in.readString(); };
result.description = in.readString();
final List<String> parameterNames = new ArrayList<String>(); private Input() {
in.readTypedList(parameterNames, STRING_CREATOR); }
result.parameterNames = parameterNames;
result.function = (AFunction) in.readSerializable(); @Nonnull
private static Input fromParcel(@Nonnull Parcel in) {
final Input result = new Input();
result.name = in.readString();
result.content = in.readString();
result.description = in.readString();
return result; final List<String> parameterNames = new ArrayList<String>();
} in.readTypedList(parameterNames, STRING_CREATOR);
result.parameterNames = parameterNames;
@Nullable result.function = (AFunction) in.readSerializable();
private AFunction function;
@Nullable return result;
private String name; }
@Nullable @Nonnull
private String content; public static Input newInstance() {
return new Input();
}
@Nullable @Nonnull
private String description; public static Input newFromFunction(@Nonnull IFunction function) {
final Input result = new Input();
result.function = AFunction.fromIFunction(function);
return result;
}
@Nullable @Nonnull
private List<String> parameterNames; public static Input newInstance(@Nullable IFunction function,
@Nullable String name,
@Nullable String value,
@Nullable String description,
@Nonnull List<String> parameterNames) {
private Input() { final Input result = new Input();
} if (function != null) {
result.function = AFunction.fromIFunction(function);
}
result.name = name;
result.content = value;
result.description = description;
result.parameterNames = new ArrayList<String>(parameterNames);
@Nonnull return result;
public static Input newInstance() { }
return new Input();
}
@Nonnull @Nonnull
public static Input newFromFunction(@Nonnull IFunction function) { public static Input newFromDisplay(@Nonnull CalculatorDisplayViewState viewState) {
final Input result = new Input(); final Input result = new Input();
result.function = AFunction.fromIFunction(function);
return result;
}
@Nonnull result.content = viewState.getText();
public static Input newInstance(@Nullable IFunction function, final Generic generic = viewState.getResult();
@Nullable String name, if (generic != null) {
@Nullable String value, final Set<Constant> constants = CalculatorUtils.getNotSystemConstants(generic);
@Nullable String description, final List<String> parameterNames = new ArrayList<String>(constants.size());
@Nonnull List<String> parameterNames) { for (Constant constant : constants) {
parameterNames.add(constant.getName());
}
result.parameterNames = parameterNames;
}
final Input result = new Input(); return result;
if (function != null) { }
result.function = AFunction.fromIFunction(function);
}
result.name = name;
result.content = value;
result.description = description;
result.parameterNames = new ArrayList<String>(parameterNames);
return result; @Nullable
} public AFunction getFunction() {
return function;
}
@Nullable @Nullable
public AFunction getFunction() { public String getName() {
return function; return name == null ? (function == null ? null : function.getName()) : name;
} }
@Nullable @Nullable
public String getName() { public String getContent() {
return name == null ? (function == null ? null : function.getName()) : name; return content == null ? (function == null ? null : function.getContent()) : content;
} }
@Nullable @Nullable
public String getContent() { public String getDescription() {
return content == null ? (function == null ? null : function.getContent()) : content; return description == null ? (function == null ? null : function.getDescription()) : description;
} }
@Nullable @Nullable
public String getDescription() { public List<String> getParameterNames() {
return description == null ? (function == null ? null : function.getDescription()) : description; return parameterNames == null ? (function == null ? null : function.getParameterNames()) : parameterNames;
} }
@Nullable @Override
public List<String> getParameterNames() { public int describeContents() {
return parameterNames == null ? (function == null ? null : function.getParameterNames()) : parameterNames; return 0;
} }
@Override @Override
public int describeContents() { public void writeToParcel(@Nonnull Parcel out, int flags) {
return 0; out.writeString(name);
} out.writeString(content);
out.writeString(description);
@Override out.writeList(parameterNames);
public void writeToParcel(@Nonnull Parcel out, int flags) { out.writeSerializable(function);
out.writeString(name); }
out.writeString(content); }
out.writeString(description);
out.writeList(parameterNames);
out.writeSerializable(function);
}
@Nonnull
public static Input newFromDisplay(@Nonnull CalculatorDisplayViewState viewState) {
final Input result = new Input();
result.content = viewState.getText();
final Generic generic = viewState.getResult();
if (generic != null) {
final Set<Constant> constants = CalculatorUtils.getNotSystemConstants(generic);
final List<String> parameterNames = new ArrayList<String>(constants.size());
for (Constant constant : constants) {
parameterNames.add(constant.getName());
}
result.parameterNames = parameterNames;
}
return result;
}
}
} }

View File

@ -24,12 +24,6 @@ package org.solovyev.android.calculator.function;
import android.view.View; import android.view.View;
import android.widget.EditText; import android.widget.EditText;
import jscl.CustomFunctionCalculationException;
import jscl.math.function.Function;
import jscl.math.function.IFunction;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.solovyev.android.calculator.CalculatorFunctionsMathRegistry; import org.solovyev.android.calculator.CalculatorFunctionsMathRegistry;
import org.solovyev.android.calculator.CalculatorMathRegistry; import org.solovyev.android.calculator.CalculatorMathRegistry;
@ -43,123 +37,130 @@ import org.solovyev.common.text.Strings;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.CustomFunctionCalculationException;
import jscl.math.function.Function;
import jscl.math.function.IFunction;
public class FunctionEditorSaver implements View.OnClickListener { public class FunctionEditorSaver implements View.OnClickListener {
@Nonnull @Nonnull
private final Object source; private final Object source;
@Nonnull @Nonnull
private final AFunction.Builder builder; private final AFunction.Builder builder;
@Nullable @Nullable
private final IFunction editedInstance; private final IFunction editedInstance;
@Nonnull @Nonnull
private final View view; private final View view;
@Nonnull @Nonnull
private final CalculatorMathRegistry<Function> mathRegistry; private final CalculatorMathRegistry<Function> mathRegistry;
public FunctionEditorSaver(@Nonnull AFunction.Builder builder, public FunctionEditorSaver(@Nonnull AFunction.Builder builder,
@Nullable IFunction editedInstance, @Nullable IFunction editedInstance,
@Nonnull View view, @Nonnull View view,
@Nonnull CalculatorMathRegistry<Function> registry, @Nonnull CalculatorMathRegistry<Function> registry,
@Nonnull Object source) { @Nonnull Object source) {
this.builder = builder; this.builder = builder;
this.editedInstance = editedInstance; this.editedInstance = editedInstance;
this.view = view; this.view = view;
this.mathRegistry = registry; this.mathRegistry = registry;
this.source = source; this.source = source;
} }
@Override @Nonnull
public void onClick(View v) { public static FunctionEditDialogFragment.Input readInput(@Nullable IFunction function, @Nonnull View root) {
final Integer error; final EditText editName = (EditText) root.findViewById(R.id.function_edit_name);
String name = editName.getText().toString();
final FunctionEditDialogFragment.Input input = readInput(null, view); final EditText editValue = (EditText) root.findViewById(R.id.function_edit_value);
String content = editValue.getText().toString();
final String name = input.getName(); final EditText editDescription = (EditText) root.findViewById(R.id.function_edit_description);
final String content = input.getContent(); String description = editDescription.getText().toString();
final String description = input.getDescription();
List<String> parameterNames = input.getParameterNames(); final FunctionParamsView editParams = (FunctionParamsView) root.findViewById(R.id.function_params_layout);
if (parameterNames == null) { List<String> parameterNames = editParams.getParameterNames();
parameterNames = Collections.emptyList();
}
if (VarEditorSaver.isValidName(name)) { return FunctionEditDialogFragment.Input.newInstance(function, name, content, description, parameterNames);
}
boolean canBeSaved = false; @Override
public void onClick(View v) {
final Integer error;
final Function entityFromRegistry = mathRegistry.get(name); final FunctionEditDialogFragment.Input input = readInput(null, view);
if (entityFromRegistry == null) {
canBeSaved = true;
} else if (editedInstance != null && entityFromRegistry.getId().equals(editedInstance.getId())) {
canBeSaved = true;
}
if (canBeSaved) { final String name = input.getName();
if (validateParameters(parameterNames)) { final String content = input.getContent();
final String description = input.getDescription();
if (!Strings.isEmpty(content)) { List<String> parameterNames = input.getParameterNames();
builder.setParameterNames(parameterNames); if (parameterNames == null) {
builder.setName(name); parameterNames = Collections.emptyList();
builder.setDescription(description); }
builder.setValue(content);
error = null;
} else {
error = R.string.function_is_empty;
}
} else {
error = R.string.function_param_not_empty;
}
} else {
error = R.string.function_already_exists;
}
} else {
error = R.string.function_name_is_not_valid;
}
if (error != null) { if (VarEditorSaver.isValidName(name)) {
Locator.getInstance().getNotifier().showMessage(error, MessageType.error);
} else {
try {
CalculatorFunctionsMathRegistry.saveFunction(mathRegistry, new FunctionBuilderAdapter(builder), editedInstance, source, true);
} catch (CustomFunctionCalculationException e) {
Locator.getInstance().getNotifier().showMessage(e);
} catch (AFunction.Builder.CreationException e) {
Locator.getInstance().getNotifier().showMessage(e);
}
}
}
@Nonnull boolean canBeSaved = false;
public static FunctionEditDialogFragment.Input readInput(@Nullable IFunction function, @Nonnull View root) {
final EditText editName = (EditText) root.findViewById(R.id.function_edit_name);
String name = editName.getText().toString();
final EditText editValue = (EditText) root.findViewById(R.id.function_edit_value); final Function entityFromRegistry = mathRegistry.get(name);
String content = editValue.getText().toString(); if (entityFromRegistry == null) {
canBeSaved = true;
} else if (editedInstance != null && entityFromRegistry.getId().equals(editedInstance.getId())) {
canBeSaved = true;
}
final EditText editDescription = (EditText) root.findViewById(R.id.function_edit_description); if (canBeSaved) {
String description = editDescription.getText().toString(); if (validateParameters(parameterNames)) {
final FunctionParamsView editParams = (FunctionParamsView) root.findViewById(R.id.function_params_layout); if (!Strings.isEmpty(content)) {
List<String> parameterNames = editParams.getParameterNames(); builder.setParameterNames(parameterNames);
builder.setName(name);
builder.setDescription(description);
builder.setValue(content);
error = null;
} else {
error = R.string.function_is_empty;
}
} else {
error = R.string.function_param_not_empty;
}
} else {
error = R.string.function_already_exists;
}
} else {
error = R.string.function_name_is_not_valid;
}
return FunctionEditDialogFragment.Input.newInstance(function, name, content, description, parameterNames); if (error != null) {
} Locator.getInstance().getNotifier().showMessage(error, MessageType.error);
} else {
try {
CalculatorFunctionsMathRegistry.saveFunction(mathRegistry, new FunctionBuilderAdapter(builder), editedInstance, source, true);
} catch (CustomFunctionCalculationException e) {
Locator.getInstance().getNotifier().showMessage(e);
} catch (AFunction.Builder.CreationException e) {
Locator.getInstance().getNotifier().showMessage(e);
}
}
}
private boolean validateParameters(@Nonnull List<String> parameterNames) { private boolean validateParameters(@Nonnull List<String> parameterNames) {
for (String parameterName : parameterNames) { for (String parameterName : parameterNames) {
if (!VarEditorSaver.isValidName(parameterName)) { if (!VarEditorSaver.isValidName(parameterName)) {
return false; return false;
} }
} }
return true; return true;
} }
} }

View File

@ -30,27 +30,27 @@ import android.widget.EditText;
public class FunctionParamEditText extends EditText { public class FunctionParamEditText extends EditText {
public FunctionParamEditText(Context context) { public FunctionParamEditText(Context context) {
super(context); super(context);
} }
public FunctionParamEditText(Context context, AttributeSet attrs) { public FunctionParamEditText(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
} }
public FunctionParamEditText(Context context, AttributeSet attrs, int defStyle) { public FunctionParamEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
} }
// we restore state manually outside // we restore state manually outside
@Override @Override
public Parcelable onSaveInstanceState() { public Parcelable onSaveInstanceState() {
super.onSaveInstanceState(); super.onSaveInstanceState();
return AbsSavedState.EMPTY_STATE; return AbsSavedState.EMPTY_STATE;
} }
@Override @Override
public void onRestoreInstanceState(Parcelable state) { public void onRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(null); super.onRestoreInstanceState(null);
} }
} }

View File

@ -32,183 +32,184 @@ import android.view.ViewGroup;
import android.widget.EditText; import android.widget.EditText;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import jscl.text.MutableInt;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.text.MutableInt;
public class FunctionParamsView extends LinearLayout { public class FunctionParamsView extends LinearLayout {
@Nonnull private static final String PARAM_TAG_PREFIX = "function_param_";
private final MutableInt paramsCount = new MutableInt(0); @Nonnull
private final MutableInt paramsCount = new MutableInt(0);
@Nonnull
private final List<Integer> paramIds = new ArrayList<Integer>(10);
@Nonnull public FunctionParamsView(Context context) {
private final List<Integer> paramIds = new ArrayList<Integer>(10); super(context);
}
private static final String PARAM_TAG_PREFIX = "function_param_"; public FunctionParamsView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FunctionParamsView(Context context) { @TargetApi(Build.VERSION_CODES.HONEYCOMB)
super(context); public FunctionParamsView(Context context, AttributeSet attrs, int defStyle) {
} super(context, attrs, defStyle);
}
public FunctionParamsView(Context context, AttributeSet attrs) { public void init() {
super(context, attrs); init(Collections.<String>emptyList());
} }
@TargetApi(Build.VERSION_CODES.HONEYCOMB) public void init(@Nonnull List<String> parameters) {
public FunctionParamsView(Context context, AttributeSet attrs, int defStyle) { this.setOrientation(VERTICAL);
super(context, attrs, defStyle);
}
public void init() { final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
init(Collections.<String>emptyList());
}
public void init(@Nonnull List<String> parameters) { final View addParamView = inflater.inflate(R.layout.function_add_param, null);
this.setOrientation(VERTICAL);
final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); final View addParamButton = addParamView.findViewById(R.id.function_add_param_button);
final View addParamView = inflater.inflate(R.layout.function_add_param, null); addParamButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addParam(null);
}
});
final View addParamButton = addParamView.findViewById(R.id.function_add_param_button); this.addView(addParamView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
addParamButton.setOnClickListener(new View.OnClickListener() { for (String parameter : parameters) {
@Override addParam(parameter);
public void onClick(View v) { }
addParam(null); }
}
});
this.addView(addParamView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); public void addParam(@Nullable String name) {
synchronized (paramsCount) {
final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for (String parameter : parameters) { final Integer id = paramsCount.intValue();
addParam(parameter);
}
}
public void addParam(@Nullable String name) { final View editParamView = inflater.inflate(R.layout.function_edit_param, null);
synchronized (paramsCount) {
final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final Integer id = paramsCount.intValue(); editParamView.setTag(getParamTag(id));
final View editParamView = inflater.inflate(R.layout.function_edit_param, null); final EditText paramNameEditText = (EditText) editParamView.findViewById(R.id.function_param_edit_text);
paramNameEditText.setText(name);
editParamView.setTag(getParamTag(id)); final View removeParamButton = editParamView.findViewById(R.id.function_remove_param_button);
removeParamButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
removeParam(id);
}
});
final EditText paramNameEditText = (EditText) editParamView.findViewById(R.id.function_param_edit_text); final View upParamButton = editParamView.findViewById(R.id.function_up_param_button);
paramNameEditText.setText(name); upParamButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
upParam(id);
}
});
final View removeParamButton = editParamView.findViewById(R.id.function_remove_param_button); final View downParamButton = editParamView.findViewById(R.id.function_down_param_button);
removeParamButton.setOnClickListener(new OnClickListener() { downParamButton.setOnClickListener(new OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
removeParam(id); downParam(id);
} }
}); });
final View upParamButton = editParamView.findViewById(R.id.function_up_param_button); this.addView(editParamView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
upParamButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
upParam(id);
}
});
final View downParamButton = editParamView.findViewById(R.id.function_down_param_button); paramIds.add(id);
downParamButton.setOnClickListener(new OnClickListener() { paramsCount.increment();
@Override }
public void onClick(View v) { }
downParam(id);
}
});
this.addView(editParamView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); private void downParam(@Nonnull Integer id) {
synchronized (paramsCount) {
int index = paramIds.indexOf(id);
if (index < paramIds.size() - 1) {
swap(index, index + 1);
}
}
}
paramIds.add(id); private void upParam(@Nonnull Integer id) {
paramsCount.increment(); synchronized (paramsCount) {
} int index = paramIds.indexOf(id);
} if (index > 0) {
swap(index, index - 1);
}
}
}
private void downParam(@Nonnull Integer id) { private void swap(int index1, int index2) {
synchronized (paramsCount) { final View editParamView1 = getParamView(paramIds.get(index1));
int index = paramIds.indexOf(id); final View editParamView2 = getParamView(paramIds.get(index2));
if (index < paramIds.size() - 1) {
swap(index, index + 1);
}
}
}
private void upParam(@Nonnull Integer id) { if (editParamView1 != null && editParamView2 != null) {
synchronized (paramsCount) { final EditText paramNameEditText1 = (EditText) editParamView1.findViewById(R.id.function_param_edit_text);
int index = paramIds.indexOf(id); final EditText paramNameEditText2 = (EditText) editParamView2.findViewById(R.id.function_param_edit_text);
if (index > 0) { swap(paramNameEditText1, paramNameEditText2);
swap(index, index - 1); }
} }
}
}
private void swap(int index1, int index2) { private void swap(@Nonnull TextView first,
final View editParamView1 = getParamView(paramIds.get(index1)); @Nonnull TextView second) {
final View editParamView2 = getParamView(paramIds.get(index2)); final CharSequence tmp = first.getText();
first.setText(second.getText());
second.setText(tmp);
}
if (editParamView1 != null && editParamView2 != null) { @Nullable
final EditText paramNameEditText1 = (EditText) editParamView1.findViewById(R.id.function_param_edit_text); private View getParamView(@Nonnull Integer id) {
final EditText paramNameEditText2 = (EditText) editParamView2.findViewById(R.id.function_param_edit_text); final String tag = getParamTag(id);
swap(paramNameEditText1, paramNameEditText2); return this.findViewWithTag(tag);
} }
}
private void swap(@Nonnull TextView first, @Nonnull
@Nonnull TextView second) { private String getParamTag(@Nonnull Integer index) {
final CharSequence tmp = first.getText(); return PARAM_TAG_PREFIX + index;
first.setText(second.getText()); }
second.setText(tmp);
}
@Nullable public void removeParam(@Nonnull Integer id) {
private View getParamView(@Nonnull Integer id) { synchronized (paramsCount) {
final String tag = getParamTag(id); if (paramIds.contains(id)) {
return this.findViewWithTag(tag); final View editParamView = getParamView(id);
} if (editParamView != null) {
this.removeView(editParamView);
paramIds.remove(id);
}
}
}
}
@Nonnull @Nonnull
private String getParamTag(@Nonnull Integer index) { public List<String> getParameterNames() {
return PARAM_TAG_PREFIX + index; synchronized (paramsCount) {
} final List<String> result = new ArrayList<String>(paramsCount.intValue());
public void removeParam(@Nonnull Integer id) { for (Integer id : paramIds) {
synchronized (paramsCount) { final View paramView = getParamView(id);
if (paramIds.contains(id)) { if (paramView != null) {
final View editParamView = getParamView(id); final EditText paramNameEditText = (EditText) paramView.findViewById(R.id.function_param_edit_text);
if (editParamView != null) { result.add(paramNameEditText.getText().toString());
this.removeView(editParamView); }
paramIds.remove(id); }
}
}
}
}
@Nonnull return result;
public List<String> getParameterNames() { }
synchronized (paramsCount) { }
final List<String> result = new ArrayList<String>(paramsCount.intValue());
for (Integer id : paramIds) {
final View paramView = getParamView(id);
if (paramView != null) {
final EditText paramNameEditText = (EditText) paramView.findViewById(R.id.function_param_edit_text);
result.add(paramNameEditText.getText().toString());
}
}
return result;
}
}
} }

View File

@ -4,105 +4,108 @@ import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.google.android.gms.analytics.GoogleAnalytics; import com.google.android.gms.analytics.GoogleAnalytics;
import com.google.android.gms.analytics.HitBuilders; import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.analytics.Tracker; import com.google.android.gms.analytics.Tracker;
import org.solovyev.android.calculator.Preferences; import org.solovyev.android.calculator.Preferences;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import org.solovyev.common.listeners.JEvent; import org.solovyev.common.listeners.JEvent;
import org.solovyev.common.listeners.JEventListener; import org.solovyev.common.listeners.JEventListener;
import org.solovyev.common.listeners.JEventListeners; import org.solovyev.common.listeners.JEventListeners;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.PrintStream; import java.io.PrintStream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class Ga implements SharedPreferences.OnSharedPreferenceChangeListener { public final class Ga implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final int LAYOUT = 1; private static final int LAYOUT = 1;
private static final int THEME = 2; private static final int THEME = 2;
@Nonnull @Nonnull
private final GoogleAnalytics analytics; private final GoogleAnalytics analytics;
@Nonnull @Nonnull
private final Tracker tracker; private final Tracker tracker;
public Ga(@Nonnull Context context, @Nonnull SharedPreferences preferences, @Nonnull JEventListeners<JEventListener<? extends JEvent>, JEvent> bus) { public Ga(@Nonnull Context context, @Nonnull SharedPreferences preferences, @Nonnull JEventListeners<JEventListener<? extends JEvent>, JEvent> bus) {
analytics = GoogleAnalytics.getInstance(context); analytics = GoogleAnalytics.getInstance(context);
tracker = analytics.newTracker(R.xml.ga); tracker = analytics.newTracker(R.xml.ga);
preferences.registerOnSharedPreferenceChangeListener(this); preferences.registerOnSharedPreferenceChangeListener(this);
} }
@Nonnull @Nonnull
private String getStackTrace(@Nonnull Exception e) { private String getStackTrace(@Nonnull Exception e) {
try { try {
final ByteArrayOutputStream out = new ByteArrayOutputStream(); final ByteArrayOutputStream out = new ByteArrayOutputStream();
e.printStackTrace(new PrintStream(out)); e.printStackTrace(new PrintStream(out));
return new String(out.toByteArray()); return new String(out.toByteArray());
} catch (Exception e1) { } catch (Exception e1) {
Log.e("Ga", e1.getMessage(), e1); Log.e("Ga", e1.getMessage(), e1);
} }
return ""; return "";
} }
private void reportLayout(@Nonnull Preferences.Gui.Layout layout) { private void reportLayout(@Nonnull Preferences.Gui.Layout layout) {
tracker.send(new HitBuilders.EventBuilder().setCustomDimension(LAYOUT, layout.name()).build()); tracker.send(new HitBuilders.EventBuilder().setCustomDimension(LAYOUT, layout.name()).build());
} }
private void reportTheme(@Nonnull Preferences.Gui.Theme theme) { private void reportTheme(@Nonnull Preferences.Gui.Theme theme) {
tracker.send(new HitBuilders.EventBuilder().setCustomDimension(THEME, theme.name()).build()); tracker.send(new HitBuilders.EventBuilder().setCustomDimension(THEME, theme.name()).build());
} }
@Nonnull @Nonnull
public GoogleAnalytics getAnalytics() { public GoogleAnalytics getAnalytics() {
return analytics; return analytics;
} }
@Nonnull @Nonnull
public Tracker getTracker() { public Tracker getTracker() {
return tracker; return tracker;
} }
public void onButtonPressed(@Nullable String text) { public void onButtonPressed(@Nullable String text) {
if (TextUtils.isEmpty(text)) { if (TextUtils.isEmpty(text)) {
return; return;
} }
final HitBuilders.EventBuilder b = new HitBuilders.EventBuilder(); final HitBuilders.EventBuilder b = new HitBuilders.EventBuilder();
b.setCategory("ui"); b.setCategory("ui");
b.setAction("click"); b.setAction("click");
b.setLabel(text); b.setLabel(text);
tracker.send(b.build()); tracker.send(b.build());
} }
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (TextUtils.equals(key, Preferences.Gui.layout.getKey())) { if (TextUtils.equals(key, Preferences.Gui.layout.getKey())) {
reportLayout(Preferences.Gui.layout.getPreferenceNoError(preferences)); reportLayout(Preferences.Gui.layout.getPreferenceNoError(preferences));
} else if (TextUtils.equals(key, Preferences.Gui.theme.getKey())) { } else if (TextUtils.equals(key, Preferences.Gui.theme.getKey())) {
reportTheme(Preferences.Gui.theme.getPreferenceNoError(preferences)); reportTheme(Preferences.Gui.theme.getPreferenceNoError(preferences));
} }
} }
public void reportInitially(@Nonnull SharedPreferences preferences) { public void reportInitially(@Nonnull SharedPreferences preferences) {
reportLayout(Preferences.Gui.layout.getPreferenceNoError(preferences)); reportLayout(Preferences.Gui.layout.getPreferenceNoError(preferences));
reportTheme(Preferences.Gui.theme.getPreferenceNoError(preferences)); reportTheme(Preferences.Gui.theme.getPreferenceNoError(preferences));
} }
public void onBootStart() { public void onBootStart() {
final HitBuilders.EventBuilder b = new HitBuilders.EventBuilder(); final HitBuilders.EventBuilder b = new HitBuilders.EventBuilder();
b.setCategory("lifecycle"); b.setCategory("lifecycle");
b.setAction("boot"); b.setAction("boot");
tracker.send(b.build()); tracker.send(b.build());
} }
public void onFloatingCalculatorOpened() { public void onFloatingCalculatorOpened() {
final HitBuilders.EventBuilder b = new HitBuilders.EventBuilder(); final HitBuilders.EventBuilder b = new HitBuilders.EventBuilder();
b.setCategory("lifecycle"); b.setCategory("lifecycle");
b.setAction("floating_calculator"); b.setAction("floating_calculator");
b.setLabel("start"); b.setLabel("start");
tracker.send(b.build()); tracker.send(b.build());
} }
} }

View File

@ -26,14 +26,16 @@ import android.app.Application;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import org.solovyev.android.calculator.Calculator; import org.solovyev.android.calculator.Calculator;
import org.solovyev.android.calculator.CalculatorEventData; import org.solovyev.android.calculator.CalculatorEventData;
import org.solovyev.android.calculator.CalculatorEventType; import org.solovyev.android.calculator.CalculatorEventType;
import org.solovyev.common.history.HistoryAction; import org.solovyev.common.history.HistoryAction;
import java.util.List;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.List;
/** /**
* User: serso * User: serso
@ -42,132 +44,132 @@ import java.util.List;
*/ */
public class AndroidCalculatorHistory implements CalculatorHistory { public class AndroidCalculatorHistory implements CalculatorHistory {
@Nonnull @Nonnull
private final CalculatorHistoryImpl calculatorHistory; private final CalculatorHistoryImpl calculatorHistory;
@Nonnull @Nonnull
private final Context context; private final Context context;
public AndroidCalculatorHistory(@Nonnull Application application, @Nonnull Calculator calculator) { public AndroidCalculatorHistory(@Nonnull Application application, @Nonnull Calculator calculator) {
this.context = application; this.context = application;
calculatorHistory = new CalculatorHistoryImpl(calculator); calculatorHistory = new CalculatorHistoryImpl(calculator);
} }
@Override @Override
public void load() { public void load() {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
if (preferences != null) { if (preferences != null) {
final String value = preferences.getString("org.solovyev.android.calculator.CalculatorModel_history", null); final String value = preferences.getString("org.solovyev.android.calculator.CalculatorModel_history", null);
if (value != null) { if (value != null) {
calculatorHistory.fromXml(value); calculatorHistory.fromXml(value);
} }
} }
} }
public void save() { public void save() {
final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
final SharedPreferences.Editor editor = settings.edit(); final SharedPreferences.Editor editor = settings.edit();
editor.putString("org.solovyev.android.calculator.CalculatorModel_history", calculatorHistory.toXml()); editor.putString("org.solovyev.android.calculator.CalculatorModel_history", calculatorHistory.toXml());
editor.apply(); editor.apply();
} }
public void clearSavedHistory() { public void clearSavedHistory() {
calculatorHistory.clearSavedHistory(); calculatorHistory.clearSavedHistory();
save(); save();
} }
public void removeSavedHistory(@Nonnull CalculatorHistoryState historyState) { public void removeSavedHistory(@Nonnull CalculatorHistoryState historyState) {
historyState.setSaved(false); historyState.setSaved(false);
calculatorHistory.removeSavedHistory(historyState); calculatorHistory.removeSavedHistory(historyState);
save(); save();
} }
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
return calculatorHistory.isEmpty(); return calculatorHistory.isEmpty();
} }
@Override @Override
public CalculatorHistoryState getLastHistoryState() { public CalculatorHistoryState getLastHistoryState() {
return calculatorHistory.getLastHistoryState(); return calculatorHistory.getLastHistoryState();
} }
@Override @Override
public boolean isUndoAvailable() { public boolean isUndoAvailable() {
return calculatorHistory.isUndoAvailable(); return calculatorHistory.isUndoAvailable();
} }
@Override @Override
public CalculatorHistoryState undo(@Nullable CalculatorHistoryState currentState) { public CalculatorHistoryState undo(@Nullable CalculatorHistoryState currentState) {
return calculatorHistory.undo(currentState); return calculatorHistory.undo(currentState);
} }
@Override @Override
public boolean isRedoAvailable() { public boolean isRedoAvailable() {
return calculatorHistory.isRedoAvailable(); return calculatorHistory.isRedoAvailable();
} }
@Override @Override
public CalculatorHistoryState redo(@Nullable CalculatorHistoryState currentState) { public CalculatorHistoryState redo(@Nullable CalculatorHistoryState currentState) {
return calculatorHistory.redo(currentState); return calculatorHistory.redo(currentState);
} }
@Override @Override
public boolean isActionAvailable(@Nonnull HistoryAction historyAction) { public boolean isActionAvailable(@Nonnull HistoryAction historyAction) {
return calculatorHistory.isActionAvailable(historyAction); return calculatorHistory.isActionAvailable(historyAction);
} }
@Override @Override
public CalculatorHistoryState doAction(@Nonnull HistoryAction historyAction, @Nullable CalculatorHistoryState currentState) { public CalculatorHistoryState doAction(@Nonnull HistoryAction historyAction, @Nullable CalculatorHistoryState currentState) {
return calculatorHistory.doAction(historyAction, currentState); return calculatorHistory.doAction(historyAction, currentState);
} }
@Override @Override
public void addState(@Nullable CalculatorHistoryState currentState) { public void addState(@Nullable CalculatorHistoryState currentState) {
calculatorHistory.addState(currentState); calculatorHistory.addState(currentState);
} }
@Nonnull @Nonnull
@Override @Override
public List<CalculatorHistoryState> getStates() { public List<CalculatorHistoryState> getStates() {
return calculatorHistory.getStates(); return calculatorHistory.getStates();
} }
@Nonnull @Nonnull
@Override @Override
public List<CalculatorHistoryState> getStates(boolean includeIntermediateStates) { public List<CalculatorHistoryState> getStates(boolean includeIntermediateStates) {
return calculatorHistory.getStates(includeIntermediateStates); return calculatorHistory.getStates(includeIntermediateStates);
} }
@Override @Override
public void clear() { public void clear() {
calculatorHistory.clear(); calculatorHistory.clear();
} }
@Nonnull @Nonnull
public List<CalculatorHistoryState> getSavedHistory() { public List<CalculatorHistoryState> getSavedHistory() {
return calculatorHistory.getSavedHistory(); return calculatorHistory.getSavedHistory();
} }
@Nonnull @Nonnull
public CalculatorHistoryState addSavedState(@Nonnull CalculatorHistoryState historyState) { public CalculatorHistoryState addSavedState(@Nonnull CalculatorHistoryState historyState) {
return calculatorHistory.addSavedState(historyState); return calculatorHistory.addSavedState(historyState);
} }
@Override @Override
public void fromXml(@Nonnull String xml) { public void fromXml(@Nonnull String xml) {
calculatorHistory.fromXml(xml); calculatorHistory.fromXml(xml);
} }
@Override @Override
public String toXml() { public String toXml() {
return calculatorHistory.toXml(); return calculatorHistory.toXml();
} }
@Override @Override
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) { public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
calculatorHistory.onCalculatorEvent(calculatorEventData, calculatorEventType, data); calculatorHistory.onCalculatorEvent(calculatorEventData, calculatorEventType, data);
} }
} }

View File

@ -81,30 +81,29 @@ import static org.solovyev.android.calculator.CalculatorEventType.clear_history_
public abstract class BaseHistoryFragment extends ListFragment implements CalculatorEventListener { public abstract class BaseHistoryFragment extends ListFragment implements CalculatorEventListener {
/* /*
********************************************************************** **********************************************************************
* *
* CONSTANTS * CONSTANTS
* *
********************************************************************** **********************************************************************
*/ */
@Nonnull public static final Comparator<CalculatorHistoryState> COMPARATOR = new Comparator<CalculatorHistoryState>() {
private static final String TAG = "CalculatorHistoryFragment"; @Override
public int compare(CalculatorHistoryState state1, CalculatorHistoryState state2) {
public static final Comparator<CalculatorHistoryState> COMPARATOR = new Comparator<CalculatorHistoryState>() { if (state1.isSaved() == state2.isSaved()) {
@Override long l = state2.getTime() - state1.getTime();
public int compare(CalculatorHistoryState state1, CalculatorHistoryState state2) { return l > 0l ? 1 : (l < 0l ? -1 : 0);
if (state1.isSaved() == state2.isSaved()) { } else if (state1.isSaved()) {
long l = state2.getTime() - state1.getTime(); return -1;
return l > 0l ? 1 : (l < 0l ? -1 : 0); } else if (state2.isSaved()) {
} else if (state1.isSaved()) { return 1;
return -1; }
} else if (state2.isSaved()) { return 0;
return 1; }
} };
return 0; @Nonnull
} private static final String TAG = "CalculatorHistoryFragment";
};
/* /*
********************************************************************** **********************************************************************
@ -113,282 +112,276 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
* *
********************************************************************** **********************************************************************
*/ */
private final ActivityMenu<Menu, MenuItem> menu = ListActivityMenu.fromResource(R.menu.history_menu, HistoryMenu.class, AndroidMenuHelper.getInstance(), new HistoryMenuFilter());
@Nonnull
private final SharedPreferences.OnSharedPreferenceChangeListener preferencesListener = new HistoryOnPreferenceChangeListener();
@Nonnull
private final DialogInterface.OnClickListener clearDialogListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
clearHistory();
break;
}
}
};
@Nonnull
private HistoryArrayAdapter adapter;
@Nonnull
private FragmentUi ui;
@Nullable
private AlertDialog clearDialog;
protected BaseHistoryFragment(@Nonnull CalculatorFragmentType fragmentType) {
ui = CalculatorApplication.getInstance().createFragmentHelper(fragmentType.getDefaultLayoutId(), fragmentType.getDefaultTitleResId(), false);
}
@Nonnull public static boolean isAlreadySaved(@Nonnull CalculatorHistoryState historyState) {
private HistoryArrayAdapter adapter; if (historyState.isSaved()) throw new AssertionError();
@Nonnull boolean result = false;
private FragmentUi ui; try {
historyState.setSaved(true);
if (Collections.contains(historyState, Locator.getInstance().getHistory().getSavedHistory(), new Equalizer<CalculatorHistoryState>() {
@Override
public boolean areEqual(@Nullable CalculatorHistoryState first, @Nullable CalculatorHistoryState second) {
return first != null && second != null &&
first.getTime() == second.getTime() &&
first.getDisplayState().equals(second.getDisplayState()) &&
first.getEditorState().equals(second.getEditorState());
}
})) {
result = true;
}
} finally {
historyState.setSaved(false);
}
return result;
}
private final ActivityMenu<Menu, MenuItem> menu = ListActivityMenu.fromResource(R.menu.history_menu, HistoryMenu.class, AndroidMenuHelper.getInstance(), new HistoryMenuFilter()); public static void useHistoryItem(@Nonnull final CalculatorHistoryState historyState) {
App.getVibrator().vibrate();
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.use_history_state, historyState);
}
@Nonnull @Nonnull
private final SharedPreferences.OnSharedPreferenceChangeListener preferencesListener = new HistoryOnPreferenceChangeListener(); public static String getHistoryText(@Nonnull CalculatorHistoryState state) {
final StringBuilder result = new StringBuilder();
result.append(state.getEditorState().getText());
result.append(getIdentitySign(state.getDisplayState().getJsclOperation()));
final String expressionResult = state.getDisplayState().getEditorState().getText();
if (expressionResult != null) {
result.append(expressionResult);
}
return result.toString();
}
@Nonnull @Nonnull
private final DialogInterface.OnClickListener clearDialogListener = new DialogInterface.OnClickListener() { private static String getIdentitySign(@Nonnull JsclOperation jsclOperation) {
@Override return jsclOperation == JsclOperation.simplify ? "" : "=";
public void onClick(DialogInterface dialog, int which) { }
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
clearHistory();
break;
}
}
};
@Nullable
private AlertDialog clearDialog;
protected BaseHistoryFragment(@Nonnull CalculatorFragmentType fragmentType) { @Override
ui = CalculatorApplication.getInstance().createFragmentHelper(fragmentType.getDefaultLayoutId(), fragmentType.getDefaultTitleResId(), false); public void onCreate(Bundle savedInstanceState) {
} super.onCreate(savedInstanceState);
@Override ui.onCreate(this);
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ui.onCreate(this); setHasOptionsMenu(true);
setHasOptionsMenu(true); logDebug("onCreate");
}
logDebug("onCreate"); private int logDebug(@Nonnull String msg) {
} return Log.d(TAG + ": " + getTag(), msg);
}
private int logDebug(@Nonnull String msg) { @Override
return Log.d(TAG + ": " + getTag(), msg); public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
} return ui.onCreateView(this, inflater, container);
}
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public void onViewCreated(View root, Bundle savedInstanceState) {
return ui.onCreateView(this, inflater, container); super.onViewCreated(root, savedInstanceState);
}
@Override final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
public void onViewCreated(View root, Bundle savedInstanceState) { final Boolean showDatetime = Preferences.History.showDatetime.getPreference(preferences);
super.onViewCreated(root, savedInstanceState);
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); ui.onViewCreated(this, root);
final Boolean showDatetime = Preferences.History.showDatetime.getPreference(preferences);
ui.onViewCreated(this, root); adapter = new HistoryArrayAdapter(this.getActivity(), getItemLayoutId(), org.solovyev.android.calculator.R.id.history_item, new ArrayList<CalculatorHistoryState>(), showDatetime);
setListAdapter(adapter);
adapter = new HistoryArrayAdapter(this.getActivity(), getItemLayoutId(), org.solovyev.android.calculator.R.id.history_item, new ArrayList<CalculatorHistoryState>(), showDatetime); final ListView lv = getListView();
setListAdapter(adapter); lv.setTextFilterEnabled(true);
final ListView lv = getListView(); final FloatingActionButton fab = (FloatingActionButton) root.findViewById(R.id.fab);
lv.setTextFilterEnabled(true); fab.attachToListView(lv);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Locator.getInstance().getCalculator().fireCalculatorEvent(clear_history_requested, null);
}
});
final FloatingActionButton fab = (FloatingActionButton) root.findViewById(R.id.fab); lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
fab.attachToListView(lv); public void onItemClick(final AdapterView<?> parent,
fab.setOnClickListener(new View.OnClickListener() { final View view,
@Override final int position,
public void onClick(View v) { final long id) {
Locator.getInstance().getCalculator().fireCalculatorEvent(clear_history_requested, null);
}
});
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { useHistoryItem((CalculatorHistoryState) parent.getItemAtPosition(position));
public void onItemClick(final AdapterView<?> parent, }
final View view, });
final int position,
final long id) {
useHistoryItem((CalculatorHistoryState) parent.getItemAtPosition(position)); lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
} @Override
}); public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) {
final CalculatorHistoryState historyState = (CalculatorHistoryState) parent.getItemAtPosition(position);
lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { final FragmentActivity activity = getActivity();
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) {
final CalculatorHistoryState historyState = (CalculatorHistoryState) parent.getItemAtPosition(position);
final FragmentActivity activity = getActivity(); final HistoryItemMenuData data = new HistoryItemMenuData(historyState, adapter);
final HistoryItemMenuData data = new HistoryItemMenuData(historyState, adapter); final List<HistoryItemMenuItem> menuItems = Collections.asList(HistoryItemMenuItem.values());
final List<HistoryItemMenuItem> menuItems = Collections.asList(HistoryItemMenuItem.values()); if (historyState.isSaved()) {
menuItems.remove(HistoryItemMenuItem.save);
} else {
if (isAlreadySaved(historyState)) {
menuItems.remove(HistoryItemMenuItem.save);
}
menuItems.remove(HistoryItemMenuItem.remove);
menuItems.remove(HistoryItemMenuItem.edit);
}
if (historyState.isSaved()) { if (historyState.getDisplayState().isValid() && Strings.isEmpty(historyState.getDisplayState().getEditorState().getText())) {
menuItems.remove(HistoryItemMenuItem.save); menuItems.remove(HistoryItemMenuItem.copy_result);
} else { }
if (isAlreadySaved(historyState)) {
menuItems.remove(HistoryItemMenuItem.save);
}
menuItems.remove(HistoryItemMenuItem.remove);
menuItems.remove(HistoryItemMenuItem.edit);
}
if (historyState.getDisplayState().isValid() && Strings.isEmpty(historyState.getDisplayState().getEditorState().getText())) { final ContextMenuBuilder<HistoryItemMenuItem, HistoryItemMenuData> menuBuilder = ContextMenuBuilder.newInstance(activity, "history-menu", ListContextMenu.newInstance(menuItems));
menuItems.remove(HistoryItemMenuItem.copy_result); menuBuilder.build(data).show();
}
final ContextMenuBuilder<HistoryItemMenuItem, HistoryItemMenuData> menuBuilder = ContextMenuBuilder.newInstance(activity, "history-menu", ListContextMenu.newInstance(menuItems)); return true;
menuBuilder.build(data).show(); }
});
}
return true; @Override
} public void onResume() {
}); super.onResume();
}
@Override this.ui.onResume(this);
public void onResume() {
super.onResume();
this.ui.onResume(this); updateAdapter();
PreferenceManager.getDefaultSharedPreferences(getActivity()).registerOnSharedPreferenceChangeListener(preferencesListener);
}
updateAdapter(); @Override
PreferenceManager.getDefaultSharedPreferences(getActivity()).registerOnSharedPreferenceChangeListener(preferencesListener); public void onPause() {
} PreferenceManager.getDefaultSharedPreferences(getActivity()).unregisterOnSharedPreferenceChangeListener(preferencesListener);
@Override this.ui.onPause(this);
public void onPause() {
PreferenceManager.getDefaultSharedPreferences(getActivity()).unregisterOnSharedPreferenceChangeListener(preferencesListener);
this.ui.onPause(this); super.onPause();
}
super.onPause(); @Override
} public void onDestroyView() {
ui.onDestroyView(this);
super.onDestroyView();
}
@Override @Override
public void onDestroyView() { public void onDestroy() {
ui.onDestroyView(this); logDebug("onDestroy");
super.onDestroyView(); if (clearDialog != null) {
} clearDialog.dismiss();
clearDialog = null;
}
ui.onDestroy(this);
@Override super.onDestroy();
public void onDestroy() { }
logDebug("onDestroy");
if (clearDialog != null) {
clearDialog.dismiss();
clearDialog = null;
}
ui.onDestroy(this);
super.onDestroy(); protected abstract int getItemLayoutId();
}
protected abstract int getItemLayoutId(); private void updateAdapter() {
final List<CalculatorHistoryState> historyList = getHistoryList();
private void updateAdapter() { final ArrayAdapter<CalculatorHistoryState> adapter = getAdapter();
final List<CalculatorHistoryState> historyList = getHistoryList(); try {
adapter.setNotifyOnChange(false);
adapter.clear();
for (CalculatorHistoryState historyState : historyList) {
adapter.add(historyState);
}
} finally {
adapter.setNotifyOnChange(true);
}
final ArrayAdapter<CalculatorHistoryState> adapter = getAdapter(); adapter.notifyDataSetChanged();
try { }
adapter.setNotifyOnChange(false);
adapter.clear();
for (CalculatorHistoryState historyState : historyList) {
adapter.add(historyState);
}
} finally {
adapter.setNotifyOnChange(true);
}
adapter.notifyDataSetChanged(); @Nonnull
} private List<CalculatorHistoryState> getHistoryList() {
final List<CalculatorHistoryState> calculatorHistoryStates = getHistoryItems();
public static boolean isAlreadySaved(@Nonnull CalculatorHistoryState historyState) { java.util.Collections.sort(calculatorHistoryStates, COMPARATOR);
if (historyState.isSaved()) throw new AssertionError();
boolean result = false; final FilterRulesChain<CalculatorHistoryState> filterRulesChain = new FilterRulesChain<>();
try { filterRulesChain.addFilterRule(new JPredicate<CalculatorHistoryState>() {
historyState.setSaved(true); @Override
if (Collections.contains(historyState, Locator.getInstance().getHistory().getSavedHistory(), new Equalizer<CalculatorHistoryState>() { public boolean apply(CalculatorHistoryState object) {
@Override return object == null || Strings.isEmpty(object.getEditorState().getText());
public boolean areEqual(@Nullable CalculatorHistoryState first, @Nullable CalculatorHistoryState second) { }
return first != null && second != null && });
first.getTime() == second.getTime() &&
first.getDisplayState().equals(second.getDisplayState()) &&
first.getEditorState().equals(second.getEditorState());
}
})) {
result = true;
}
} finally {
historyState.setSaved(false);
}
return result;
}
public static void useHistoryItem(@Nonnull final CalculatorHistoryState historyState) { new Filter<>(filterRulesChain).filter(calculatorHistoryStates.iterator());
App.getVibrator().vibrate();
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.use_history_state, historyState);
}
@Nonnull return calculatorHistoryStates;
private List<CalculatorHistoryState> getHistoryList() { }
final List<CalculatorHistoryState> calculatorHistoryStates = getHistoryItems();
java.util.Collections.sort(calculatorHistoryStates, COMPARATOR); @Nonnull
protected abstract List<CalculatorHistoryState> getHistoryItems();
final FilterRulesChain<CalculatorHistoryState> filterRulesChain = new FilterRulesChain<>(); protected abstract void clearHistory();
filterRulesChain.addFilterRule(new JPredicate<CalculatorHistoryState>() {
@Override
public boolean apply(CalculatorHistoryState object) {
return object == null || Strings.isEmpty(object.getEditorState().getText());
}
});
new Filter<>(filterRulesChain).filter(calculatorHistoryStates.iterator()); @Nonnull
protected HistoryArrayAdapter getAdapter() {
return adapter;
}
return calculatorHistoryStates; @Override
} public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
switch (calculatorEventType) {
case history_state_added:
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
logDebug("onCalculatorEvent");
updateAdapter();
}
});
break;
case clear_history_requested:
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
clearDialog = new AlertDialog.Builder(getActivity()).setTitle(R.string.cpp_clear_history_title)
.setMessage(R.string.cpp_clear_history_message)
.setPositiveButton(R.string.cpp_clear_history, clearDialogListener)
.setNegativeButton(R.string.c_cancel, clearDialogListener)
.create();
clearDialog.show();
}
});
break;
}
@Nonnull }
protected abstract List<CalculatorHistoryState> getHistoryItems();
@Nonnull
public static String getHistoryText(@Nonnull CalculatorHistoryState state) {
final StringBuilder result = new StringBuilder();
result.append(state.getEditorState().getText());
result.append(getIdentitySign(state.getDisplayState().getJsclOperation()));
final String expressionResult = state.getDisplayState().getEditorState().getText();
if (expressionResult != null) {
result.append(expressionResult);
}
return result.toString();
}
@Nonnull
private static String getIdentitySign(@Nonnull JsclOperation jsclOperation) {
return jsclOperation == JsclOperation.simplify ? "" : "=";
}
protected abstract void clearHistory();
@Nonnull
protected HistoryArrayAdapter getAdapter() {
return adapter;
}
@Override
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
switch (calculatorEventType) {
case history_state_added:
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
logDebug("onCalculatorEvent");
updateAdapter();
}
});
break;
case clear_history_requested:
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
clearDialog = new AlertDialog.Builder(getActivity()).setTitle(R.string.cpp_clear_history_title)
.setMessage(R.string.cpp_clear_history_message)
.setPositiveButton(R.string.cpp_clear_history, clearDialogListener)
.setNegativeButton(R.string.c_cancel, clearDialogListener)
.create();
clearDialog.show();
}
});
break;
}
}
/* /*
********************************************************************** **********************************************************************
@ -398,69 +391,69 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
********************************************************************** **********************************************************************
*/ */
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
this.menu.onCreateOptionsMenu(this.getActivity(), menu); this.menu.onCreateOptionsMenu(this.getActivity(), menu);
} }
@Override @Override
public void onPrepareOptionsMenu(Menu menu) { public void onPrepareOptionsMenu(Menu menu) {
this.menu.onPrepareOptionsMenu(this.getActivity(), menu); this.menu.onPrepareOptionsMenu(this.getActivity(), menu);
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
return this.menu.onOptionsItemSelected(this.getActivity(), item); return this.menu.onOptionsItemSelected(this.getActivity(), item);
} }
private static enum HistoryMenu implements IdentifiableMenuItem<MenuItem> { private static enum HistoryMenu implements IdentifiableMenuItem<MenuItem> {
toggle_datetime(R.id.menu_history_toggle_datetime) { toggle_datetime(R.id.menu_history_toggle_datetime) {
@Override @Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) { public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(CalculatorApplication.getInstance()); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(CalculatorApplication.getInstance());
final Boolean showDatetime = Preferences.History.showDatetime.getPreference(preferences); final Boolean showDatetime = Preferences.History.showDatetime.getPreference(preferences);
Preferences.History.showDatetime.putPreference(preferences, !showDatetime); Preferences.History.showDatetime.putPreference(preferences, !showDatetime);
} }
}, },
fullscreen(R.id.menu_history_fullscreen) { fullscreen(R.id.menu_history_fullscreen) {
@Override @Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) { public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
context.startActivity(new Intent(context, CalculatorHistoryActivity.class)); context.startActivity(new Intent(context, CalculatorHistoryActivity.class));
} }
}; };
private final int itemId; private final int itemId;
HistoryMenu(int itemId) { HistoryMenu(int itemId) {
this.itemId = itemId; this.itemId = itemId;
} }
@Nonnull @Nonnull
@Override @Override
public Integer getItemId() { public Integer getItemId() {
return this.itemId; return this.itemId;
} }
} }
private class HistoryMenuFilter implements JPredicate<AMenuItem<MenuItem>> { private class HistoryMenuFilter implements JPredicate<AMenuItem<MenuItem>> {
@Override @Override
public boolean apply(@Nullable AMenuItem<MenuItem> menuItem) { public boolean apply(@Nullable AMenuItem<MenuItem> menuItem) {
boolean result = false; boolean result = false;
if (menuItem instanceof IdentifiableMenuItem<?>) { if (menuItem instanceof IdentifiableMenuItem<?>) {
switch (((IdentifiableMenuItem) menuItem).getItemId()) { switch (((IdentifiableMenuItem) menuItem).getItemId()) {
case R.id.menu_history_fullscreen: case R.id.menu_history_fullscreen:
result = !ui.isPane(BaseHistoryFragment.this); result = !ui.isPane(BaseHistoryFragment.this);
break; break;
} }
} }
return result; return result;
} }
} }
/* /*
********************************************************************** **********************************************************************
@ -470,13 +463,13 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
********************************************************************** **********************************************************************
*/ */
private final class HistoryOnPreferenceChangeListener implements SharedPreferences.OnSharedPreferenceChangeListener { private final class HistoryOnPreferenceChangeListener implements SharedPreferences.OnSharedPreferenceChangeListener {
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (Preferences.History.showDatetime.isSameKey(key)) { if (Preferences.History.showDatetime.isSameKey(key)) {
getAdapter().setShowDatetime(Preferences.History.showDatetime.getPreference(preferences)); getAdapter().setShowDatetime(Preferences.History.showDatetime.getPreference(preferences));
} }
} }
} }
} }

View File

@ -23,7 +23,12 @@
package org.solovyev.android.calculator.history; package org.solovyev.android.calculator.history;
import android.os.Bundle; import android.os.Bundle;
import org.solovyev.android.calculator.*;
import org.solovyev.android.calculator.BaseActivity;
import org.solovyev.android.calculator.CalculatorEventData;
import org.solovyev.android.calculator.CalculatorEventListener;
import org.solovyev.android.calculator.CalculatorEventType;
import org.solovyev.android.calculator.R;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -33,22 +38,22 @@ import static org.solovyev.android.calculator.CalculatorFragmentType.saved_histo
public class CalculatorHistoryActivity extends BaseActivity implements CalculatorEventListener { public class CalculatorHistoryActivity extends BaseActivity implements CalculatorEventListener {
public CalculatorHistoryActivity() { public CalculatorHistoryActivity() {
super(R.layout.main_empty, CalculatorHistoryActivity.class.getSimpleName()); super(R.layout.main_empty, CalculatorHistoryActivity.class.getSimpleName());
} }
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
ui.addTab(this, history, null, R.id.main_layout); ui.addTab(this, history, null, R.id.main_layout);
ui.addTab(this, saved_history, null, R.id.main_layout); ui.addTab(this, saved_history, null, R.id.main_layout);
} }
@Override @Override
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) { public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
if (calculatorEventType == CalculatorEventType.use_history_state) { if (calculatorEventType == CalculatorEventType.use_history_state) {
this.finish(); this.finish();
} }
} }
} }

View File

@ -29,13 +29,16 @@ import android.view.ViewGroup;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import org.solovyev.common.text.Strings; import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull;
import java.util.List; import java.util.List;
import static android.view.View.*; import javax.annotation.Nonnull;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static org.solovyev.android.calculator.CalculatorFragmentType.saved_history; import static org.solovyev.android.calculator.CalculatorFragmentType.saved_history;
import static org.solovyev.android.calculator.history.BaseHistoryFragment.isAlreadySaved; import static org.solovyev.android.calculator.history.BaseHistoryFragment.isAlreadySaved;
@ -46,79 +49,79 @@ import static org.solovyev.android.calculator.history.BaseHistoryFragment.isAlre
*/ */
public class HistoryArrayAdapter extends ArrayAdapter<CalculatorHistoryState> { public class HistoryArrayAdapter extends ArrayAdapter<CalculatorHistoryState> {
private static final int DATETIME_FORMAT = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH | DateUtils.FORMAT_ABBREV_TIME; private static final int DATETIME_FORMAT = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH | DateUtils.FORMAT_ABBREV_TIME;
private boolean showDatetime; private boolean showDatetime;
HistoryArrayAdapter(Context context, int resource, int textViewResourceId, @Nonnull List<CalculatorHistoryState> historyList, boolean showDatetime) { HistoryArrayAdapter(Context context, int resource, int textViewResourceId, @Nonnull List<CalculatorHistoryState> historyList, boolean showDatetime) {
super(context, resource, textViewResourceId, historyList); super(context, resource, textViewResourceId, historyList);
this.showDatetime = showDatetime; this.showDatetime = showDatetime;
} }
@Override @Override
public View getView(int position, View convertView, ViewGroup parent) { public View getView(int position, View convertView, ViewGroup parent) {
final ViewGroup result = (ViewGroup) super.getView(position, convertView, parent); final ViewGroup result = (ViewGroup) super.getView(position, convertView, parent);
final CalculatorHistoryState state = getItem(position); final CalculatorHistoryState state = getItem(position);
final TextView time = (TextView) result.findViewById(R.id.history_time); final TextView time = (TextView) result.findViewById(R.id.history_time);
if (showDatetime) { if (showDatetime) {
time.setVisibility(VISIBLE); time.setVisibility(VISIBLE);
time.setText(DateUtils.formatDateTime(getContext(), state.getTime(), DATETIME_FORMAT)); time.setText(DateUtils.formatDateTime(getContext(), state.getTime(), DATETIME_FORMAT));
} else { } else {
time.setVisibility(GONE); time.setVisibility(GONE);
time.setText(null); time.setText(null);
} }
final TextView editor = (TextView) result.findViewById(R.id.history_item); final TextView editor = (TextView) result.findViewById(R.id.history_item);
editor.setText(BaseHistoryFragment.getHistoryText(state)); editor.setText(BaseHistoryFragment.getHistoryText(state));
final TextView commentView = (TextView) result.findViewById(R.id.history_item_comment); final TextView commentView = (TextView) result.findViewById(R.id.history_item_comment);
if (commentView != null) { if (commentView != null) {
final String comment = state.getComment(); final String comment = state.getComment();
if (!Strings.isEmpty(comment)) { if (!Strings.isEmpty(comment)) {
commentView.setText(comment); commentView.setText(comment);
commentView.setVisibility(VISIBLE); commentView.setVisibility(VISIBLE);
} else { } else {
commentView.setText(null); commentView.setText(null);
commentView.setVisibility(GONE); commentView.setVisibility(GONE);
} }
} }
final ImageView status = (ImageView) result.findViewById(R.id.history_item_status_icon); final ImageView status = (ImageView) result.findViewById(R.id.history_item_status_icon);
if (status != null) { if (status != null) {
if (state.isSaved() || isAlreadySaved(state)) { if (state.isSaved() || isAlreadySaved(state)) {
status.setVisibility(VISIBLE); status.setVisibility(VISIBLE);
status.setOnClickListener(new View.OnClickListener() { status.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
final Context context = getContext(); final Context context = getContext();
if (context instanceof CalculatorHistoryActivity) { if (context instanceof CalculatorHistoryActivity) {
final CalculatorHistoryActivity activity = (CalculatorHistoryActivity) context; final CalculatorHistoryActivity activity = (CalculatorHistoryActivity) context;
activity.getUi().selectTab(activity, saved_history); activity.getUi().selectTab(activity, saved_history);
} }
} }
}); });
} else { } else {
status.setVisibility(GONE); status.setVisibility(GONE);
status.setOnClickListener(null); status.setOnClickListener(null);
} }
} }
return result; return result;
} }
@Override @Override
public void notifyDataSetChanged() { public void notifyDataSetChanged() {
this.setNotifyOnChange(false); this.setNotifyOnChange(false);
this.sort(BaseHistoryFragment.COMPARATOR); this.sort(BaseHistoryFragment.COMPARATOR);
this.setNotifyOnChange(true); this.setNotifyOnChange(true);
super.notifyDataSetChanged(); super.notifyDataSetChanged();
} }
public void setShowDatetime(boolean showDatetime) { public void setShowDatetime(boolean showDatetime) {
if (this.showDatetime != showDatetime) { if (this.showDatetime != showDatetime) {
this.showDatetime = showDatetime; this.showDatetime = showDatetime;
notifyDataSetChanged(); notifyDataSetChanged();
} }
} }
} }

View File

@ -42,34 +42,34 @@ import javax.annotation.Nonnull;
*/ */
public class HistoryDragProcessor<T> implements SimpleDragListener.DragProcessor { public class HistoryDragProcessor<T> implements SimpleDragListener.DragProcessor {
@Nonnull @Nonnull
private final HistoryControl<T> historyControl; private final HistoryControl<T> historyControl;
public HistoryDragProcessor(@Nonnull HistoryControl<T> historyControl) { public HistoryDragProcessor(@Nonnull HistoryControl<T> historyControl) {
this.historyControl = historyControl; this.historyControl = historyControl;
} }
@Override @Override
public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent) { public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent) {
boolean result = false; boolean result = false;
Log.d(String.valueOf(dragButton.getId()), "History on drag event start: " + dragDirection); Log.d(String.valueOf(dragButton.getId()), "History on drag event start: " + dragDirection);
final HistoryAction historyAction; final HistoryAction historyAction;
if (dragDirection == DragDirection.up) { if (dragDirection == DragDirection.up) {
historyAction = HistoryAction.undo; historyAction = HistoryAction.undo;
} else if (dragDirection == DragDirection.down) { } else if (dragDirection == DragDirection.down) {
historyAction = HistoryAction.redo; historyAction = HistoryAction.redo;
} else { } else {
historyAction = null; historyAction = null;
} }
if (historyAction != null) { if (historyAction != null) {
App.getVibrator().vibrate(); App.getVibrator().vibrate();
result = true; result = true;
historyControl.doHistoryAction(historyAction); historyControl.doHistoryAction(historyAction);
} }
return result; return result;
} }
} }

View File

@ -26,38 +26,38 @@ import android.content.SharedPreferences;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import org.solovyev.android.calculator.CalculatorFragmentType; import org.solovyev.android.calculator.CalculatorFragmentType;
import org.solovyev.android.calculator.Preferences;
import org.solovyev.android.calculator.Locator; import org.solovyev.android.calculator.Locator;
import org.solovyev.android.calculator.Preferences;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import javax.annotation.Nonnull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
public class HistoryFragment extends BaseHistoryFragment { public class HistoryFragment extends BaseHistoryFragment {
public HistoryFragment() { public HistoryFragment() {
super(CalculatorFragmentType.history); super(CalculatorFragmentType.history);
} }
@Override @Override
protected int getItemLayoutId() { protected int getItemLayoutId() {
return R.layout.history_item; return R.layout.history_item;
} }
@Nonnull @Nonnull
@Override @Override
protected List<CalculatorHistoryState> getHistoryItems() { protected List<CalculatorHistoryState> getHistoryItems() {
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
final boolean showIntermediateCalculations = Preferences.History.showIntermediateCalculations.getPreference(preferences); final boolean showIntermediateCalculations = Preferences.History.showIntermediateCalculations.getPreference(preferences);
final List<CalculatorHistoryState> historyStates = Locator.getInstance().getHistory().getStates(showIntermediateCalculations); final List<CalculatorHistoryState> historyStates = Locator.getInstance().getHistory().getStates(showIntermediateCalculations);
return new ArrayList<CalculatorHistoryState>(historyStates); return new ArrayList<CalculatorHistoryState>(historyStates);
} }
@Override @Override
protected void clearHistory() { protected void clearHistory() {
Locator.getInstance().getHistory().clear(); Locator.getInstance().getHistory().clear();
getAdapter().clear(); getAdapter().clear();
} }
} }

View File

@ -33,24 +33,24 @@ import javax.annotation.Nonnull;
*/ */
public class HistoryItemMenuData { public class HistoryItemMenuData {
@Nonnull @Nonnull
private final ArrayAdapter<CalculatorHistoryState> adapter; private final ArrayAdapter<CalculatorHistoryState> adapter;
@Nonnull @Nonnull
private final CalculatorHistoryState historyState; private final CalculatorHistoryState historyState;
public HistoryItemMenuData(@Nonnull CalculatorHistoryState historyState, ArrayAdapter<CalculatorHistoryState> adapter) { public HistoryItemMenuData(@Nonnull CalculatorHistoryState historyState, ArrayAdapter<CalculatorHistoryState> adapter) {
this.historyState = historyState; this.historyState = historyState;
this.adapter = adapter; this.adapter = adapter;
} }
@Nonnull @Nonnull
public CalculatorHistoryState getHistoryState() { public CalculatorHistoryState getHistoryState() {
return historyState; return historyState;
} }
@Nonnull @Nonnull
public ArrayAdapter<CalculatorHistoryState> getAdapter() { public ArrayAdapter<CalculatorHistoryState> getAdapter() {
return adapter; return adapter;
} }
} }

View File

@ -33,13 +33,13 @@ import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import javax.annotation.Nonnull;
import org.solovyev.android.calculator.Locator; import org.solovyev.android.calculator.Locator;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import org.solovyev.android.menu.LabeledMenuItem; import org.solovyev.android.menu.LabeledMenuItem;
import org.solovyev.common.text.Strings; import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull;
/** /**
* User: serso * User: serso
* Date: 12/18/11 * Date: 12/18/11
@ -47,122 +47,122 @@ import org.solovyev.common.text.Strings;
*/ */
public enum HistoryItemMenuItem implements LabeledMenuItem<HistoryItemMenuData> { public enum HistoryItemMenuItem implements LabeledMenuItem<HistoryItemMenuData> {
use(R.string.c_use) { use(R.string.c_use) {
@Override @Override
public void onClick(@Nonnull HistoryItemMenuData data, @Nonnull Context context) { public void onClick(@Nonnull HistoryItemMenuData data, @Nonnull Context context) {
BaseHistoryFragment.useHistoryItem(data.getHistoryState()); BaseHistoryFragment.useHistoryItem(data.getHistoryState());
} }
}, },
copy_expression(R.string.c_copy_expression) { copy_expression(R.string.c_copy_expression) {
@Override @Override
public void onClick(@Nonnull HistoryItemMenuData data, @Nonnull Context context) { public void onClick(@Nonnull HistoryItemMenuData data, @Nonnull Context context) {
final CalculatorHistoryState calculatorHistoryState = data.getHistoryState(); final CalculatorHistoryState calculatorHistoryState = data.getHistoryState();
final String text = calculatorHistoryState.getEditorState().getText(); final String text = calculatorHistoryState.getEditorState().getText();
if (!Strings.isEmpty(text)) { if (!Strings.isEmpty(text)) {
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE); final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE);
clipboard.setText(text); clipboard.setText(text);
Toast.makeText(context, context.getText(R.string.c_expression_copied), Toast.LENGTH_SHORT).show(); Toast.makeText(context, context.getText(R.string.c_expression_copied), Toast.LENGTH_SHORT).show();
} }
} }
}, },
copy_result(R.string.c_copy_result) { copy_result(R.string.c_copy_result) {
@Override @Override
public void onClick(@Nonnull HistoryItemMenuData data, @Nonnull Context context) { public void onClick(@Nonnull HistoryItemMenuData data, @Nonnull Context context) {
final CalculatorHistoryState calculatorHistoryState = data.getHistoryState(); final CalculatorHistoryState calculatorHistoryState = data.getHistoryState();
final String text = calculatorHistoryState.getDisplayState().getEditorState().getText(); final String text = calculatorHistoryState.getDisplayState().getEditorState().getText();
if (!Strings.isEmpty(text)) { if (!Strings.isEmpty(text)) {
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE); final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE);
clipboard.setText(text); clipboard.setText(text);
Toast.makeText(context, context.getText(R.string.c_result_copied), Toast.LENGTH_SHORT).show(); Toast.makeText(context, context.getText(R.string.c_result_copied), Toast.LENGTH_SHORT).show();
} }
} }
}, },
save(R.string.c_save) { save(R.string.c_save) {
@Override @Override
public void onClick(@Nonnull final HistoryItemMenuData data, @Nonnull final Context context) { public void onClick(@Nonnull final HistoryItemMenuData data, @Nonnull final Context context) {
final CalculatorHistoryState historyState = data.getHistoryState(); final CalculatorHistoryState historyState = data.getHistoryState();
if (!historyState.isSaved()) { if (!historyState.isSaved()) {
createEditHistoryDialog(data, context, true); createEditHistoryDialog(data, context, true);
} else { } else {
Toast.makeText(context, context.getText(R.string.c_history_already_saved), Toast.LENGTH_LONG).show(); Toast.makeText(context, context.getText(R.string.c_history_already_saved), Toast.LENGTH_LONG).show();
} }
} }
}, },
edit(R.string.c_edit) { edit(R.string.c_edit) {
@Override @Override
public void onClick(@Nonnull final HistoryItemMenuData data, @Nonnull final Context context) { public void onClick(@Nonnull final HistoryItemMenuData data, @Nonnull final Context context) {
final CalculatorHistoryState historyState = data.getHistoryState(); final CalculatorHistoryState historyState = data.getHistoryState();
if (historyState.isSaved()) { if (historyState.isSaved()) {
createEditHistoryDialog(data, context, false); createEditHistoryDialog(data, context, false);
} else { } else {
Toast.makeText(context, context.getText(R.string.c_history_must_be_saved), Toast.LENGTH_LONG).show(); Toast.makeText(context, context.getText(R.string.c_history_must_be_saved), Toast.LENGTH_LONG).show();
} }
} }
}, },
remove(R.string.c_remove) { remove(R.string.c_remove) {
@Override @Override
public void onClick(@Nonnull HistoryItemMenuData data, @Nonnull Context context) { public void onClick(@Nonnull HistoryItemMenuData data, @Nonnull Context context) {
final CalculatorHistoryState historyState = data.getHistoryState(); final CalculatorHistoryState historyState = data.getHistoryState();
if (historyState.isSaved()) { if (historyState.isSaved()) {
data.getAdapter().remove(historyState); data.getAdapter().remove(historyState);
Locator.getInstance().getHistory().removeSavedHistory(historyState); Locator.getInstance().getHistory().removeSavedHistory(historyState);
Toast.makeText(context, context.getText(R.string.c_history_was_removed), Toast.LENGTH_LONG).show(); Toast.makeText(context, context.getText(R.string.c_history_was_removed), Toast.LENGTH_LONG).show();
data.getAdapter().notifyDataSetChanged(); data.getAdapter().notifyDataSetChanged();
} }
} }
}; };
private static void createEditHistoryDialog(@Nonnull final HistoryItemMenuData data, @Nonnull final Context context, final boolean save) { private final int captionId;
final CalculatorHistoryState historyState = data.getHistoryState();
final LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); private HistoryItemMenuItem(int captionId) {
final View editView = layoutInflater.inflate(R.layout.history_edit, null); this.captionId = captionId;
final TextView historyExpression = (TextView) editView.findViewById(R.id.history_edit_expression); }
historyExpression.setText(BaseHistoryFragment.getHistoryText(historyState));
final EditText comment = (EditText) editView.findViewById(R.id.history_edit_comment); private static void createEditHistoryDialog(@Nonnull final HistoryItemMenuData data, @Nonnull final Context context, final boolean save) {
comment.setText(historyState.getComment()); final CalculatorHistoryState historyState = data.getHistoryState();
final AlertDialog.Builder builder = new AlertDialog.Builder(context) final LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
.setTitle(save ? R.string.c_save_history : R.string.c_edit_history) final View editView = layoutInflater.inflate(R.layout.history_edit, null);
.setCancelable(true) final TextView historyExpression = (TextView) editView.findViewById(R.id.history_edit_expression);
.setNegativeButton(R.string.c_cancel, null) historyExpression.setText(BaseHistoryFragment.getHistoryText(historyState));
.setPositiveButton(R.string.c_save, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (save) {
final CalculatorHistoryState savedHistoryItem = Locator.getInstance().getHistory().addSavedState(historyState);
savedHistoryItem.setComment(comment.getText().toString());
Locator.getInstance().getHistory().save();
// we don't need to add element to the adapter as adapter of another activity must be updated and not this
//data.getAdapter().add(savedHistoryItem);
} else {
historyState.setComment(comment.getText().toString());
Locator.getInstance().getHistory().save();
}
data.getAdapter().notifyDataSetChanged();
Toast.makeText(context, context.getText(R.string.c_history_saved), Toast.LENGTH_LONG).show();
}
})
.setView(editView);
builder.create().show(); final EditText comment = (EditText) editView.findViewById(R.id.history_edit_comment);
} comment.setText(historyState.getComment());
private final int captionId; final AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setTitle(save ? R.string.c_save_history : R.string.c_edit_history)
.setCancelable(true)
.setNegativeButton(R.string.c_cancel, null)
.setPositiveButton(R.string.c_save, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (save) {
final CalculatorHistoryState savedHistoryItem = Locator.getInstance().getHistory().addSavedState(historyState);
savedHistoryItem.setComment(comment.getText().toString());
Locator.getInstance().getHistory().save();
// we don't need to add element to the adapter as adapter of another activity must be updated and not this
//data.getAdapter().add(savedHistoryItem);
} else {
historyState.setComment(comment.getText().toString());
Locator.getInstance().getHistory().save();
}
data.getAdapter().notifyDataSetChanged();
Toast.makeText(context, context.getText(R.string.c_history_saved), Toast.LENGTH_LONG).show();
}
})
.setView(editView);
private HistoryItemMenuItem(int captionId) { builder.create().show();
this.captionId = captionId; }
}
@Nonnull @Nonnull
@Override @Override
public String getCaption(@Nonnull Context context) { public String getCaption(@Nonnull Context context) {
return context.getString(captionId); return context.getString(captionId);
} }
} }

View File

@ -26,30 +26,31 @@ import org.solovyev.android.calculator.CalculatorFragmentType;
import org.solovyev.android.calculator.Locator; import org.solovyev.android.calculator.Locator;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import javax.annotation.Nonnull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
public class SavedHistoryFragment extends BaseHistoryFragment { public class SavedHistoryFragment extends BaseHistoryFragment {
public SavedHistoryFragment() { public SavedHistoryFragment() {
super(CalculatorFragmentType.saved_history); super(CalculatorFragmentType.saved_history);
} }
@Override @Override
protected int getItemLayoutId() { protected int getItemLayoutId() {
return R.layout.saved_history_item; return R.layout.saved_history_item;
} }
@Nonnull @Nonnull
@Override @Override
protected List<CalculatorHistoryState> getHistoryItems() { protected List<CalculatorHistoryState> getHistoryItems() {
return new ArrayList<CalculatorHistoryState>(Locator.getInstance().getHistory().getSavedHistory()); return new ArrayList<CalculatorHistoryState>(Locator.getInstance().getHistory().getSavedHistory());
} }
@Override @Override
protected void clearHistory() { protected void clearHistory() {
Locator.getInstance().getHistory().clearSavedHistory(); Locator.getInstance().getHistory().clearSavedHistory();
getAdapter().clear(); getAdapter().clear();
} }
} }

View File

@ -25,11 +25,11 @@ package org.solovyev.android.calculator.history;
import android.widget.EditText; import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import org.solovyev.android.calculator.Editor;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.solovyev.android.calculator.Editor;
/** /**
* User: serso * User: serso
* Date: 12/17/11 * Date: 12/17/11
@ -37,32 +37,32 @@ import org.solovyev.android.calculator.Editor;
*/ */
public class TextViewEditorAdapter implements Editor { public class TextViewEditorAdapter implements Editor {
@Nonnull @Nonnull
private final TextView textView; private final TextView textView;
public TextViewEditorAdapter(@Nonnull TextView textView) { public TextViewEditorAdapter(@Nonnull TextView textView) {
this.textView = textView; this.textView = textView;
} }
@Override @Override
public CharSequence getText() { public CharSequence getText() {
return textView.getText().toString(); return textView.getText().toString();
} }
@Override @Override
public void setText(@Nullable CharSequence text) { public void setText(@Nullable CharSequence text) {
textView.setText(text); textView.setText(text);
} }
@Override @Override
public int getSelection() { public int getSelection() {
return textView.getSelectionStart(); return textView.getSelectionStart();
} }
@Override @Override
public void setSelection(int selection) { public void setSelection(int selection) {
if (textView instanceof EditText) { if (textView instanceof EditText) {
((EditText) textView).setSelection(selection); ((EditText) textView).setSelection(selection);
} }
} }
} }

View File

@ -10,60 +10,60 @@ import java.util.Locale;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
public final class Language { public final class Language {
@Nonnull @Nonnull
public final String code; public final String code;
@Nonnull @Nonnull
public final Locale locale; public final Locale locale;
@Nonnull @Nonnull
final String name; final String name;
public Language(@Nonnull String code, @Nonnull Locale locale) { public Language(@Nonnull String code, @Nonnull Locale locale) {
this.code = code; this.code = code;
this.locale = locale; this.locale = locale;
this.name = makeName(code, locale); this.name = makeName(code, locale);
} }
@Nonnull @Nonnull
public String getName(@Nonnull Context context) { private static String makeName(@Nonnull String code, @Nonnull Locale locale) {
if (!isSystem()) { if (code.equals(Languages.SYSTEM_LANGUAGE_CODE)) {
return name; return "";
} else { }
return context.getString(R.string.cpp_system_language) + " (" + locale.getDisplayLanguage(locale) + ")";
}
}
@Nonnull final int underscore = code.indexOf("_");
private static String makeName(@Nonnull String code, @Nonnull Locale locale) { if (underscore >= 0 && TextUtils.isEmpty(locale.getDisplayCountry(locale))) {
if (code.equals(Languages.SYSTEM_LANGUAGE_CODE)) { return locale.getDisplayName(locale) + " (" + code.substring(underscore + 1) + ")";
return ""; }
}
final int underscore = code.indexOf("_"); return locale.getDisplayName(locale);
if (underscore >= 0 && TextUtils.isEmpty(locale.getDisplayCountry(locale))) { }
return locale.getDisplayName(locale) + " (" + code.substring(underscore + 1) + ")";
}
return locale.getDisplayName(locale); @Nonnull
} public String getName(@Nonnull Context context) {
if (!isSystem()) {
return name;
} else {
return context.getString(R.string.cpp_system_language) + " (" + locale.getDisplayLanguage(locale) + ")";
}
}
public boolean isSystem() { public boolean isSystem() {
return code.equals(Languages.SYSTEM_LANGUAGE_CODE); return code.equals(Languages.SYSTEM_LANGUAGE_CODE);
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
final Language language = (Language) o; final Language language = (Language) o;
return code.equals(language.code); return code.equals(language.code);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return code.hashCode(); return code.hashCode();
} }
} }

View File

@ -23,147 +23,147 @@ import javax.annotation.Nullable;
public final class Languages implements SharedPreferences.OnSharedPreferenceChangeListener { public final class Languages implements SharedPreferences.OnSharedPreferenceChangeListener {
@Nonnull @Nonnull
private static final Locale[] locales = Locale.getAvailableLocales(); public static final String SYSTEM_LANGUAGE_CODE = "00";
@Nonnull @Nonnull
public static final String SYSTEM_LANGUAGE_CODE = "00"; public static final Language SYSTEM_LANGUAGE = new Language(SYSTEM_LANGUAGE_CODE, Locale.getDefault());
@Nonnull @Nonnull
public static final Language SYSTEM_LANGUAGE = new Language(SYSTEM_LANGUAGE_CODE, Locale.getDefault()); private static final Locale[] locales = Locale.getAvailableLocales();
@Nonnull @Nonnull
private final List<Language> list = new ArrayList<>(); private final List<Language> list = new ArrayList<>();
public void init(@Nonnull SharedPreferences preferences) { @Nullable
preferences.registerOnSharedPreferenceChangeListener(this); private static Language makeLanguage(@Nonnull String localeId) {
} final Locale locale = findLocaleById(localeId);
if (locale == null) {
return null;
}
return new Language(localeId, locale);
}
@Nonnull @Nullable
public List<Language> getList() { private static Locale findLocaleById(@Nonnull String id) {
Check.isMainThread(); for (Locale locale : locales) {
if (list.isEmpty()) { if (TextUtils.equals(locale.toString(), id)) {
loadList(); return locale;
} }
return list; }
}
private void loadList() { final String language;
Check.isMainThread(); final int underscore = id.indexOf("_");
Check.isEmpty(list); if (underscore >= 0) {
tryAddLanguage("ar"); language = id.substring(0, underscore);
tryAddLanguage("cs"); } else {
tryAddLanguage("en"); language = id;
tryAddLanguage("es_ES"); }
tryAddLanguage("de");
tryAddLanguage("fi");
tryAddLanguage("fr");
tryAddLanguage("it");
tryAddLanguage("it");
tryAddLanguage("pl");
tryAddLanguage("pt_BR");
tryAddLanguage("pt_PT");
tryAddLanguage("ru");
tryAddLanguage("tr");
tryAddLanguage("vi");
tryAddLanguage("uk");
tryAddLanguage("ja");
tryAddLanguage("zh_CN");
tryAddLanguage("zh_TW");
Collections.sort(list, new Comparator<Language>() {
@Override
public int compare(Language lhs, Language rhs) {
return lhs.name.compareTo(rhs.name);
}
});
list.add(0, SYSTEM_LANGUAGE);
}
private void tryAddLanguage(@Nonnull String locale) { for (Locale locale : locales) {
final Language language = makeLanguage(locale); if (TextUtils.equals(locale.getLanguage(), language)) {
if (language != null) { return locale;
list.add(language); }
} }
}
@Nullable Log.d("Languages", "No locale found for " + id);
private static Language makeLanguage(@Nonnull String localeId) { return null;
final Locale locale = findLocaleById(localeId); }
if (locale == null) {
return null;
}
return new Language(localeId, locale);
}
@Nullable public void init(@Nonnull SharedPreferences preferences) {
private static Locale findLocaleById(@Nonnull String id) { preferences.registerOnSharedPreferenceChangeListener(this);
for (Locale locale : locales) { }
if (TextUtils.equals(locale.toString(), id)) {
return locale;
}
}
final String language; @Nonnull
final int underscore = id.indexOf("_"); public List<Language> getList() {
if (underscore >= 0) { Check.isMainThread();
language = id.substring(0, underscore); if (list.isEmpty()) {
} else { loadList();
language = id; }
} return list;
}
for (Locale locale : locales) { private void loadList() {
if (TextUtils.equals(locale.getLanguage(), language)) { Check.isMainThread();
return locale; Check.isEmpty(list);
} tryAddLanguage("ar");
} tryAddLanguage("cs");
tryAddLanguage("en");
tryAddLanguage("es_ES");
tryAddLanguage("de");
tryAddLanguage("fi");
tryAddLanguage("fr");
tryAddLanguage("it");
tryAddLanguage("it");
tryAddLanguage("pl");
tryAddLanguage("pt_BR");
tryAddLanguage("pt_PT");
tryAddLanguage("ru");
tryAddLanguage("tr");
tryAddLanguage("vi");
tryAddLanguage("uk");
tryAddLanguage("ja");
tryAddLanguage("zh_CN");
tryAddLanguage("zh_TW");
Collections.sort(list, new Comparator<Language>() {
@Override
public int compare(Language lhs, Language rhs) {
return lhs.name.compareTo(rhs.name);
}
});
list.add(0, SYSTEM_LANGUAGE);
}
Log.d("Languages", "No locale found for " + id); private void tryAddLanguage(@Nonnull String locale) {
return null; final Language language = makeLanguage(locale);
} if (language != null) {
list.add(language);
}
}
@Nonnull @Nonnull
public Language getCurrent() { public Language getCurrent() {
return get(Preferences.Gui.language.getPreference(App.getPreferences())); return get(Preferences.Gui.language.getPreference(App.getPreferences()));
} }
@Nonnull @Nonnull
public Language get(@Nonnull String code) { public Language get(@Nonnull String code) {
Language language = findLanguageByCode(code); Language language = findLanguageByCode(code);
if (language != null) { if (language != null) {
return language; return language;
} }
return SYSTEM_LANGUAGE; return SYSTEM_LANGUAGE;
} }
@Nullable @Nullable
private Language findLanguageByCode(@Nonnull String code) { private Language findLanguageByCode(@Nonnull String code) {
for (Language language : getList()) { for (Language language : getList()) {
if (TextUtils.equals(language.code, code)) { if (TextUtils.equals(language.code, code)) {
return language; return language;
} }
} }
return null; return null;
} }
@Override @Override
public void onSharedPreferenceChanged(@Nonnull SharedPreferences p, String key) { public void onSharedPreferenceChanged(@Nonnull SharedPreferences p, String key) {
if (Preferences.Gui.language.isSameKey(key)) { if (Preferences.Gui.language.isSameKey(key)) {
updateLanguage(App.getApplication(), false); updateLanguage(App.getApplication(), false);
} }
} }
public void updateLanguage(@Nonnull Context context, boolean initial) { public void updateLanguage(@Nonnull Context context, boolean initial) {
final Language language = getCurrent(); final Language language = getCurrent();
// we don't need to set system language while starting up the app // we don't need to set system language while starting up the app
if (!initial || !language.isSystem()) { if (!initial || !language.isSystem()) {
if (!Locale.getDefault().equals(language.locale)) { if (!Locale.getDefault().equals(language.locale)) {
Locale.setDefault(language.locale); Locale.setDefault(language.locale);
} }
final Resources r = context.getResources(); final Resources r = context.getResources();
final DisplayMetrics dm = r.getDisplayMetrics(); final DisplayMetrics dm = r.getDisplayMetrics();
final Configuration c = r.getConfiguration(); final Configuration c = r.getConfiguration();
if (c.locale == null || !c.locale.equals(language.locale)) { if (c.locale == null || !c.locale.equals(language.locale)) {
c.locale = language.locale; c.locale = language.locale;
r.updateConfiguration(c, dm); r.updateConfiguration(c, dm);
} }
} }
} }
} }

View File

@ -67,14 +67,14 @@ import javax.annotation.Nullable;
public abstract class AbstractMathEntityListFragment<T extends MathEntity> extends ListFragment implements CalculatorEventListener { public abstract class AbstractMathEntityListFragment<T extends MathEntity> extends ListFragment implements CalculatorEventListener {
/* /*
********************************************************************** **********************************************************************
* *
* CONSTANTS * CONSTANTS
* *
********************************************************************** **********************************************************************
*/ */
public static final String MATH_ENTITY_CATEGORY_EXTRA_STRING = "org.solovyev.android.calculator.CalculatorVarsActivity_math_entity_category"; public static final String MATH_ENTITY_CATEGORY_EXTRA_STRING = "org.solovyev.android.calculator.CalculatorVarsActivity_math_entity_category";
/* /*
@ -84,251 +84,195 @@ public abstract class AbstractMathEntityListFragment<T extends MathEntity> exten
* *
********************************************************************** **********************************************************************
*/ */
@Nonnull
private final FragmentUi ui;
@Nonnull
private final Handler uiHandler = new Handler();
@Nullable
private MathEntityArrayAdapter<T> adapter;
@Nullable
private String category;
@Nullable protected AbstractMathEntityListFragment(@Nonnull CalculatorFragmentType fragmentType) {
private MathEntityArrayAdapter<T> adapter; ui = CalculatorApplication.getInstance().createFragmentHelper(fragmentType.getDefaultLayoutId(), fragmentType.getDefaultTitleResId());
}
@Nullable @Nonnull
private String category; public static Bundle createBundleFor(@Nonnull String categoryId) {
final Bundle result = new Bundle(1);
putCategory(result, categoryId);
return result;
}
@Nonnull static void putCategory(@Nonnull Bundle bundle, @Nonnull String categoryId) {
private final FragmentUi ui; bundle.putString(MATH_ENTITY_CATEGORY_EXTRA_STRING, categoryId);
}
@Nonnull @Override
private final Handler uiHandler = new Handler(); public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
protected AbstractMathEntityListFragment(@Nonnull CalculatorFragmentType fragmentType) { final Bundle bundle = getArguments();
ui = CalculatorApplication.getInstance().createFragmentHelper(fragmentType.getDefaultLayoutId(), fragmentType.getDefaultTitleResId()); if (bundle != null) {
} category = bundle.getString(MATH_ENTITY_CATEGORY_EXTRA_STRING);
}
@Override ui.onCreate(this);
public void onCreate(Bundle savedInstanceState) { }
super.onCreate(savedInstanceState);
final Bundle bundle = getArguments(); @Override
if (bundle != null) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
category = bundle.getString(MATH_ENTITY_CATEGORY_EXTRA_STRING); return ui.onCreateView(this, inflater, container);
} }
ui.onCreate(this); @Override
} public void onViewCreated(View root, Bundle savedInstanceState) {
super.onViewCreated(root, savedInstanceState);
@Override ui.onViewCreated(this, root);
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return ui.onCreateView(this, inflater, container);
}
@Override final ListView lv = getListView();
public void onViewCreated(View root, Bundle savedInstanceState) { lv.setTextFilterEnabled(true);
super.onViewCreated(root, savedInstanceState);
ui.onViewCreated(this, root); lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(final AdapterView<?> parent,
final View view,
final int position,
final long id) {
final AMenuItem<T> onClick = getOnClickAction();
if (onClick != null) {
onClick.onClick(((T) parent.getItemAtPosition(position)), getActivity());
}
}
});
final ListView lv = getListView(); getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
lv.setTextFilterEnabled(true); @Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
final T item = (T) parent.getItemAtPosition(position);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { final List<LabeledMenuItem<T>> menuItems = getMenuItemsOnLongClick(item);
public void onItemClick(final AdapterView<?> parent,
final View view,
final int position,
final long id) {
final AMenuItem<T> onClick = getOnClickAction();
if (onClick != null) {
onClick.onClick(((T) parent.getItemAtPosition(position)), getActivity());
}
}
});
getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { if (!menuItems.isEmpty()) {
@Override final ContextMenuBuilder<LabeledMenuItem<T>, T> menuBuilder = ContextMenuBuilder.newInstance(AbstractMathEntityListFragment.this.getActivity(), "math-entity-menu", ListContextMenu.newInstance(menuItems));
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { menuBuilder.build(item).show();
final T item = (T) parent.getItemAtPosition(position); }
final List<LabeledMenuItem<T>> menuItems = getMenuItemsOnLongClick(item); return true;
}
});
}
if (!menuItems.isEmpty()) { @Nullable
final ContextMenuBuilder<LabeledMenuItem<T>, T> menuBuilder = ContextMenuBuilder.newInstance(AbstractMathEntityListFragment.this.getActivity(), "math-entity-menu", ListContextMenu.newInstance(menuItems)); protected abstract AMenuItem<T> getOnClickAction();
menuBuilder.build(item).show();
}
return true; @Override
} public void onDestroyView() {
}); ui.onDestroyView(this);
} super.onDestroyView();
}
@Nullable @Override
protected abstract AMenuItem<T> getOnClickAction(); public void onDestroy() {
ui.onDestroy(this);
@Override super.onDestroy();
public void onDestroyView() { }
ui.onDestroyView(this);
super.onDestroyView();
}
@Override @Nonnull
public void onDestroy() { protected abstract List<LabeledMenuItem<T>> getMenuItemsOnLongClick(@Nonnull T item);
ui.onDestroy(this);
super.onDestroy(); @Override
} public void onPause() {
this.ui.onPause(this);
@Nonnull super.onPause();
protected abstract List<LabeledMenuItem<T>> getMenuItemsOnLongClick(@Nonnull T item); }
@Override @Override
public void onPause() { public void onResume() {
this.ui.onPause(this); super.onResume();
super.onPause(); this.ui.onResume(this);
}
@Override adapter = new MathEntityArrayAdapter<T>(getDescriptionGetter(), this.getActivity(), getMathEntitiesByCategory());
public void onResume() { setListAdapter(adapter);
super.onResume();
this.ui.onResume(this); sort();
}
adapter = new MathEntityArrayAdapter<T>(getDescriptionGetter(), this.getActivity(), getMathEntitiesByCategory()); @Nonnull
setListAdapter(adapter); private List<T> getMathEntitiesByCategory() {
final List<T> result = getMathEntities();
sort(); new Filter<T>(new JPredicate<T>() {
} @Override
public boolean apply(T t) {
return !isInCategory(t);
}
}).filter(result.iterator());
@Nonnull return result;
private List<T> getMathEntitiesByCategory() { }
final List<T> result = getMathEntities();
new Filter<T>(new JPredicate<T>() { protected boolean isInCategory(@Nullable T t) {
@Override return t != null && (category == null || Objects.areEqual(getMathEntityCategory(t), category));
public boolean apply(T t) { }
return !isInCategory(t);
}
}).filter(result.iterator());
return result; @Nonnull
} protected abstract MathEntityDescriptionGetter getDescriptionGetter();
protected boolean isInCategory(@Nullable T t) { @Nonnull
return t != null && (category == null || Objects.areEqual(getMathEntityCategory(t), category)); protected abstract List<T> getMathEntities();
}
@Nonnull @Nullable
protected abstract MathEntityDescriptionGetter getDescriptionGetter(); abstract String getMathEntityCategory(@Nonnull T t);
@Nonnull protected void sort() {
protected abstract List<T> getMathEntities(); final MathEntityArrayAdapter<T> localAdapter = adapter;
if (localAdapter != null) {
localAdapter.sort(new Comparator<T>() {
@Override
public int compare(T function1, T function2) {
return function1.getName().compareTo(function2.getName());
}
});
@Nullable localAdapter.notifyDataSetChanged();
abstract String getMathEntityCategory(@Nonnull T t); }
}
protected void sort() { public void addToAdapter(@Nonnull T mathEntity) {
final MathEntityArrayAdapter<T> localAdapter = adapter; if (this.adapter != null) {
if (localAdapter != null) { this.adapter.add(mathEntity);
localAdapter.sort(new Comparator<T>() { }
@Override }
public int compare(T function1, T function2) {
return function1.getName().compareTo(function2.getName());
}
});
localAdapter.notifyDataSetChanged(); public void removeFromAdapter(@Nonnull T mathEntity) {
} if (this.adapter != null) {
} this.adapter.remove(mathEntity);
}
}
protected static class MathEntityArrayAdapter<T extends MathEntity> extends ArrayAdapter<T> { public void notifyAdapter() {
if (this.adapter != null) {
this.adapter.notifyDataSetChanged();
}
}
@Nonnull @Nullable
private final MathEntityDescriptionGetter descriptionGetter; protected MathEntityArrayAdapter<T> getAdapter() {
return adapter;
}
private MathEntityArrayAdapter(@Nonnull MathEntityDescriptionGetter descriptionGetter, @Nonnull
@Nonnull Context context, protected Handler getUiHandler() {
@Nonnull List<T> objects) { return uiHandler;
super(context, R.layout.math_entity, R.id.math_entity_text, objects); }
this.descriptionGetter = descriptionGetter;
}
@Override @Override
public View getView(int position, @Nullable View convertView, ViewGroup parent) { public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
final ViewGroup result; }
if (convertView == null) {
result = (ViewGroup) super.getView(position, convertView, parent);
fillView(position, result);
} else {
result = (ViewGroup) convertView;
fillView(position, result);
}
return result;
}
private void fillView(int position, @Nonnull ViewGroup result) {
final T mathEntity = getItem(position);
final TextView text = (TextView) result.findViewById(R.id.math_entity_text);
text.setText(String.valueOf(mathEntity));
final String mathEntityDescription = descriptionGetter.getDescription(getContext(), mathEntity.getName());
final TextView description = (TextView) result.findViewById(R.id.math_entity_short_description);
if (!Strings.isEmpty(mathEntityDescription)) {
description.setVisibility(View.VISIBLE);
description.setText(mathEntityDescription);
} else {
description.setVisibility(View.GONE);
}
}
}
protected static class MathEntityDescriptionGetterImpl implements MathEntityDescriptionGetter {
@Nonnull
private final CalculatorMathRegistry<?> mathRegistry;
public MathEntityDescriptionGetterImpl(@Nonnull CalculatorMathRegistry<?> mathRegistry) {
this.mathRegistry = mathRegistry;
}
@Override
public String getDescription(@Nonnull Context context, @Nonnull String mathEntityName) {
return this.mathRegistry.getDescription(mathEntityName);
}
}
protected static interface MathEntityDescriptionGetter {
@Nullable
String getDescription(@Nonnull Context context, @Nonnull String mathEntityName);
}
public void addToAdapter(@Nonnull T mathEntity) {
if (this.adapter != null) {
this.adapter.add(mathEntity);
}
}
public void removeFromAdapter(@Nonnull T mathEntity) {
if (this.adapter != null) {
this.adapter.remove(mathEntity);
}
}
public void notifyAdapter() {
if (this.adapter != null) {
this.adapter.notifyDataSetChanged();
}
}
@Nullable
protected MathEntityArrayAdapter<T> getAdapter() {
return adapter;
}
@Nonnull
protected Handler getUiHandler() {
return uiHandler;
}
/* /*
********************************************************************** **********************************************************************
@ -338,18 +282,70 @@ public abstract class AbstractMathEntityListFragment<T extends MathEntity> exten
********************************************************************** **********************************************************************
*/ */
@Nonnull protected static interface MathEntityDescriptionGetter {
public static Bundle createBundleFor(@Nonnull String categoryId) {
final Bundle result = new Bundle(1);
putCategory(result, categoryId);
return result;
}
static void putCategory(@Nonnull Bundle bundle, @Nonnull String categoryId) { @Nullable
bundle.putString(MATH_ENTITY_CATEGORY_EXTRA_STRING, categoryId); String getDescription(@Nonnull Context context, @Nonnull String mathEntityName);
} }
@Override protected static class MathEntityArrayAdapter<T extends MathEntity> extends ArrayAdapter<T> {
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
} @Nonnull
private final MathEntityDescriptionGetter descriptionGetter;
private MathEntityArrayAdapter(@Nonnull MathEntityDescriptionGetter descriptionGetter,
@Nonnull Context context,
@Nonnull List<T> objects) {
super(context, R.layout.math_entity, R.id.math_entity_text, objects);
this.descriptionGetter = descriptionGetter;
}
@Override
public View getView(int position, @Nullable View convertView, ViewGroup parent) {
final ViewGroup result;
if (convertView == null) {
result = (ViewGroup) super.getView(position, convertView, parent);
fillView(position, result);
} else {
result = (ViewGroup) convertView;
fillView(position, result);
}
return result;
}
private void fillView(int position, @Nonnull ViewGroup result) {
final T mathEntity = getItem(position);
final TextView text = (TextView) result.findViewById(R.id.math_entity_text);
text.setText(String.valueOf(mathEntity));
final String mathEntityDescription = descriptionGetter.getDescription(getContext(), mathEntity.getName());
final TextView description = (TextView) result.findViewById(R.id.math_entity_short_description);
if (!Strings.isEmpty(mathEntityDescription)) {
description.setVisibility(View.VISIBLE);
description.setText(mathEntityDescription);
} else {
description.setVisibility(View.GONE);
}
}
}
protected static class MathEntityDescriptionGetterImpl implements MathEntityDescriptionGetter {
@Nonnull
private final CalculatorMathRegistry<?> mathRegistry;
public MathEntityDescriptionGetterImpl(@Nonnull CalculatorMathRegistry<?> mathRegistry) {
this.mathRegistry = mathRegistry;
}
@Override
public String getDescription(@Nonnull Context context, @Nonnull String mathEntityName) {
return this.mathRegistry.getDescription(mathEntityName);
}
}
} }

View File

@ -25,58 +25,66 @@ package org.solovyev.android.calculator.math.edit;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import org.solovyev.android.calculator.*;
import org.solovyev.android.calculator.AndroidFunctionCategory;
import org.solovyev.android.calculator.BaseActivity;
import org.solovyev.android.calculator.CalculatorEventData;
import org.solovyev.android.calculator.CalculatorEventListener;
import org.solovyev.android.calculator.CalculatorEventType;
import org.solovyev.android.calculator.CalculatorFragmentType;
import org.solovyev.android.calculator.FunctionCategory;
import org.solovyev.android.calculator.R;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public class CalculatorFunctionsActivity extends BaseActivity implements CalculatorEventListener { public class CalculatorFunctionsActivity extends BaseActivity implements CalculatorEventListener {
public CalculatorFunctionsActivity() { public CalculatorFunctionsActivity() {
super(R.layout.main_empty, CalculatorFunctionsActivity.class.getSimpleName()); super(R.layout.main_empty, CalculatorFunctionsActivity.class.getSimpleName());
} }
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
final Bundle bundle; final Bundle bundle;
final Intent intent = getIntent(); final Intent intent = getIntent();
if (intent != null) { if (intent != null) {
bundle = intent.getExtras(); bundle = intent.getExtras();
} else { } else {
bundle = null; bundle = null;
} }
final CalculatorFragmentType fragmentType = CalculatorFragmentType.functions; final CalculatorFragmentType fragmentType = CalculatorFragmentType.functions;
for (FunctionCategory category : FunctionCategory.getCategoriesByTabOrder()) { for (FunctionCategory category : FunctionCategory.getCategoriesByTabOrder()) {
final AndroidFunctionCategory androidCategory = AndroidFunctionCategory.valueOf(category); final AndroidFunctionCategory androidCategory = AndroidFunctionCategory.valueOf(category);
if (androidCategory != null) { if (androidCategory != null) {
final Bundle fragmentParameters; final Bundle fragmentParameters;
if (category == FunctionCategory.my && bundle != null) { if (category == FunctionCategory.my && bundle != null) {
AbstractMathEntityListFragment.putCategory(bundle, category.name()); AbstractMathEntityListFragment.putCategory(bundle, category.name());
fragmentParameters = bundle; fragmentParameters = bundle;
} else { } else {
fragmentParameters = AbstractMathEntityListFragment.createBundleFor(category.name()); fragmentParameters = AbstractMathEntityListFragment.createBundleFor(category.name());
} }
ui.addTab(this, fragmentType.createSubFragmentTag(category.name()), fragmentType.getFragmentClass(), fragmentParameters, androidCategory.getCaptionId(), R.id.main_layout); ui.addTab(this, fragmentType.createSubFragmentTag(category.name()), fragmentType.getFragmentClass(), fragmentParameters, androidCategory.getCaptionId(), R.id.main_layout);
} else { } else {
Log.e(CalculatorFunctionsActivity.class.getSimpleName(), "Unable to find android function category for " + category); Log.e(CalculatorFunctionsActivity.class.getSimpleName(), "Unable to find android function category for " + category);
} }
} }
} }
@Override @Override
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) { public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {
switch (calculatorEventType) { switch (calculatorEventType) {
case use_function: case use_function:
this.finish(); this.finish();
break; break;
} }
} }
} }

Some files were not shown because too many files have changed in this diff Show More