Calculator++ widget

This commit is contained in:
Sergey Solovyev 2012-10-20 16:22:25 +04:00
parent 42acacee32
commit bf0aa44f4f
85 changed files with 2708 additions and 1960 deletions

View File

@ -7,19 +7,7 @@ package org.solovyev.android.calculator;
*/
public final class CalculatorButtonActions {
public static final String ERASE = "erase";
public static final String PASTE = "paste";
public static final String COPY = "copy";
public static final String CLEAR = "clear";
public static final String SHOW_FUNCTIONS = "functions";
public static final String SHOW_VARS = "vars";
public static final String SHOW_OPERATORS = "operators";
private CalculatorButtonActions() {
throw new AssertionError();
}
public static final String SHOW_HISTORY = "history";
public static final String MOVE_CURSOR_RIGHT = "";
public static final String MOVE_CURSOR_LEFT = "";
}

View File

@ -5,12 +5,14 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.jscl.JsclOperation;
import java.io.Serializable;
/**
* User: serso
* Date: 9/20/12
* Time: 9:50 PM
*/
public interface CalculatorDisplayViewState {
public interface CalculatorDisplayViewState extends Serializable {
@NotNull
String getText();

View File

@ -13,11 +13,19 @@ import org.solovyev.common.text.StringUtils;
*/
public class CalculatorDisplayViewStateImpl implements CalculatorDisplayViewState {
/*
**********************************************************************
*
* FIELDS
*
**********************************************************************
*/
@NotNull
private JsclOperation operation = JsclOperation.numeric;
@Nullable
private Generic result;
private transient Generic result;
@Nullable
private String stringResult = "";
@ -29,6 +37,14 @@ public class CalculatorDisplayViewStateImpl implements CalculatorDisplayViewStat
private int selection = 0;
/*
**********************************************************************
*
* CONSTRUCTORS
*
**********************************************************************
*/
private CalculatorDisplayViewStateImpl() {
}
@ -62,6 +78,14 @@ public class CalculatorDisplayViewStateImpl implements CalculatorDisplayViewStat
return calculatorDisplayState;
}
/*
**********************************************************************
*
* METHODS
*
**********************************************************************
*/
@NotNull
@Override
public String getText() {

View File

@ -65,7 +65,7 @@ public class CalculatorEditorImpl implements CalculatorEditor {
setViewState(newViewState, true);
}
private void setViewState(@NotNull CalculatorEditorViewState newViewState, boolean fireEvent) {
private void setViewState(@NotNull CalculatorEditorViewState newViewState, boolean majorChanges) {
synchronized (viewLock) {
final CalculatorEditorViewState oldViewState = this.lastViewState;
@ -74,8 +74,10 @@ public class CalculatorEditorImpl implements CalculatorEditor {
this.view.setState(newViewState);
}
if (fireEvent) {
if (majorChanges) {
calculator.fireCalculatorEvent(CalculatorEventType.editor_state_changed, new CalculatorEditorChangeEventDataImpl(oldViewState, newViewState));
} else {
calculator.fireCalculatorEvent(CalculatorEventType.editor_state_changed_light, new CalculatorEditorChangeEventDataImpl(oldViewState, newViewState));
}
}
}

View File

@ -2,12 +2,14 @@ package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
import java.io.Serializable;
/**
* User: Solovyev_S
* Date: 21.09.12
* Time: 11:48
*/
public interface CalculatorEditorViewState {
public interface CalculatorEditorViewState extends Serializable {
@NotNull
String getText();

View File

@ -58,6 +58,7 @@ public enum CalculatorEventType {
// @NotNull org.solovyev.android.calculator.CalculatorEditorChangeEventData
editor_state_changed,
editor_state_changed_light,
// @NotNull CalculatorDisplayChangeEventData
display_state_changed,
@ -88,8 +89,6 @@ public enum CalculatorEventType {
clear_history_requested,
show_history,
/*
**********************************************************************
*
@ -123,10 +122,24 @@ public enum CalculatorEventType {
*
**********************************************************************
*/
show_history,
show_history_detached,
show_functions,
show_functions_detached,
show_vars,
show_operators;
show_vars_detached,
open_app,
show_operators,
show_operators_detached,
show_settings,
show_settings_detached,
show_like_dialog;
public boolean isOfType(@NotNull CalculatorEventType... types) {
for (CalculatorEventType type : types) {

View File

@ -62,28 +62,10 @@ public class CalculatorKeyboardImpl implements CalculatorKeyboard {
private boolean processSpecialButtons(@NotNull String text) {
boolean result = false;
if (CalculatorButtonActions.MOVE_CURSOR_LEFT.equals(text)) {
this.moveCursorLeft();
final CalculatorSpecialButton button = CalculatorSpecialButton.getByActionCode(text);
if ( button != null ) {
button.onClick(this);
result = true;
} else if (CalculatorButtonActions.MOVE_CURSOR_RIGHT.equals(text)) {
this.moveCursorRight();
result = true;
} else if (CalculatorButtonActions.SHOW_HISTORY.equals(text)) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_history, null);
} else if (CalculatorButtonActions.ERASE.equals(text)) {
CalculatorLocatorImpl.getInstance().getEditor().erase();
} else if (CalculatorButtonActions.COPY.equals(text)) {
copyButtonPressed();
} else if (CalculatorButtonActions.PASTE.equals(text)) {
pasteButtonPressed();
} else if (CalculatorButtonActions.CLEAR.equals(text)) {
clearButtonPressed();
} else if (CalculatorButtonActions.SHOW_FUNCTIONS.equals(text)) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_functions, null);
} else if (CalculatorButtonActions.SHOW_OPERATORS.equals(text)) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_operators, null);
} else if (CalculatorButtonActions.SHOW_VARS.equals(text)) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_vars, null);
}
return result;

View File

@ -19,4 +19,6 @@ public interface CalculatorNotifier {
void showMessage(@NotNull Integer messageCode, @NotNull MessageType messageType, @NotNull List<Object> parameters);
void showMessage(@NotNull Integer messageCode, @NotNull MessageType messageType, @Nullable Object... parameters);
void showDebugMessage(@Nullable String tag, @NotNull String message);
}

View File

@ -0,0 +1,155 @@
package org.solovyev.android.calculator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: serso
* Date: 10/20/12
* Time: 2:05 PM
*/
public enum CalculatorSpecialButton {
history("history") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_history, null);
}
},
history_detached("history_detached") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_history_detached, null);
}
},
cursor_right("") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
keyboard.moveCursorRight();
}
},
cursor_left("") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
keyboard.moveCursorLeft();
}
},
settings("settings") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_settings, null);
}
},
settings_detached("settings_detached") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_settings_detached, null);
}
},
like("like") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_like_dialog, null);
}
},
erase("erase") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
CalculatorLocatorImpl.getInstance().getEditor().erase();
}
},
paste("paste") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
keyboard.pasteButtonPressed();
}
},
copy("copy") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
keyboard.copyButtonPressed();
}
},
equals("=") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
CalculatorLocatorImpl.getInstance().getCalculator().evaluate();
}
},
clear("clear") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
keyboard.clearButtonPressed();
}
},
functions("functions") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_functions, null);
}
},
functions_detached("functions_detached") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_functions_detached, null);
}
},
open_app("open_app") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.open_app, null);
}
},
vars("vars") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_vars, null);
}
},
vars_detached("vars_detached") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_vars_detached, null);
}
},
operators("operators") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_operators, null);
}
},
operators_detached("operators_detached") {
@Override
public void onClick(@NotNull CalculatorKeyboard keyboard) {
CalculatorLocatorImpl.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.show_operators_detached, null);
}
};
@NotNull
private final String actionCode;
CalculatorSpecialButton(@NotNull String actionCode) {
this.actionCode = actionCode;
}
@NotNull
public String getActionCode() {
return actionCode;
}
@Nullable
public static CalculatorSpecialButton getByActionCode(@NotNull String actionCode) {
for (CalculatorSpecialButton button : values()) {
if (button.getActionCode().equals(actionCode)) {
return button;
}
}
return null;
}
public abstract void onClick(@NotNull CalculatorKeyboard keyboard);
}

View File

@ -25,4 +25,8 @@ public class DummyCalculatorNotifier implements CalculatorNotifier {
@Override
public void showMessage(@NotNull Integer messageCode, @NotNull MessageType messageType, @Nullable Object... parameters) {
}
@Override
public void showDebugMessage(@Nullable String tag, @NotNull String message) {
}
}

View File

@ -42,6 +42,7 @@ public class ListCalculatorEventContainer implements CalculatorEventContainer {
final CalculatorLogger logger = CalculatorLocatorImpl.getInstance().getLogger();
for (CalculatorEvent e : calculatorEvents) {
CalculatorLocatorImpl.getInstance().getLogger().debug(TAG, "Event fired: " + e.getCalculatorEventType());
for (CalculatorEventListener listener : listeners) {
/*long startTime = System.currentTimeMillis();*/
listener.onCalculatorEvent(e.getCalculatorEventData(), e.getCalculatorEventType(), e.getData());

View File

@ -0,0 +1,23 @@
package org.solovyev.android.calculator;
import jscl.math.Expression;
import org.junit.Test;
import org.solovyev.android.calculator.jscl.JsclOperation;
/**
* User: serso
* Date: 10/20/12
* Time: 12:24 PM
*/
public class CalculatorDisplayViewStateImplTest {
@Test
public void testSerializable() throws Exception {
CalculatorTestUtils.testSerialization(CalculatorDisplayViewStateImpl.newValidState(JsclOperation.numeric, null, "test", 3));
CalculatorTestUtils.testSerialization(CalculatorDisplayViewStateImpl.newValidState(JsclOperation.numeric, Expression.valueOf("3"), "test", 3));
CalculatorTestUtils.testSerialization(CalculatorDisplayViewStateImpl.newValidState(JsclOperation.simplify, Expression.valueOf("3+3"), "test", 3));
CalculatorTestUtils.testSerialization(CalculatorDisplayViewStateImpl.newDefaultInstance());
CalculatorTestUtils.testSerialization(CalculatorDisplayViewStateImpl.newErrorState(JsclOperation.numeric, "ertert"));
}
}

View File

@ -0,0 +1,21 @@
package org.solovyev.android.calculator;
import junit.framework.Assert;
import org.junit.Test;
/**
* User: serso
* Date: 10/20/12
* Time: 12:31 PM
*/
public class CalculatorEditorViewStateImplTest {
@Test
public void testSerialization() throws Exception {
CalculatorTestUtils.testSerialization(CalculatorEditorViewStateImpl.newDefaultInstance());
CalculatorEditorViewState out = CalculatorTestUtils.testSerialization(CalculatorEditorViewStateImpl.newInstance("treter", 2));
Assert.assertEquals(2, out.getSelection());
Assert.assertEquals("treter", out.getText());
}
}

View File

@ -8,6 +8,7 @@ import org.mockito.Mockito;
import org.solovyev.android.calculator.history.CalculatorHistory;
import org.solovyev.android.calculator.jscl.JsclOperation;
import java.io.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@ -74,6 +75,32 @@ public class CalculatorTestUtils {
assertError(expression, JsclOperation.numeric);
}
public static <S extends Serializable> S testSerialization(@NotNull S serializable) throws IOException, ClassNotFoundException {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(out);
oos.writeObject(serializable);
} finally {
if (oos != null) {
oos.close();
}
}
byte[] serialized = out.toByteArray();
Assert.assertTrue(serialized.length > 0);
final ObjectInputStream resultStream = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray()));
final S result = (S) resultStream.readObject();
Assert.assertNotNull(result);
return result;
}
private static final class TestCalculatorEventListener implements CalculatorEventListener {
@Nullable

View File

@ -11,7 +11,7 @@
<application android:debuggable="false" android:hardwareAccelerated="false" android:icon="@drawable/icon" android:label="@string/c_app_name" android:name=".CalculatorApplication" android:theme="@style/metro_blue_theme">
<activity android:label="@string/c_app_name" android:name=".CalculatorActivity" android:windowSoftInputMode="adjustPan">
<activity android:label="@string/c_app_name" android:name=".CalculatorActivity" android:windowSoftInputMode="adjustPan" android:clearTaskOnLaunch="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@ -48,11 +48,14 @@
<receiver
android:icon="@drawable/icon"
android:label="Example Widget"
android:label="@string/c_app_name"
android:name=".widget.CalculatorWidgetProvider">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
<action android:name="org.solovyev.calculator.widget.EDITOR_STATE_CHANGED"/>
<action android:name="org.solovyev.calculator.widget.DISPLAY_STATE_CHANGED"/>
<action android:name="org.solovyev.calculator.widget.BUTTON_PRESSED"/>
</intent-filter>
<meta-data

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 868 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -8,7 +8,7 @@
<org.solovyev.android.view.ColorButton xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:c="http://schemas.android.com/apk/res/org.solovyev.android.calculator"
a:id="@+id/pasteButton"
a:id="@+id/copyButton"
a:drawableTop="@drawable/kb_copy"
style="?controlImageButtonStyle"
a:onClick="copyButtonClickHandler"/>

View File

@ -8,7 +8,7 @@
<org.solovyev.android.view.drag.DirectionDragButton xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:c="http://schemas.android.com/apk/res/org.solovyev.android.calculator"
a:id="@+id/squareBracketsButton"
a:id="@+id/periodButton"
a:text="."
c:textUp=","
c:directionTextScale="0.5"

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2009-2011. Created by serso aka se.solovyev.
~ For more information, please, contact se.solovyev@gmail.com
~ or visit http://se.solovyev.org
-->
<ImageButton xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/appButton"
a:src="@drawable/kb_logo"
style="@style/widget_metro_control_image_button_style"
a:contentDescription="App"/>

View File

@ -10,4 +10,4 @@
a:id="@+id/clearButton"
a:text="@string/c_clear"
a:textStyle="bold"
style="@style/metro_control_image_button_style"/>
style="@style/widget_metro_control_button_style"/>

View File

@ -6,7 +6,8 @@
~ or visit http://se.solovyev.org
-->
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/pasteButton"
a:drawableTop="@drawable/kb_copy"
style="@style/metro_control_image_button_style"/>
<ImageButton xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/copyButton"
a:src="@drawable/kb_copy"
style="@style/widget_metro_control_image_button_style"
a:contentDescription="Copy"/>

View File

@ -9,9 +9,8 @@
<TextView
xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/calculatorDisplay"
style="@style/display_style"
style="@style/widget_display_style"
a:textIsSelectable="true"
a:padding="@dimen/display_padding"
a:inputType="textMultiLine"
a:maxLines="3"
a:scrollHorizontally="false"
a:scrollbars="none"/>
a:singleLine="false"
a:scrollbars="vertical"/>

View File

@ -9,4 +9,4 @@
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/divisionButton"
a:text="/"
style="@style/metro_blue_operation_button_style"/>
style="@style/widget_metro_blue_operation_button_style"/>

View File

@ -7,6 +7,6 @@
-->
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/squareBracketsButton"
a:id="@+id/periodButton"
a:text="."
style="@style/metro_digit_button_style"/>

View File

@ -15,7 +15,7 @@
<TextView
a:id="@+id/calculatorEditor"
style="@style/editor_style"
style="@style/widget_editor_style"
a:textIsSelectable="true"
a:singleLine="false"
a:scrollbars="vertical"

View File

@ -9,4 +9,4 @@
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/eightDigitButton"
a:text="8"
style="@style/metro_digit_button_style"/>
style="@style/widget_metro_digit_button_style"/>

View File

@ -9,4 +9,4 @@
xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/equalsButton"
a:text="="
style="@style/metro_control_button_style"/>
style="@style/widget_metro_control_button_style"/>

View File

@ -6,7 +6,8 @@
~ or visit http://se.solovyev.org
-->
<Button xmlns:a="http://schemas.android.com/apk/res/android"
<ImageButton xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/eraseButton"
a:drawableTop="@drawable/kb_delete"
style="@style/metro_control_image_button_style"/>
a:src="@drawable/kb_delete"
style="@style/widget_metro_control_image_button_style"
a:contentDescription="Erase"/>

View File

@ -8,4 +8,4 @@
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/fiveDigitButton"
a:text="5"
style="@style/metro_digit_button_style"/>
style="@style/widget_metro_digit_button_style"/>

View File

@ -8,4 +8,4 @@
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/fourDigitButton"
a:text="4"
style="@style/metro_digit_button_style"/>
style="@style/widget_metro_digit_button_style"/>

View File

@ -10,4 +10,4 @@
a:id="@+id/functionsButton"
a:text="ƒ(x)"
a:textStyle="italic"
style="@style/metro_control_button_style"/>
style="@style/widget_metro_control_button_style"/>

View File

@ -8,5 +8,5 @@
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/historyButton"
a:text="@string/c_history_button"
style="@style/metro_control_button_style"
style="@style/widget_metro_control_button_style"
a:textStyle="bold"/>

View File

@ -13,6 +13,7 @@
<include layout="@layout/widget_eight_digit_button"/>
<include layout="@layout/widget_nine_digit_button"/>
<include layout="@layout/widget_multiplication_button"/>
<include layout="@layout/widget_percent_button"/>
<include layout="@layout/widget_clear_button"/>
</LinearLayout>
@ -25,6 +26,7 @@
<include layout="@layout/widget_five_digit_button"/>
<include layout="@layout/widget_six_digit_button"/>
<include layout="@layout/widget_division_button"/>
<include layout="@layout/widget_power_button"/>
<include layout="@layout/widget_erase_button"/>
</LinearLayout>
@ -37,6 +39,7 @@
<include layout="@layout/widget_two_digit_button"/>
<include layout="@layout/widget_three_digit_button"/>
<include layout="@layout/widget_plus_button"/>
<include layout="@layout/widget_like_button"/>
<include layout="@layout/widget_copy_button"/>
</LinearLayout>
@ -49,6 +52,7 @@
<include layout="@layout/widget_zero_digit_button"/>
<include layout="@layout/widget_dot_button"/>
<include layout="@layout/widget_subtraction_button"/>
<include layout="@layout/widget_settings_button"/>
<include layout="@layout/widget_paste_button"/>
</LinearLayout>
@ -62,6 +66,7 @@
<include layout="@layout/widget_right_button"/>
<include layout="@layout/widget_vars_button"/>
<include layout="@layout/widget_functions_button"/>
<include layout="@layout/widget_app_button"/>
<include layout="@layout/widget_history_button"/>
</LinearLayout>

View File

@ -4,7 +4,7 @@
a:layout_width="match_parent"
a:layout_height="match_parent"
a:orientation="vertical"
style="@style/default_main_layout_style">
style="@style/widget_main_layout_style">
<include layout="@layout/widget_editor"
a:layout_weight="2"
@ -22,9 +22,9 @@
a:layout_height="match_parent"/>
<include layout="@layout/widget_display"
a:layout_weight="4"
a:layout_weight="5"
a:layout_width="0dp"
a:layout_height="match_parent"/>
a:layout_height="wrap_content"/>
</LinearLayout>

View File

@ -9,4 +9,4 @@
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/leftButton"
a:text="◀"
style="@style/metro_control_button_style"/>
style="@style/widget_metro_control_button_style"/>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2009-2011. Created by serso aka se.solovyev.
~ For more information, please, contact se.solovyev@gmail.com
~ or visit http://se.solovyev.org
-->
<ImageButton xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/likeButton"
a:src="@drawable/kb_facebook"
style="@style/widget_metro_control_image_button_style"
a:contentDescription="Like"/>

View File

@ -9,4 +9,4 @@
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/multiplicationButton"
a:text="×"
style="@style/metro_blue_operation_button_style"/>
style="@style/widget_metro_blue_operation_button_style"/>

View File

@ -9,4 +9,4 @@
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/nineDigitButton"
a:text="9"
style="@style/metro_digit_button_style"/>
style="@style/widget_metro_digit_button_style"/>

View File

@ -9,4 +9,4 @@
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/oneDigitButton"
a:text="1"
style="@style/metro_digit_button_style"/>
style="@style/widget_metro_digit_button_style"/>

View File

@ -6,7 +6,8 @@
~ or visit http://se.solovyev.org
-->
<Button xmlns:a="http://schemas.android.com/apk/res/android"
<ImageButton xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/pasteButton"
a:drawableTop="@drawable/kb_paste"
style="@style/metro_control_image_button_style"/>
a:src="@drawable/kb_paste"
style="@style/widget_metro_control_image_button_style"
a:contentDescription="Paste"/>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2009-2011. Created by serso aka se.solovyev.
~ For more information, please, contact se.solovyev@gmail.com
~ or visit http://se.solovyev.org
-->
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/percentButton"
a:text="%"
style="@style/widget_metro_blue_operation_button_style"/>

View File

@ -8,4 +8,4 @@
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/plusButton"
a:text="+"
style="@style/metro_blue_operation_button_style"/>
style="@style/widget_metro_blue_operation_button_style"/>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2009-2011. Created by serso aka se.solovyev.
~ For more information, please, contact se.solovyev@gmail.com
~ or visit http://se.solovyev.org
-->
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/powerButton"
a:text="^"
style="@style/widget_metro_blue_operation_button_style"/>

View File

@ -9,4 +9,4 @@
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/rightButton"
a:text="▶"
style="@style/metro_control_button_style"/>
style="@style/widget_metro_control_button_style"/>

View File

@ -9,4 +9,4 @@
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/roundBracketsButton"
a:text="()"
style="@style/metro_digit_button_style"/>
style="@style/widget_metro_digit_button_style"/>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2009-2011. Created by serso aka se.solovyev.
~ For more information, please, contact se.solovyev@gmail.com
~ or visit http://se.solovyev.org
-->
<ImageButton xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/settingsButton"
a:src="@drawable/kb_settings"
style="@style/widget_metro_control_image_button_style"
a:contentDescription="Settings"/>

View File

@ -3,4 +3,4 @@
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/sevenDigitButton"
a:text="7"
style="@style/metro_digit_button_style"/>
style="@style/widget_metro_digit_button_style"/>

View File

@ -9,4 +9,4 @@
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/sixDigitButton"
a:text="6"
style="@style/metro_digit_button_style"/>
style="@style/widget_metro_digit_button_style"/>

View File

@ -8,4 +8,4 @@
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/subtractionButton"
a:text="-"
style="@style/metro_blue_operation_button_style"/>
style="@style/widget_metro_blue_operation_button_style"/>

View File

@ -9,4 +9,4 @@
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/threeDigitButton"
a:text="3"
style="@style/metro_digit_button_style"/>
style="@style/widget_metro_digit_button_style"/>

View File

@ -9,4 +9,4 @@
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/twoDigitButton"
a:text="2"
style="@style/metro_digit_button_style"/>
style="@style/widget_metro_digit_button_style"/>

View File

@ -10,4 +10,4 @@
a:id="@+id/varsButton"
a:text="π,…"
a:textStyle="italic"
style="@style/metro_control_button_style"/>
style="@style/widget_metro_control_button_style"/>

View File

@ -9,4 +9,4 @@
<Button xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/zeroDigitButton"
a:text="0"
style="@style/metro_digit_button_style"/>
style="@style/widget_metro_digit_button_style"/>

View File

@ -11,6 +11,7 @@
<color name="button_ce_text_color">#ffffffff</color>
<color name="default_text_color">#ffffffff</color>
<color name="display_error_text_color">#ff393939</color>
<color name="widget_cursor_color">#ff707070</color>
<color name="selected_angle_unit_text_color">#ffffff99</color>
<color name="default_background">#ff000000</color>
<color name="pane_background">#ff1f1f1f</color>

View File

@ -15,6 +15,10 @@
<dimen name="math_entity_text_size">20sp</dimen>
<dimen name="math_entity_description_text_size">15sp</dimen>
<dimen name="widget_editor_text_size">25sp</dimen>
<dimen name="widget_keyboard_button_text_size">20dp</dimen>
<dimen name="widget_display_text_size">25sp</dimen>
<!--only for not multipane-->
<dimen name="editor_padding">5dp</dimen>
<dimen name="display_padding">3dp</dimen>

View File

@ -58,6 +58,14 @@
<item name="android:textSize">@dimen/display_text_size</item>
</style>
<style name="widget_editor_style" parent="editor_style">
<item name="android:textSize">@dimen/widget_editor_text_size</item>
</style>
<style name="widget_display_style" parent="display_style">
<item name="android:textSize">@dimen/widget_display_text_size</item>
</style>
<style name="about_style" parent="default_text">
<item name="android:gravity">center</item>
<item name="android:layout_width">fill_parent</item>

View File

@ -80,6 +80,10 @@
<item name="android:layout_width">match_parent</item>
</style>
<style name="widget_main_layout_style" parent="default_main_layout_style">
<item name="android:padding">1dp</item>
</style>
<style name="default_actionbar_style" parent="@style/Widget.Sherlock.ActionBar">
<item name="background">@drawable/default_abs__ab_transparent_dark_holo</item>
<item name="android:background">@drawable/default_abs__ab_transparent_dark_holo</item>

View File

@ -4,18 +4,34 @@
<item name="android:background">@drawable/metro_button_dark</item>
</style>
<style name="widget_metro_digit_button_style" parent="metro_digit_button_style">
<item name="android:textSize">@dimen/widget_keyboard_button_text_size</item>
</style>
<style name="metro_control_button_style" parent="metro_digit_button_style">
<item name="android:background">@drawable/metro_button_light</item>
</style>
<style name="widget_metro_control_button_style" parent="metro_control_button_style">
<item name="android:textSize">@dimen/widget_keyboard_button_text_size</item>
</style>
<style name="metro_blue_operation_button_style" parent="metro_digit_button_style">
<item name="android:background">@drawable/metro_blue_button</item>
</style>
<style name="widget_metro_blue_operation_button_style" parent="metro_blue_operation_button_style">
<item name="android:textSize">@dimen/widget_keyboard_button_text_size</item>
</style>
<style name="metro_control_image_button_style" parent="metro_control_button_style">
<item name="android:padding">6dp</item>
</style>
<style name="widget_metro_control_image_button_style" parent="metro_control_image_button_style">
<item name="android:scaleType">center</item>
</style>
<style name="metro_blue_fragment_list_view_item_style" parent="default_fragment_list_view_item_style">
<item name="background">@drawable/metro_blue_list_item</item>
<item name="android:background">@drawable/metro_blue_list_item</item>

View File

@ -1,34 +1,17 @@
<resources>
<style name="metro_digit_button_style" parent="keyboard_button_style">
<item name="android:background">@drawable/metro_button_dark</item>
</style>
<style name="metro_control_button_style" parent="metro_digit_button_style">
<item name="android:background">@drawable/metro_button_light</item>
</style>
<style name="metro_green_operation_button_style" parent="metro_digit_button_style">
<item name="android:background">@drawable/metro_button_green</item>
</style>
<style name="metro_control_image_button_style" parent="metro_control_button_style">
<item name="android:padding">6dp</item>
</style>
<style name="metro_green_fragment_list_view_item_style" parent="default_fragment_list_view_item_style">
<item name="background">@drawable/metro_green_list_item</item>
<item name="android:background">@drawable/metro_green_list_item</item>
</style>
<style name="metro_green_theme" parent="default_theme">
<item name="digitButtonStyle">@style/metro_digit_button_style</item>
<item name="controlButtonStyle">@style/metro_control_button_style</item>
<item name="controlImageButtonStyle">@style/metro_control_image_button_style</item>
<style name="metro_green_theme" parent="metro_blue_theme">
<item name="operationButtonStyle">@style/metro_green_operation_button_style</item>
<item name="fragmentListViewItemStyle">@style/metro_green_fragment_list_view_item_style</item>
</style>
</resources>

View File

@ -1,34 +1,18 @@
<resources>
<style name="metro_digit_button_style" parent="keyboard_button_style">
<item name="android:background">@drawable/metro_button_dark</item>
</style>
<style name="metro_control_button_style" parent="metro_digit_button_style">
<item name="android:background">@drawable/metro_button_light</item>
</style>
<style name="metro_purple_operation_button_style" parent="metro_digit_button_style">
<item name="android:background">@drawable/metro_button_purple</item>
</style>
<style name="metro_control_image_button_style" parent="metro_control_button_style">
<item name="android:padding">6dp</item>
</style>
<style name="metro_purple_fragment_list_view_item_style" parent="default_fragment_list_view_item_style">
<item name="background">@drawable/metro_purple_list_item</item>
<item name="android:background">@drawable/metro_purple_list_item</item>
</style>
<style name="metro_purple_theme" parent="default_theme">
<item name="digitButtonStyle">@style/metro_digit_button_style</item>
<item name="controlButtonStyle">@style/metro_control_button_style</item>
<item name="controlImageButtonStyle">@style/metro_control_image_button_style</item>
<style name="metro_purple_theme" parent="metro_blue_theme">
<item name="operationButtonStyle">@style/metro_purple_operation_button_style</item>
<item name="fragmentListViewItemStyle">@style/metro_purple_fragment_list_view_item_style</item>
</style>
</resources>

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:a="http://schemas.android.com/apk/res/android"
a:minWidth="150dp"
a:minHeight="200dp"
a:updatePeriodMillis="1000"
a:minWidth="180dp"
a:minHeight="220dp"
a:initialLayout="@layout/widget_layout"
a:previewImage="@drawable/widget_preview"
a:resizeMode="horizontal|vertical">
</appwidget-provider>

View File

@ -1,5 +1,6 @@
package org.solovyev.android;
import android.os.Looper;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
@ -32,4 +33,8 @@ public final class AndroidUtils2 {
dialogFragment.show(ft, fragmentTag);
}
public static boolean isUiThread() {
return Looper.myLooper() == Looper.getMainLooper();
}
}

View File

@ -180,12 +180,39 @@ public class AndroidCalculator implements Calculator, CalculatorEventListener {
case show_history:
CalculatorActivityLauncher.showHistory(CalculatorApplication.getInstance());
break;
case show_history_detached:
CalculatorActivityLauncher.showHistory(CalculatorApplication.getInstance(), true);
break;
case show_functions:
CalculatorActivityLauncher.showFunctions(CalculatorApplication.getInstance());
break;
case show_functions_detached:
CalculatorActivityLauncher.showFunctions(CalculatorApplication.getInstance(), true);
break;
case show_operators:
CalculatorActivityLauncher.showOperators(CalculatorApplication.getInstance());
break;
case show_operators_detached:
CalculatorActivityLauncher.showOperators(CalculatorApplication.getInstance(), true);
break;
case show_vars:
CalculatorActivityLauncher.showVars(CalculatorApplication.getInstance());
break;
case show_vars_detached:
CalculatorActivityLauncher.showVars(CalculatorApplication.getInstance(), true);
break;
case show_settings:
CalculatorActivityLauncher.showSettings(CalculatorApplication.getInstance());
break;
case show_settings_detached:
CalculatorActivityLauncher.showSettings(CalculatorApplication.getInstance(), true);
break;
case show_like_dialog:
CalculatorActivityLauncher.likeButtonPressed(CalculatorApplication.getInstance());
break;
case open_app:
CalculatorActivityLauncher.openApp(CalculatorApplication.getInstance());
break;
}
}
}

View File

@ -47,9 +47,8 @@ public class AndroidCalculatorEditorView extends EditText implements SharedPrefe
private volatile boolean viewStateChange = false;
// NOTE: static because super constructor calls some overridden methods (like onSelectionChanged and current lock is not yet created)
@NotNull
private static final Object viewLock = new Object();
@Nullable
private final Object viewLock = new Object();
@NotNull
private final Handler uiHandler = new Handler();
@ -154,6 +153,7 @@ public class AndroidCalculatorEditorView extends EditText implements SharedPrefe
@Override
public void setState(@NotNull final CalculatorEditorViewState viewState) {
if (viewLock != null) {
synchronized (viewLock) {
final CharSequence text = prepareText(viewState.getText(), highlightText);
@ -176,9 +176,11 @@ public class AndroidCalculatorEditorView extends EditText implements SharedPrefe
});
}
}
}
@Override
protected void onSelectionChanged(int selStart, int selEnd) {
if (viewLock != null) {
synchronized (viewLock) {
if (!viewStateChange) {
// external text change => need to notify editor
@ -187,8 +189,10 @@ public class AndroidCalculatorEditorView extends EditText implements SharedPrefe
}
}
}
}
public void handleTextChange(Editable s) {
if (viewLock != null) {
synchronized (viewLock) {
if (!viewStateChange) {
// external text change => need to notify editor
@ -196,6 +200,7 @@ public class AndroidCalculatorEditorView extends EditText implements SharedPrefe
}
}
}
}
private final class TextWatcherImpl implements TextWatcher {

View File

@ -1,9 +1,11 @@
package org.solovyev.android.calculator;
import android.app.Application;
import android.os.Handler;
import android.widget.Toast;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.AndroidUtils2;
import org.solovyev.android.msg.AndroidMessage;
import org.solovyev.common.msg.Message;
import org.solovyev.common.msg.MessageType;
@ -20,13 +22,18 @@ public class AndroidCalculatorNotifier implements CalculatorNotifier {
@NotNull
private final Application application;
@NotNull
private final Handler uiHandler = new Handler();
public AndroidCalculatorNotifier(@NotNull Application application) {
assert AndroidUtils2.isUiThread();
this.application = application;
}
@Override
public void showMessage(@NotNull Message message) {
Toast.makeText(application, message.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
showMessageInUiThread(message.getLocalizedMessage());
}
@Override
@ -38,4 +45,25 @@ public class AndroidCalculatorNotifier implements CalculatorNotifier {
public void showMessage(@NotNull Integer messageCode, @NotNull MessageType messageType, @Nullable Object... parameters) {
showMessage(new AndroidMessage(messageCode, messageType, application, parameters));
}
@Override
public void showDebugMessage(@Nullable final String tag, @NotNull final String message) {
/*if (AndroidUtils.isDebuggable(application)) {
showMessageInUiThread(tag == null ? message : tag + ": " + message);
}*/
}
private void showMessageInUiThread(@NotNull final String message) {
if (AndroidUtils2.isUiThread()) {
Toast.makeText(application, message, Toast.LENGTH_SHORT).show();
} else {
uiHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(application,message, Toast.LENGTH_SHORT).show();
}
});
}
}
}

View File

@ -167,7 +167,7 @@ public class CalculatorActivity extends SherlockFragmentActivity implements Shar
@SuppressWarnings({"UnusedDeclaration"})
public void equalsButtonClickHandler(@NotNull View v) {
getCalculator().evaluate();
buttonPressed(CalculatorSpecialButton.equals);
}
@Override
@ -241,12 +241,12 @@ public class CalculatorActivity extends SherlockFragmentActivity implements Shar
@SuppressWarnings({"UnusedDeclaration"})
public void historyButtonClickHandler(@NotNull View v) {
buttonPressed(CalculatorButtonActions.SHOW_HISTORY);
buttonPressed(CalculatorSpecialButton.history);
}
@SuppressWarnings({"UnusedDeclaration"})
public void eraseButtonClickHandler(@NotNull View v) {
buttonPressed(CalculatorButtonActions.ERASE);
buttonPressed(CalculatorSpecialButton.erase);
}
@SuppressWarnings({"UnusedDeclaration"})
@ -256,12 +256,12 @@ public class CalculatorActivity extends SherlockFragmentActivity implements Shar
@SuppressWarnings({"UnusedDeclaration"})
public void pasteButtonClickHandler(@NotNull View v) {
buttonPressed(CalculatorButtonActions.PASTE);
buttonPressed(CalculatorSpecialButton.paste);
}
@SuppressWarnings({"UnusedDeclaration"})
public void copyButtonClickHandler(@NotNull View v) {
buttonPressed(CalculatorButtonActions.COPY);
buttonPressed(CalculatorSpecialButton.copy);
}
@NotNull
@ -271,7 +271,7 @@ public class CalculatorActivity extends SherlockFragmentActivity implements Shar
@SuppressWarnings({"UnusedDeclaration"})
public void clearButtonClickHandler(@NotNull View v) {
buttonPressed(CalculatorButtonActions.CLEAR);
buttonPressed(CalculatorSpecialButton.clear);
}
@SuppressWarnings({"UnusedDeclaration"})
@ -291,28 +291,32 @@ public class CalculatorActivity extends SherlockFragmentActivity implements Shar
}
}
private void buttonPressed(@NotNull CalculatorSpecialButton button) {
buttonPressed(button.getActionCode());
}
private void buttonPressed(@NotNull String text) {
getKeyboard().buttonPressed(text);
}
@SuppressWarnings({"UnusedDeclaration"})
public void functionsButtonClickHandler(@NotNull View v) {
buttonPressed(CalculatorButtonActions.SHOW_FUNCTIONS);
buttonPressed(CalculatorSpecialButton.functions);
}
@SuppressWarnings({"UnusedDeclaration"})
public void operatorsButtonClickHandler(@NotNull View v) {
buttonPressed(CalculatorButtonActions.SHOW_OPERATORS);
buttonPressed(CalculatorSpecialButton.operators);
}
@SuppressWarnings({"UnusedDeclaration"})
public void varsButtonClickHandler(@NotNull View v) {
buttonPressed(CalculatorButtonActions.SHOW_VARS);
buttonPressed(CalculatorSpecialButton.vars);
}
@SuppressWarnings({"UnusedDeclaration"})
public void likeButtonClickHandler(@NotNull View v) {
CalculatorApplication.likeButtonPressed(this);
buttonPressed(CalculatorSpecialButton.like);
}
}

View File

@ -2,6 +2,7 @@ package org.solovyev.android.calculator;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import jscl.math.Generic;
import jscl.math.function.Constant;
@ -24,7 +25,13 @@ import org.solovyev.common.text.StringUtils;
public class CalculatorActivityLauncher {
public static void showHistory(@NotNull final Context context) {
context.startActivity(new Intent(context, CalculatorHistoryActivity.class));
showHistory(context, false);
}
public static void showHistory(@NotNull final Context context, boolean detached) {
final Intent intent = new Intent(context, CalculatorHistoryActivity.class);
addFlags(intent, detached);
context.startActivity(intent);
}
public static void showHelp(@NotNull final Context context) {
@ -32,7 +39,23 @@ public class CalculatorActivityLauncher {
}
public static void showSettings(@NotNull final Context context) {
context.startActivity(new Intent(context, CalculatorPreferencesActivity.class));
showSettings(context, false);
}
public static void showSettings(@NotNull final Context context, boolean detached) {
final Intent intent = new Intent(context, CalculatorPreferencesActivity.class);
addFlags(intent, detached);
context.startActivity(intent);
}
private static void addFlags(@NotNull Intent intent, boolean detached) {
int flags = Intent.FLAG_ACTIVITY_NEW_TASK;
if (detached) {
flags = flags | Intent.FLAG_ACTIVITY_NO_HISTORY;
}
intent.setFlags(flags);
}
public static void showAbout(@NotNull final Context context) {
@ -40,15 +63,33 @@ public class CalculatorActivityLauncher {
}
public static void showFunctions(@NotNull final Context context) {
context.startActivity(new Intent(context, CalculatorFunctionsActivity.class));
showHistory(context, false);
}
public static void showFunctions(@NotNull final Context context, boolean detached) {
final Intent intent = new Intent(context, CalculatorFunctionsActivity.class);
addFlags(intent, detached);
context.startActivity(intent);
}
public static void showOperators(@NotNull final Context context) {
context.startActivity(new Intent(context, CalculatorOperatorsActivity.class));
showOperators(context, false);
}
public static void showOperators(@NotNull final Context context, boolean detached) {
final Intent intent = new Intent(context, CalculatorOperatorsActivity.class);
addFlags(intent, detached);
context.startActivity(intent);
}
public static void showVars(@NotNull final Context context) {
context.startActivity(new Intent(context, CalculatorVarsActivity.class));
showVars(context, false);
}
public static void showVars(@NotNull final Context context, boolean detached) {
final Intent intent = new Intent(context, CalculatorVarsActivity.class);
addFlags(intent, detached);
context.startActivity(intent);
}
public static void plotGraph(@NotNull final Context context, @NotNull Generic generic, @NotNull Constant constant){
@ -82,4 +123,16 @@ public class CalculatorActivityLauncher {
CalculatorLocatorImpl.getInstance().getNotifier().showMessage(R.string.c_not_valid_result, MessageType.error);
}
}
public static void openApp(@NotNull Context context) {
final Intent intent = new Intent(context, CalculatorActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);
}
public static void likeButtonPressed(@NotNull final Context context) {
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(CalculatorApplication.FACEBOOK_APP_URL));
addFlags(intent, false);
context.startActivity(intent);
}
}

View File

@ -1,9 +1,6 @@
package org.solovyev.android.calculator;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.preference.PreferenceManager;
import net.robotmedia.billing.BillingController;
import net.robotmedia.billing.helper.DefaultBillingObserver;
@ -15,6 +12,7 @@ import org.jetbrains.annotations.NotNull;
import org.solovyev.android.ads.AdsController;
import org.solovyev.android.calculator.history.AndroidCalculatorHistory;
import org.solovyev.android.calculator.model.AndroidCalculatorEngine;
import org.solovyev.android.calculator.widget.CalculatorWidgetHelper;
/**
* User: serso
@ -39,6 +37,7 @@ public class CalculatorApplication extends android.app.Application {
**********************************************************************
*/
private static final String TAG = "Calculator++ Application";
public static final String FACEBOOK_APP_URL = "http://www.facebook.com/calculatorpp";
public static final String AD_FREE_PRODUCT_ID = "ad_free";
@ -49,6 +48,9 @@ public class CalculatorApplication extends android.app.Application {
@NotNull
private static CalculatorApplication instance;
@NotNull
private CalculatorWidgetHelper widgetHelper;
/*
**********************************************************************
*
@ -91,6 +93,10 @@ public class CalculatorApplication extends android.app.Application {
CalculatorLocatorImpl.getInstance().getCalculator().init();
// in order to not to be garbage collected
widgetHelper = new CalculatorWidgetHelper();
CalculatorLocatorImpl.getInstance().getCalculator().addCalculatorEventListener(widgetHelper);
AdsController.getInstance().init(ADMOB_USER_ID, AD_FREE_PRODUCT_ID, new BillingController.IConfiguration() {
@Override
@ -115,6 +121,9 @@ public class CalculatorApplication extends android.app.Application {
AdsController.getInstance().isAdFree(CalculatorApplication.this);
}
}).start();
CalculatorLocatorImpl.getInstance().getLogger().debug(TAG, "Application started!");
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Application started!");
}
private void setTheme(@NotNull SharedPreferences preferences) {
@ -154,7 +163,4 @@ public class CalculatorApplication extends android.app.Application {
return instance;
}
public static void likeButtonPressed(@NotNull final Context context) {
context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(FACEBOOK_APP_URL)));
}
}

View File

@ -1,11 +0,0 @@
package org.solovyev.android.calculator.widget;
/**
* User: Solovyev_S
* Date: 19.10.12
* Time: 18:09
*/
public class CalculatorWidgetController {
public static final String BUTTON_PRESSED_ACTION = "org.solovyev.calculator.widget.BUTTON_PRESSED";
}

View File

@ -0,0 +1,65 @@
package org.solovyev.android.calculator.widget;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.*;
/**
* User: serso
* Date: 10/19/12
* Time: 11:11 PM
*/
public class CalculatorWidgetHelper extends BroadcastReceiver implements CalculatorEventListener {
private static final String TAG = "Calculator++ Widget Helper";
@NotNull
private final CalculatorEventHolder lastEvent = new CalculatorEventHolder(CalculatorUtils.createFirstEventDataId());
public CalculatorWidgetHelper() {
CalculatorLocatorImpl.getInstance().getCalculator().addCalculatorEventListener(this);
}
@Override
public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) {
final CalculatorEventHolder.Result result = lastEvent.apply(calculatorEventData);
if (result.isNewAfter()) {
switch (calculatorEventType) {
case editor_state_changed_light:
case editor_state_changed:
final CalculatorEditorChangeEventData editorChangeData = (CalculatorEditorChangeEventData) data;
final CalculatorEditorViewState newEditorState = editorChangeData.getNewValue();
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Editor state changed: " + newEditorState.getText());
CalculatorWidgetProvider.onEditorStateChanged(CalculatorApplication.getInstance(), newEditorState);
break;
case display_state_changed:
final CalculatorDisplayChangeEventData displayChangeData = (CalculatorDisplayChangeEventData) data;
final CalculatorDisplayViewState newDisplayState = displayChangeData.getNewValue();
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Display state changed: " + newDisplayState.getText());
CalculatorWidgetProvider.onDisplayStateChanged(CalculatorApplication.getInstance(), newDisplayState);
break;
}
}
}
@Override
public void onReceive(Context context, Intent intent) {
if (CalculatorWidgetProvider.BUTTON_PRESSED_ACTION.equals(intent.getAction())) {
final int buttonId = intent.getIntExtra(CalculatorWidgetProvider.BUTTON_ID_EXTRA, 0);
//Toast.makeText(context, "Button id: " + buttonId, Toast.LENGTH_SHORT).show();
final WidgetButton button = WidgetButton.getById(buttonId);
if ( button != null ) {
button.onClick(context);
}
}
}
}

View File

@ -3,14 +3,20 @@ package org.solovyev.android.calculator.widget;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.text.Html;
import android.widget.RemoteViews;
import android.widget.Toast;
import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.CalculatorApplication;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.CalculatorDisplayViewState;
import org.solovyev.android.calculator.CalculatorEditorViewState;
import org.solovyev.android.calculator.CalculatorLocatorImpl;
import org.solovyev.android.calculator.R;
import java.io.Serializable;
/**
* User: Solovyev_S
* Date: 19.10.12
@ -18,8 +24,57 @@ import org.solovyev.android.calculator.R;
*/
public class CalculatorWidgetProvider extends AppWidgetProvider {
public static final String BUTTON_PRESSED = "org.solovyev.calculator.widget.BUTTON_PRESSED";
/*
**********************************************************************
*
* CONSTANTS
*
**********************************************************************
*/
public static final String BUTTON_ID_EXTRA = "buttonId";
public static final String BUTTON_PRESSED_ACTION = "org.solovyev.calculator.widget.BUTTON_PRESSED";
private static final String EDITOR_STATE_CHANGED_ACTION = "org.solovyev.calculator.widget.EDITOR_STATE_CHANGED";
private static final String EDITOR_STATE_EXTRA = "editorState";
private static final String DISPLAY_STATE_CHANGED_ACTION = "org.solovyev.calculator.widget.DISPLAY_STATE_CHANGED";
private static final String DISPLAY_STATE_EXTRA = "displayState";
private static final String TAG = "Calculator++ Widget";
/*
**********************************************************************
*
* FIELDS
*
**********************************************************************
*/
@Nullable
private String cursorColor;
/*
**********************************************************************
*
* METHODS
*
**********************************************************************
*/
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
getCursorColor(context);
}
@NotNull
private String getCursorColor(@NotNull Context context) {
if ( cursorColor == null ) {
cursorColor = Integer.toHexString(context.getResources().getColor(R.color.widget_cursor_color)).substring(2);
}
return cursorColor;
}
@Override
public void onUpdate(@NotNull Context context,
@ -27,20 +82,118 @@ public class CalculatorWidgetProvider extends AppWidgetProvider {
@NotNull int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
for (int appWidgetId : appWidgetIds) {
final RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
for (WidgetButton button : WidgetButton.values()) {
final Intent onButtonClickIntent = new Intent(context, CalculatorWidgetProvider.class);
onButtonClickIntent.setAction(CalculatorWidgetController.BUTTON_PRESSED_ACTION);
final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, onButtonClickIntent, 0);
views.setOnClickPendingIntent(R.id.oneDigitButton, pendingIntent);
onButtonClickIntent.setAction(BUTTON_PRESSED_ACTION);
onButtonClickIntent.putExtra(BUTTON_ID_EXTRA, button.getButtonId());
final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, button.getButtonId(), onButtonClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (pendingIntent != null) {
views.setOnClickPendingIntent(button.getButtonId(), pendingIntent);
}
}
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
if ( BUTTON_PRESSED.equals(intent.getAction()) ) {
Toast.makeText(CalculatorApplication.getInstance(), "Button pressed!", Toast.LENGTH_SHORT).show();
if (CalculatorWidgetProvider.BUTTON_PRESSED_ACTION.equals(intent.getAction())) {
final int buttonId = intent.getIntExtra(CalculatorWidgetProvider.BUTTON_ID_EXTRA, 0);
final WidgetButton button = WidgetButton.getById(buttonId);
if (button != null) {
button.onClick(context);
}
} else if (EDITOR_STATE_CHANGED_ACTION.equals(intent.getAction())) {
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Editor state changed broadcast received!");
final Serializable object = intent.getSerializableExtra(EDITOR_STATE_EXTRA);
if (object instanceof CalculatorEditorViewState) {
updateEditorState(context, (CalculatorEditorViewState) object);
}
} else if (DISPLAY_STATE_CHANGED_ACTION.equals(intent.getAction())) {
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Display state changed broadcast received!");
final Serializable object = intent.getSerializableExtra(DISPLAY_STATE_EXTRA);
if (object instanceof CalculatorDisplayViewState) {
updateDisplayState(context, (CalculatorDisplayViewState) object);
}
}
}
private void updateDisplayState(@NotNull Context context, @NotNull CalculatorDisplayViewState displayState) {
if (displayState.isValid()) {
setText(context, R.id.calculatorDisplay, displayState.getText());
setTextColor(context, R.id.calculatorDisplay, context.getResources().getColor(R.color.default_text_color));
} else {
setTextColor(context, R.id.calculatorDisplay, context.getResources().getColor(R.color.display_error_text_color));
}
}
private void setText(@NotNull Context context, int textViewId, @Nullable CharSequence text) {
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
final int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, CalculatorWidgetProvider.class));
for (int appWidgetId : appWidgetIds) {
final RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
views.setTextViewText(textViewId, text);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
private void setTextColor(@NotNull Context context, int textViewId, int textColor) {
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
final int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, CalculatorWidgetProvider.class));
for (int appWidgetId : appWidgetIds) {
final RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
views.setTextColor(textViewId, textColor);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
private void updateEditorState(@NotNull Context context, @NotNull CalculatorEditorViewState editorState) {
String text = editorState.getText();
CharSequence newText = text;
int selection = editorState.getSelection();
if (selection >= 0 && selection <= text.length() ) {
// inject cursor
newText = Html.fromHtml(text.substring(0, selection) + "<font color=\"#" + getCursorColor(context) + "\">|</font>" + text.substring(selection));
}
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "New editor state: " + text);
setText(context, R.id.calculatorEditor, newText);
}
/*
**********************************************************************
*
* STATIC
*
**********************************************************************
*/
public static void onEditorStateChanged(@NotNull Context context, @NotNull CalculatorEditorViewState editorViewState) {
final Intent intent = new Intent(EDITOR_STATE_CHANGED_ACTION);
intent.setClass(context, CalculatorWidgetProvider.class);
intent.putExtra(EDITOR_STATE_EXTRA, editorViewState);
context.sendBroadcast(intent);
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Editor state changed broadcast sent");
}
public static void onDisplayStateChanged(@NotNull Context context, @NotNull CalculatorDisplayViewState displayViewState) {
final Intent intent = new Intent(DISPLAY_STATE_CHANGED_ACTION);
intent.setClass(context, CalculatorWidgetProvider.class);
intent.putExtra(DISPLAY_STATE_EXTRA, displayViewState);
context.sendBroadcast(intent);
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Display state changed broadcast sent");
}
}

View File

@ -0,0 +1,94 @@
package org.solovyev.android.calculator.widget;
import android.content.Context;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.CalculatorLocatorImpl;
import org.solovyev.android.calculator.CalculatorSpecialButton;
import org.solovyev.android.calculator.R;
/**
* User: serso
* Date: 10/20/12
* Time: 12:05 AM
*/
enum WidgetButton {
/*digits*/
one(R.id.oneDigitButton, "1"),
two(R.id.twoDigitButton, "2"),
three(R.id.threeDigitButton, "3"),
four(R.id.fourDigitButton, "4"),
five(R.id.fiveDigitButton, "5"),
six(R.id.sixDigitButton, "6"),
seven(R.id.sevenDigitButton, "7"),
eight(R.id.eightDigitButton, "8"),
nine(R.id.nineDigitButton, "9"),
zero(R.id.zeroDigitButton, "0"),
period(R.id.periodButton, "."),
brackets(R.id.roundBracketsButton, "()"),
settings(R.id.settingsButton, CalculatorSpecialButton.settings_detached),
like(R.id.likeButton, CalculatorSpecialButton.like),
/*last row*/
left(R.id.leftButton, CalculatorSpecialButton.cursor_left),
right(R.id.rightButton, CalculatorSpecialButton.cursor_right),
vars(R.id.varsButton, CalculatorSpecialButton.vars_detached),
functions(R.id.functionsButton, CalculatorSpecialButton.functions_detached),
app(R.id.appButton, CalculatorSpecialButton.open_app),
history(R.id.historyButton, CalculatorSpecialButton.history_detached),
/*operations*/
multiplication(R.id.multiplicationButton, "*"),
division(R.id.divisionButton, "/"),
plus(R.id.plusButton, "+"),
subtraction(R.id.subtractionButton, "-"),
percent(R.id.percentButton, "%"),
power(R.id.powerButton, "^"),
/*last column*/
clear(R.id.clearButton, CalculatorSpecialButton.clear),
erase(R.id.eraseButton, CalculatorSpecialButton.erase),
copy(R.id.copyButton, CalculatorSpecialButton.copy),
paste(R.id.pasteButton, CalculatorSpecialButton.paste),
/*equals*/
equals(R.id.equalsButton, CalculatorSpecialButton.equals);
private final int buttonId;
@NotNull
private final String text;
WidgetButton(int buttonId, @NotNull CalculatorSpecialButton button) {
this(buttonId, button.getActionCode());
}
WidgetButton(int buttonId, @NotNull String text) {
this.buttonId = buttonId;
this.text = text;
}
public void onClick(@NotNull Context context) {
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage("Calculator++ Widget", "Button pressed: " + text);
CalculatorLocatorImpl.getInstance().getKeyboard().buttonPressed(text);
}
@Nullable
public static WidgetButton getById(int buttonId) {
for (WidgetButton widgetButton : values()) {
if (widgetButton.buttonId == buttonId) {
return widgetButton;
}
}
return null;
}
public int getButtonId() {
return buttonId;
}
}