mirror of
https://github.com/moparisthebest/k-9
synced 2025-02-11 12:40:22 -05:00
Merge of remote branch 'origin/master' into ms-eas.
This commit is contained in:
commit
004360fb8e
@ -9,5 +9,6 @@
|
||||
<classpathentry kind="lib" path="libs/jzlib-1.0.7.jar"/>
|
||||
<classpathentry kind="lib" path="libs/jutf7-1.0.1-SNAPSHOT.jar"/>
|
||||
<classpathentry kind="lib" path="libs/htmlcleaner-2.2.jar"/>
|
||||
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||
<classpathentry kind="output" path="bin/classes"/>
|
||||
</classpath>
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:versionCode="15011"
|
||||
android:versionName="4.112" package="com.fsck.k9"
|
||||
android:versionCode="15012"
|
||||
android:versionName="4.113" package="com.fsck.k9"
|
||||
>
|
||||
<uses-sdk
|
||||
android:minSdkVersion="7"
|
||||
|
@ -19,5 +19,5 @@
|
||||
split.density=false
|
||||
java.encoding=utf8
|
||||
# Project target.
|
||||
target=android-9
|
||||
target=android-15
|
||||
extensible.libs.classpath=compile-only-libs
|
||||
|
@ -1,11 +0,0 @@
|
||||
<html>
|
||||
<body bgcolor="white">
|
||||
<table width="100%" height="100%">
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<font color="gray">No text</font>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
@ -1,17 +0,0 @@
|
||||
<html>
|
||||
<body bgcolor="white">
|
||||
<table width="100%" height="100%">
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<font color="gray">Loading...</font>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<img src="loading.gif">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
@ -1,18 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Phasellus dui dui, luctus sit amet, hendrerit ac, blandit quis, diam. Duis libero velit, elementum id, mattis ut, fermentum aliquet, tortor. Maecenas tincidunt egestas pede. Integer sagittis ipsum ut lorem. Morbi egestas egestas sapien. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Duis eget erat ac sem iaculis sollicitudin. Maecenas in velit id mauris cursus tincidunt. Sed ultrices elit in sapien ullamcorper imperdiet. Nunc viverra, lacus id varius elementum, nisl turpis lacinia tellus, sit amet viverra neque odio quis nisl. Quisque facilisis, ipsum non vulputate malesuada, leo augue elementum tortor, nec eleifend tellus lectus non massa.
|
||||
<br/><br/>
|
||||
Maecenas pulvinar rutrum risus. Phasellus mattis arcu sit amet neque. Aliquam sed quam at nulla laoreet pretium. Proin elit. Integer ullamcorper dolor a pede. Nam lobortis quam ut mauris. Pellentesque non mauris ut lacus hendrerit iaculis. In volutpat nulla et turpis. Fusce mollis. Aliquam sit amet tortor fermentum orci lacinia convallis. Donec tincidunt tortor sed erat sollicitudin gravida. In hac habitasse platea dictumst. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed pulvinar arcu consectetuer dolor. Nunc luctus aliquam leo. In hac habitasse platea dictumst. Praesent et mi sit amet ligula blandit hendrerit. Nam aliquam tincidunt est. Aliquam erat volutpat.
|
||||
<br/><br/>
|
||||
Curabitur augue. Fusce pulvinar nisi vitae diam. Donec dictum. Sed suscipit convallis magna. Ut hendrerit tortor in mauris. In at diam. Maecenas commodo. Aliquam erat volutpat. Nunc odio eros, vestibulum at, sodales id, congue et, risus. Curabitur feugiat blandit lacus. Nulla gravida placerat enim. Nunc turpis. Praesent malesuada.
|
||||
<br/><br/>
|
||||
Aenean quis erat. Vivamus non ipsum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed metus magna, porta eu, ultricies vitae, vulputate et, urna. Sed pulvinar, massa at ultricies rhoncus, nunc eros dapibus felis, quis congue risus orci rhoncus nibh. Pellentesque quam ante, laoreet vitae, iaculis a, gravida in, nibh. In hac habitasse platea dictumst. Aliquam erat volutpat. Suspendisse augue neque, posuere eu, sollicitudin quis, sagittis et, massa. Maecenas varius sem sodales ipsum. Donec congue mi nec orci. Nam pede ipsum, varius sed, condimentum ac, rhoncus non, lorem. Integer vestibulum, neque vitae ornare euismod, mauris turpis congue massa, non venenatis arcu lorem eget metus. Sed sollicitudin, enim aliquam pharetra cursus, neque augue bibendum leo, vitae ullamcorper ante felis nec massa. Maecenas vitae urna. Proin tincidunt, urna eu sodales vulputate, nisl tellus pretium ligula, ut venenatis metus nulla eu lectus. Integer urna purus, sagittis ut, posuere sed, sagittis non, mauris. Nunc eros risus, lacinia sit amet, dictum in, faucibus quis, urna. Fusce dictum mattis enim. Vivamus luctus sagittis felis.
|
||||
<br/><br/>
|
||||
Fusce pulvinar, erat a facilisis congue, lacus libero imperdiet dui, nec luctus justo neque sit amet mauris. Praesent sodales. Sed sed nisl a arcu tempus placerat. Duis sagittis risus. Aliquam tristique. Ut a mi. Integer volutpat, turpis vitae lobortis blandit, lorem sapien suscipit arcu, sit amet dignissim felis mauris vitae ipsum. Sed elit. Mauris elementum, pede nec accumsan pretium, leo metus fringilla erat, at feugiat turpis arcu pretium urna. Morbi lorem tellus, commodo sed, convallis id, suscipit sed, leo. Donec egestas ultricies tellus. Curabitur sapien orci, interdum nec, molestie at, pharetra eu, magna. Duis pharetra orci sed felis posuere malesuada. Donec nec nisi non urna ultricies porttitor. Maecenas lectus. Sed dignissim malesuada justo. Nunc rutrum consectetuer nunc.
|
||||
|
||||
<img src="cid:23978198273">
|
||||
more text
|
||||
<img src="cid:12371982371">
|
||||
more text
|
||||
</body>
|
||||
</html>
|
@ -11,5 +11,5 @@
|
||||
split.density=false
|
||||
java.encoding=utf8
|
||||
# Project target.
|
||||
target=android-10
|
||||
target=android-15
|
||||
extensible.libs.classpath=compile-only-libs
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 434 B After Width: | Height: | Size: 570 B |
Binary file not shown.
Before Width: | Height: | Size: 436 B After Width: | Height: | Size: 570 B |
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ExpandableListView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:divider="?android:attr/listDivider"
|
||||
android:childDivider="?android:attr/listDivider"
|
||||
android:indicatorLeft="14dip" />
|
@ -3,37 +3,25 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:orientation="horizontal"
|
||||
android:paddingRight="6dip"
|
||||
android:paddingBottom="2dip"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
android:gravity="center_vertical" >
|
||||
|
||||
android:background="#cccccc"
|
||||
android:gravity="left|center_vertical">
|
||||
<View
|
||||
android:id="@+id/chip"
|
||||
android:layout_width="6dip"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentLeft="true" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft" >
|
||||
android:layout_width="6dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
android:id="@+id/name"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingLeft="18dp"
|
||||
android:paddingRight="4dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
</LinearLayout>
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -4,26 +4,10 @@
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:orientation="horizontal"
|
||||
android:paddingRight="6dip"
|
||||
android:paddingBottom="2dip"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
android:gravity="center_vertical" >
|
||||
|
||||
<View
|
||||
android:id="@+id/chip"
|
||||
android:layout_width="6dip"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentLeft="true" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft" >
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingRight="4dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
@ -32,7 +16,7 @@
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
@ -41,8 +25,6 @@
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
|
||||
</LinearLayout>
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -2,15 +2,14 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="#ffffff" >
|
||||
android:orientation="vertical">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1"
|
||||
android:scrollbarStyle="outsideInset"
|
||||
android:fillViewport="true" >
|
||||
android:scrollbarStyle="insideOverlay"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
@ -20,17 +19,19 @@
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:paddingTop="6dp"
|
||||
android:orientation="vertical"
|
||||
android:background="#ededed" >
|
||||
android:background="#45bcbcbc">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/from"
|
||||
<Button
|
||||
android:id="@+id/identity"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="left|center"
|
||||
android:layout_marginLeft="6dip"
|
||||
android:layout_marginRight="6dip"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
android:layout_marginRight="6dip"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/to_wrapper"
|
||||
android:layout_height="wrap_content"
|
||||
@ -38,27 +39,28 @@
|
||||
android:layout_marginLeft="6dip"
|
||||
android:layout_marginRight="6dip"
|
||||
android:layout_width="fill_parent">
|
||||
|
||||
<MultiAutoCompleteTextView
|
||||
android:id="@+id/to"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textEmailAddress|textMultiLine"
|
||||
android:imeOptions="actionNext"
|
||||
android:hint="@string/message_compose_to_hint"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_marginRight="6dip"
|
||||
android:layout_weight="5"
|
||||
/>
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/add_to"
|
||||
android:contentDescription="@string/message_compose_description_add_to"
|
||||
android:src="@drawable/ic_button_contacts"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_width="60dip"
|
||||
android:layout_marginTop="1dip"
|
||||
/>
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginTop="1dip"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/cc_wrapper"
|
||||
android:visibility="gone"
|
||||
@ -67,27 +69,28 @@
|
||||
android:layout_marginLeft="6dip"
|
||||
android:layout_marginRight="6dip"
|
||||
android:layout_width="fill_parent">
|
||||
|
||||
<MultiAutoCompleteTextView
|
||||
android:id="@+id/cc"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="5"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginRight="6dip"
|
||||
android:inputType="textEmailAddress|textMultiLine"
|
||||
android:imeOptions="actionNext"
|
||||
android:hint="@string/message_compose_cc_hint"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/add_cc"
|
||||
android:contentDescription="@string/message_compose_description_add_cc"
|
||||
android:src="@drawable/ic_button_contacts"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="60dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_marginTop="1dip"
|
||||
/>
|
||||
android:layout_marginTop="1dip"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/bcc_wrapper"
|
||||
android:visibility="gone"
|
||||
@ -99,24 +102,23 @@
|
||||
|
||||
<MultiAutoCompleteTextView
|
||||
android:id="@+id/bcc"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="6dip"
|
||||
android:layout_weight="5"
|
||||
android:layout_weight="1"
|
||||
android:inputType="textEmailAddress|textMultiLine"
|
||||
android:imeOptions="actionNext"
|
||||
android:hint="@string/message_compose_bcc_hint"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
/>
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/add_bcc"
|
||||
android:contentDescription="@string/message_compose_description_add_bcc"
|
||||
android:layout_marginTop="1dip"
|
||||
android:layout_height="fill_parent"
|
||||
android:id="@+id/add_bcc"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="60dip"
|
||||
android:src="@drawable/ic_button_contacts"
|
||||
/>
|
||||
android:layout_width="wrap_content"
|
||||
android:src="@drawable/ic_button_contacts"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
@ -138,7 +140,6 @@
|
||||
<CheckBox
|
||||
android:text="@string/btn_crypto_sign"
|
||||
android:id="@+id/cb_crypto_signature"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
@ -154,7 +155,6 @@
|
||||
android:id="@+id/userId"
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
@ -162,7 +162,6 @@
|
||||
android:id="@+id/userIdRest"
|
||||
android:textSize="10sp"
|
||||
android:ellipsize="end"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
@ -173,7 +172,6 @@
|
||||
<CheckBox
|
||||
android:text="@string/btn_encrypt"
|
||||
android:id="@+id/cb_encrypt"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@ -191,7 +189,6 @@
|
||||
android:inputType="textEmailSubject|textAutoCorrect|textCapSentences|textImeMultiLine"
|
||||
android:imeOptions="actionNext"
|
||||
android:singleLine="true"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<!--
|
||||
@ -211,30 +208,31 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- We have to use "wrap_content" (not "0dip") for "layout_height", otherwise the
|
||||
EditText won't properly grow in height while the user is typing the message -->
|
||||
<EditText
|
||||
android:id="@+id/message_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.0"
|
||||
android:layout_weight="1"
|
||||
android:gravity="left|top"
|
||||
android:hint="@string/message_compose_content_hint"
|
||||
android:inputType="textMultiLine|textAutoCorrect|textCapSentences"
|
||||
android:imeOptions="actionDone|flagNoEnterAction"
|
||||
android:minLines="3"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/upper_signature"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.0"
|
||||
android:gravity="left|top"
|
||||
android:editable="false"
|
||||
android:minLines="0"
|
||||
android:autoText="true"
|
||||
android:capitalize="sentences"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:hint="@string/message_compose_signature_hint"
|
||||
android:inputType="textMultiLine|textAutoCorrect|textCapSentences"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<Button
|
||||
@ -244,9 +242,7 @@
|
||||
android:padding="0dip"
|
||||
android:layout_gravity="right"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentRight="true" />
|
||||
android:layout_width="match_parent"/>
|
||||
|
||||
<!-- Quoted text bar -->
|
||||
<RelativeLayout
|
||||
@ -258,12 +254,11 @@
|
||||
android:id="@+id/quoted_text"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.0"
|
||||
android:gravity="left|top"
|
||||
android:minLines="3"
|
||||
android:autoText="true"
|
||||
android:capitalize="sentences"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:inputType="textMultiLine|textAutoCorrect|textCapSentences"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<com.fsck.k9.view.MessageWebView
|
||||
@ -280,19 +275,17 @@
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/quoted_text_edit"
|
||||
android:contentDescription="@string/message_compose_description_edit_quoted_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginRight="8dip"
|
||||
android:background="@drawable/btn_edit" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/quoted_text_delete"
|
||||
android:contentDescription="@string/message_compose_description_delete_quoted_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:background="@drawable/btn_dialog" />
|
||||
|
||||
</LinearLayout>
|
||||
@ -303,13 +296,13 @@
|
||||
android:id="@+id/lower_signature"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.0"
|
||||
android:gravity="left|top"
|
||||
android:editable="false"
|
||||
android:minLines="0"
|
||||
android:autoText="true"
|
||||
android:capitalize="sentences"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
android:hint="@string/message_compose_signature_hint"
|
||||
android:inputType="textMultiLine|textAutoCorrect|textCapSentences"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -122,16 +122,6 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/additional_headers_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="false"
|
||||
android:ellipsize="none"
|
||||
android:textSize="10sp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@ -192,6 +182,31 @@
|
||||
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:id="@+id/additional_headers_row">
|
||||
|
||||
<!-- Color chip 2 -->
|
||||
<View
|
||||
android:id="@+id/chip2"
|
||||
android:layout_marginRight="6dip"
|
||||
android:layout_width="6dip"
|
||||
android:layout_height="fill_parent"/>
|
||||
|
||||
<!-- Additional headers -->
|
||||
<TextView
|
||||
android:layout_span="2"
|
||||
android:id="@+id/additional_headers_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="10dp"
|
||||
android:singleLine="false"
|
||||
android:ellipsize="none"
|
||||
android:textSize="10sp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
|
||||
</TableRow>
|
||||
|
||||
</TableLayout>
|
||||
|
||||
<!-- Separator -->
|
||||
@ -201,19 +216,19 @@
|
||||
android:id="@+id/show_additional_headers_area"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="21.5dp"
|
||||
android:layout_height="21dp"
|
||||
android:focusable="true"
|
||||
android:clickable="true"
|
||||
android:background="@drawable/separator_area_background">
|
||||
android:background="@drawable/message_view_header_background">
|
||||
|
||||
<RelativeLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="20dp">
|
||||
|
||||
<!-- Color chip 2 -->
|
||||
<!-- Color chip 3 -->
|
||||
<View
|
||||
android:id="@+id/chip2"
|
||||
android:id="@+id/chip3"
|
||||
android:layout_marginRight="6dip"
|
||||
android:layout_width="6dip"
|
||||
android:layout_height="fill_parent"
|
||||
@ -233,10 +248,9 @@
|
||||
</RelativeLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/separator"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1.5dp"
|
||||
android:background="#59000000"/>
|
||||
android:layout_height="1dip"
|
||||
android:background="@drawable/divider_horizontal_email" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -30,12 +30,6 @@
|
||||
android:title="@string/discard_action"
|
||||
android:icon="@drawable/ic_menu_close_clear_cancel"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/choose_identity"
|
||||
android:alphabeticShortcut="i"
|
||||
android:title="@string/send_as"
|
||||
android:icon="@drawable/ic_menu_identity"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/read_receipt"
|
||||
android:alphabeticShortcut="r"
|
||||
|
@ -15,6 +15,10 @@
|
||||
android:id="@+id/set_sort_date"
|
||||
android:title="@string/sort_by_date"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/set_sort_arrival"
|
||||
android:title="@string/sort_by_arrival"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/set_sort_subject"
|
||||
android:title="@string/sort_by_subject"
|
||||
|
@ -64,7 +64,7 @@
|
||||
<string name="done_action">Fertig</string> <!-- Used to complete a multi-step process -->
|
||||
<string name="remove_action">Entfernen</string>
|
||||
<string name="discard_action">Verwerfen</string>
|
||||
<string name="save_draft_action">Als Entwurf speichern</string>
|
||||
<string name="save_draft_action">Speichern</string>
|
||||
<string name="retry_action">Erneut versuchen</string>
|
||||
<string name="refresh_action">Aktualisieren</string>
|
||||
<string name="check_mail_action">Nachrichten abrufen</string>
|
||||
@ -218,7 +218,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
\n * Speichern von Anhängen auf SD-Karte
|
||||
\n * Papierkorb leeren
|
||||
\n * Sortieren der Nachrichten
|
||||
\n * ...und viele mehr
|
||||
\n * …und viele mehr
|
||||
\n
|
||||
\nBitte beachten Sie, dass K-9, wie viele andere E-Mail-Anwendungen auch, die meisten kostenlosen Hotmail-Accounts nicht unterstützt. Zudem gibt es einige Probleme mit Microsoft Exchange-Servern.
|
||||
\n
|
||||
@ -256,6 +256,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="message_compose_bcc_hint">BCC</string>
|
||||
<string name="message_compose_subject_hint">Betreff</string>
|
||||
<string name="message_compose_content_hint">Nachrichtentext</string>
|
||||
<string name="message_compose_signature_hint">Signatur</string>
|
||||
<string name="message_compose_quote_header_separator">-------- Original-Nachricht --------</string>
|
||||
<string name="message_compose_quote_header_subject">Betreff:</string>
|
||||
<string name="message_compose_quote_header_send_date">Gesendet:</string>
|
||||
@ -269,6 +270,11 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="message_compose_downloading_attachments_toast">Einige Anhänge wurden nicht heruntergeladen. Sie werden automatisch heruntergeladen, bevor diese Nachricht gesendet wird.</string>
|
||||
<string name="message_compose_attachments_skipped_toast">Einige Anhänge können nicht weitergeleitet werden, da diese nicht heruntergeladen wurden.</string>
|
||||
<string name="message_compose_show_quoted_text_action">Original-Nachricht zitieren</string>
|
||||
<string name="message_compose_description_add_to">Empfänger hinzufügen</string>
|
||||
<string name="message_compose_description_add_cc">Empfänger hinzufügen (CC)</string>
|
||||
<string name="message_compose_description_add_bcc">Empfänger hinzufügen (BCC)</string>
|
||||
<string name="message_compose_description_delete_quoted_text">Zitierten Text entfernen</string>
|
||||
<string name="message_compose_description_edit_quoted_text">Zitierten Text bearbeiten</string>
|
||||
|
||||
<string name="message_view_from_format">Von: <xliff:g id="name">%s</xliff:g> <<xliff:g id="email">%s</xliff:g>></string>
|
||||
<string name="message_to_label">An:</string>
|
||||
@ -285,6 +291,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="message_view_status_attachment_not_saved">Anhang konnte nicht auf SD-Karte gespeichert werden.</string>
|
||||
<string name="message_view_show_pictures_instructions">Wählen Sie \"Bilder anzeigen\", um eingebettete Bilder abzurufen.</string>
|
||||
<string name="message_view_show_pictures_action">Bilder anzeigen</string>
|
||||
<string name="message_view_show_message_action">Zeige Nachricht</string>
|
||||
<string name="message_view_show_attachments_action">Zeige Anhänge</string>
|
||||
<string name="message_view_show_more_attachments_action">Mehr…</string>
|
||||
<string name="message_view_fetching_attachment_toast">Lade Anhang.</string>
|
||||
@ -402,7 +409,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="account_setup_incoming_security_tls_optional_label">TLS (falls verfügbar)</string>
|
||||
<string name="account_setup_incoming_security_tls_label">TLS (immer)</string>
|
||||
|
||||
<string name="account_setup_incoming_delete_policy_label">Bei Löschen von Nachrichten:</string>
|
||||
<string name="account_setup_incoming_delete_policy_label">Beim Löschen von Nachrichten</string>
|
||||
<string name="account_setup_incoming_delete_policy_never_label">Nie von Server löschen</string>
|
||||
<string name="account_setup_incoming_delete_policy_7days_label">Nach 7 Tagen löschen</string>
|
||||
<string name="account_setup_incoming_delete_policy_delete_label">Auch auf Server löschen</string>
|
||||
@ -426,7 +433,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="account_setup_expunge_policy_on_poll">Bei jedem Abrufen</string>
|
||||
<string name="account_setup_expunge_policy_manual">Nur manuell</string>
|
||||
|
||||
<string name="account_setup_incoming_autodetect_namespace_label">IMAP Namensraum automatisch ermitteln</string>
|
||||
<string name="account_setup_incoming_autodetect_namespace_label">IMAP-Namensraum automatisch ermitteln</string>
|
||||
<string name="account_setup_incoming_imap_path_prefix_label">IMAP-Verzeichnispräfix</string>
|
||||
|
||||
<string name="drafts_folder_label">Ordner für Entwürfe</string>
|
||||
@ -457,7 +464,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="account_setup_outgoing_require_login_label">Anmeldung erforderlich.</string>
|
||||
<string name="account_setup_outgoing_username_label">Benutzername</string>
|
||||
<string name="account_setup_outgoing_password_label">Passwort</string>
|
||||
<string name="account_setup_outgoing_authentication_label">Authentifizierungstyp</string>
|
||||
<string name="account_setup_outgoing_authentication_label">Authentifizierungsmethode</string>
|
||||
<!-- The authentication strings below are for a planned (hopefully) change to the above username and password options -->
|
||||
<string name="account_setup_outgoing_authentication_basic_label">Benutzername & Passwort</string>
|
||||
<string name="account_setup_outgoing_authentication_basic_username_label">Benutzername</string>
|
||||
@ -492,7 +499,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="push_poll_on_connect_label">Abruf beim Start der Push-Verbindung</string>
|
||||
<string name="account_setup_options_enable_push_label">Push-Mail für dieses Konto aktivieren</string>
|
||||
<string name="account_setup_options_enable_push_summary">Neue Nachrichten werden nach dem Eintreffen umgehend abgerufen, falls Ihr Server dies unterstützt. Diese Einstellung kann zur Reduzierung der Laufzeit führen oder diese verbessern.</string>
|
||||
<string name="idle_refresh_period_label">IDLE Verbindung refreshen</string>
|
||||
<string name="idle_refresh_period_label">Push-Verbindung erneuern</string>
|
||||
<string name="idle_refresh_period_1min">Jede Minute</string>
|
||||
<string name="idle_refresh_period_2min">Alle 2 Minuten</string>
|
||||
<string name="idle_refresh_period_3min">Alle 3 Minuten</string>
|
||||
@ -544,6 +551,8 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="account_settings_notification_opens_unread_summary">Zeigt beim Öffnen einer Benachrichtigung Liste der ungelesenen Nachrichten an</string>
|
||||
<string name="account_settings_notification_unread_count_label">Anzahl ungelesener Nachrichten anzeigen</string>
|
||||
<string name="account_settings_notification_unread_count_summary">Zeigt die Anzahl der ungelesenen Nachrichten in der Statuszeile.</string>
|
||||
<string name="account_settings_mark_message_as_read_on_view_label">Nachricht beim Öffnen als gelesen markieren</string>
|
||||
<string name="account_settings_mark_message_as_read_on_view_summary">Markiert eine Nachricht als gelesen, sobald sie zum Betrachten geöffnet wird.</string>
|
||||
|
||||
<string name="account_settings_enable_move_buttons_label">Spam-Leiste</string>
|
||||
<string name="account_settings_enable_move_buttons_summary">Zeige Archivieren-, Verschieben- und Spam-Schaltfläche.</string>
|
||||
@ -582,16 +591,15 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="account_settings_folders">Ordner</string>
|
||||
<string name="account_settings_message_lists">Liste der Nachrichten</string>
|
||||
<string name="account_settings_message_view">Anzeige der Nachricht</string>
|
||||
<string name="account_settings_quote_prefix_label">Prefix beim Zitieren</string>
|
||||
<string name="account_settings_quote_prefix_label">Präfix beim Zitieren</string>
|
||||
<string name="account_settings_crypto">Kryptographie</string>
|
||||
<string name="account_settings_crypto_app">OpenPGP Provider</string>
|
||||
<string name="account_settings_crypto_app_none">Keiner</string>
|
||||
<string name="account_settings_crypto_app_not_available">Nicht verfügbar</string>
|
||||
<string name="account_settings_crypto_auto_signature">Auto-sign</string>
|
||||
<string name="account_settings_crypto_auto_signature_summary">Email Adresse des Kontos verwenden um Signaturschlüssel zu schätzen.</string>
|
||||
|
||||
<string name="account_settings_crypto_auto_encrypt">Automatische verschlüsselung</string>
|
||||
<string name="account_settings_crypto_auto_encrypt_summary">Verschlüsselung aktivieren falls für den Empfänger ein öffentlichen Schlüssel abgespeichert ist.</string>
|
||||
<string name="account_settings_crypto_auto_signature">Automatisches Signieren</string>
|
||||
<string name="account_settings_crypto_auto_signature_summary">Verwendet die E-Mail-Adresse des Kontos, um den Signaturschlüssel zu finden.</string>
|
||||
<string name="account_settings_crypto_auto_encrypt">Automatische Verschlüsselung</string>
|
||||
<string name="account_settings_crypto_auto_encrypt_summary">Verschlüsselt automatisch, falls für den Empfänger ein öffentlicher Schlüssel vorhanden ist.</string>
|
||||
|
||||
<string name="account_settings_mail_check_frequency_label">Häufigkeit der E-Mail-Abfrage</string>
|
||||
<string name="account_settings_second_class_check_frequency_label">Häufigkeit der Abfrage für Nebenordner</string>
|
||||
@ -664,7 +672,7 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="account_settings_folder_target_mode_not_second_class">Alle außer Nebenordner</string>
|
||||
|
||||
<string name="account_settings_sync_remote_deletetions_label">Übernehme Löschungen vom Server</string>
|
||||
<string name="account_settings_sync_remote_deletetions_summary">Lösche Nachrichten wenn sie am Server gelöscht werden</string>
|
||||
<string name="account_settings_sync_remote_deletetions_summary">Lösche Nachrichten, wenn sie vom Server gelöscht wurden</string>
|
||||
|
||||
<string name="folder_settings_title">Ordner-Einstellungen</string>
|
||||
|
||||
@ -776,8 +784,9 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="sort_attach_first">Nachrichten mit Anhängen zuerst</string>
|
||||
<string name="sort_unattached_first">Nachrichten ohne Anhänge zuerst</string>
|
||||
|
||||
<string name="sort_by">Sortieren nach...</string>
|
||||
<string name="sort_by">Sortieren nach…</string>
|
||||
<string name="sort_by_date">Datum</string>
|
||||
<string name="sort_by_arrival">Ankunftsdatum</string>
|
||||
<string name="sort_by_sender">Absender</string>
|
||||
<string name="sort_by_subject">Betreff</string>
|
||||
<string name="sort_by_flag">Wichtigkeit</string>
|
||||
@ -978,6 +987,9 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="font_size_message_view_date">Datum</string>
|
||||
<string name="font_size_message_view_content">Nachrichtentext</string>
|
||||
|
||||
<string name="font_size_message_compose">Nachricht verfassen</string>
|
||||
<string name="font_size_message_compose_input">Texteingabefelder</string>
|
||||
|
||||
<string name="font_size_tiniest">Winzig</string>
|
||||
<string name="font_size_tiny">Sehr klein</string>
|
||||
<string name="font_size_smaller">Kleiner</string>
|
||||
@ -1019,6 +1031,9 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="save_or_discard_draft_message_dlg_title">Entwurf speichern?</string>
|
||||
<string name="save_or_discard_draft_message_instructions_fmt">Entwurf speichern oder verwerfen?</string>
|
||||
|
||||
<string name="confirm_discard_draft_message_title">Nachricht verwerfen?</string>
|
||||
<string name="confirm_discard_draft_message">Sind Sie sicher, dass Sie die Nachricht verwerfen möchten?</string>
|
||||
|
||||
<string name="refuse_to_save_draft_marked_encrypted_dlg_title">Speichern des Entwurfs verweigern.</string>
|
||||
<string name="refuse_to_save_draft_marked_encrypted_instructions_fmt">Die Speicherung von als verschlüsselt markierten Entwürfen verweigern.</string>
|
||||
|
||||
@ -1058,9 +1073,9 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<string name="settings_import">Einstellungen importieren</string>
|
||||
<string name="settings_import_selection">Auswahl importieren</string>
|
||||
<string name="settings_import_global_settings">Globale Einstellungen</string>
|
||||
<string name="settings_exporting">Einstellungen Exportieren...</string>
|
||||
<string name="settings_importing">Einstellungen Importieren...</string>
|
||||
<string name="settings_import_scanning_file">Datei lesen...</string>
|
||||
<string name="settings_exporting">Einstellungen exportieren…</string>
|
||||
<string name="settings_importing">Einstellungen importieren…</string>
|
||||
<string name="settings_import_scanning_file">Datei lesen…</string>
|
||||
<string name="settings_export_success">Exportiere Einstellungen erfolgreich in <xliff:g id="filename">%s</xliff:g> gespeichert</string>
|
||||
<string name="settings_import_global_settings_success">Globale Einstellungen erfolgreich von <xliff:g id="filename">%s</xliff:g> importiert</string>
|
||||
<string name="settings_import_success"><xliff:g id="accounts">%s</xliff:g> erfolgreich von <xliff:g id="filename">%s</xliff:g> importiert</string>
|
||||
@ -1069,21 +1084,21 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
<item quantity="other"><xliff:g id="numAccounts">%s</xliff:g> Konten</item>
|
||||
</plurals>
|
||||
<string name="settings_export_failure">Exportieren der Einstellungen ist fehlgeschlagen</string>
|
||||
<string name="settings_import_failure">Importieren der Einstellungen von <xliff:g id="filename">%s</xliff:g> sind fehlgeschlagen</string>
|
||||
<string name="settings_import_failure">Importieren der Einstellungen von <xliff:g id="filename">%s</xliff:g> ist fehlgeschlagen</string>
|
||||
<string name="settings_export_success_header">Export erfolgreich</string>
|
||||
<string name="settings_export_failed_header">Export fehlgeschlagen</string>
|
||||
<string name="settings_import_success_header">Import erfolgreich</string>
|
||||
<string name="settings_import_failed_header">Import fehlgeschlagen</string>
|
||||
<string name="settings_import_activate_account_header">Konto aktivieren</string>
|
||||
<string name="settings_import_activate_account_intro">Um das Konto \"<xliff:g id="account">%s</xliff:g>\" zu benutzen müssen sie das <xliff:g id="server_passwords">%s</xliff:g> angeben.</string>
|
||||
<string name="settings_import_activate_account_intro">Um das Konto \"<xliff:g id="account">%s</xliff:g>\" benutzen zu können, müssen Sie <xliff:g id="server_passwords">%s</xliff:g> angeben.</string>
|
||||
<plurals name="settings_import_server_passwords">
|
||||
<item quantity="one">Server Passwort</item>
|
||||
<item quantity="other">Server Passwörter</item>
|
||||
<item quantity="one">das Server Passwort</item>
|
||||
<item quantity="other">die Server Passwörter</item>
|
||||
</plurals>
|
||||
<string name="settings_import_incoming_server">Posteingangsserver (<xliff:g id="hostname">%s</xliff:g>):</string>
|
||||
<string name="settings_import_outgoing_server">Postausgangsserver (<xliff:g id="hostname">%s</xliff:g>):</string>
|
||||
<plurals name="settings_import_setting_passwords">
|
||||
<item quantity="one">Passwort Setzen...</item>
|
||||
<item quantity="one">Passwort setzen...</item>
|
||||
<item quantity="other">Passwörter setzen...</item>
|
||||
</plurals>
|
||||
<string name="settings_import_use_incoming_server_password">Passwort des Posteingangsservers benutzen</string>
|
||||
@ -1093,12 +1108,44 @@ Willkommen zum \"K-9 Mail\"-Setup. K-9 ist eine quelloffene E-Mail-Anwendung fü
|
||||
|
||||
<string name="account_unavailable">Konto \"<xliff:g id="account">%s</xliff:g>\" ist nicht verfügbar; Bitte SD-Karte prüfen.</string>
|
||||
|
||||
<string name="settings_attachment_default_path">Anhang speichern unter...</string>
|
||||
<string name="settings_attachment_default_path">Anhang speichern unter…</string>
|
||||
<string name="attachment_save_title">Anhang speichern</string>
|
||||
<string name="attachment_save_desc">Es wurde kein Dateimanager gefunden. Wo soll der Anhang abgelegt werden?</string>
|
||||
|
||||
<string name="manage_accounts_move_up_action">Nach oben verschieben</string>
|
||||
<string name="manage_accounts_move_down_action">Nach unten verschieben</string>
|
||||
<string name="manage_accounts_moving_message">Konto verschieben...</string>
|
||||
<string name="manage_accounts_moving_message">Konto verschieben…</string>
|
||||
|
||||
<string name="unread_widget_label">K-9 Ungelesen</string>
|
||||
<string name="unread_widget_select_account">Zeige die Anzahl ungelesener Nachrichten für…</string>
|
||||
|
||||
<string name="import_dialog_error_title">Kein Dateimanager gefunden!</string>
|
||||
<string name="import_dialog_error_message">Es wurde keine geeignete Applikation gefunden, um den Import durchzuführen. Bitte installieren Sie einen Dateimanager aus dem Play Store.</string>
|
||||
<string name="open_market">Play Store öffnen</string>
|
||||
<string name="close">Abbrechen</string>
|
||||
|
||||
<string name="webview_contextmenu_link_view_action">Öffnen</string>
|
||||
<string name="webview_contextmenu_link_share_action">Link weitergeben</string>
|
||||
<string name="webview_contextmenu_link_copy_action">Link kopieren</string>
|
||||
<string name="webview_contextmenu_link_clipboard_label">Link</string>
|
||||
|
||||
<string name="webview_contextmenu_image_title">Bild</string>
|
||||
<string name="webview_contextmenu_image_view_action">Bild anzeigen</string>
|
||||
<string name="webview_contextmenu_image_save_action">Bild speichern</string>
|
||||
<string name="webview_contextmenu_image_download_action">Bild herunterladen</string>
|
||||
<string name="webview_contextmenu_image_copy_action">Bild-URL kopieren</string>
|
||||
<string name="webview_contextmenu_image_clipboard_label">Bild-URL</string>
|
||||
|
||||
<string name="webview_contextmenu_phone_call_action">Anrufen</string>
|
||||
<string name="webview_contextmenu_phone_save_action">Im Adressbuch speichern</string>
|
||||
<string name="webview_contextmenu_phone_copy_action">Telefonnummer kopieren</string>
|
||||
<string name="webview_contextmenu_phone_clipboard_label">Telefonnummer</string>
|
||||
|
||||
<string name="webview_contextmenu_email_send_action">E-Mail senden</string>
|
||||
<string name="webview_contextmenu_email_save_action">Im Adressbuch speichern</string>
|
||||
<string name="webview_contextmenu_email_copy_action">E-Mail-Adresse kopieren</string>
|
||||
<string name="webview_contextmenu_email_clipboard_label">E-Mail-Adresse</string>
|
||||
|
||||
<string name="image_saved_as">Das Bild wurde als \"<xliff:g id="filename">%s</xliff:g>\" gespeichert.</string>
|
||||
<string name="image_saving_failed">Speichern des Bildes fehlgeschlagen.</string>
|
||||
</resources>
|
||||
|
@ -258,6 +258,7 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="message_compose_bcc_hint">Bcc</string>
|
||||
<string name="message_compose_subject_hint">件名</string>
|
||||
<string name="message_compose_content_hint">本文</string>
|
||||
<string name="message_compose_signature_hint">署名</string>
|
||||
<string name="message_compose_quote_header_separator">-------- 元メール --------</string>
|
||||
<string name="message_compose_quote_header_subject">件名:</string>
|
||||
<string name="message_compose_quote_header_send_date">送信日:</string>
|
||||
@ -271,6 +272,11 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="message_compose_downloading_attachments_toast">一部の添付ファイルをダウンロードしていません。このメールが送信される前に自動的にダウンロードされます。</string>
|
||||
<string name="message_compose_attachments_skipped_toast">ダウンロードしていないため、一部の添付ファイルを転送することはできません。</string>
|
||||
<string name="message_compose_show_quoted_text_action">元のメッセージを引用する</string>
|
||||
<string name="message_compose_description_add_to">Toに宛先を追加します</string>
|
||||
<string name="message_compose_description_add_cc">CCに宛先を追加します</string>
|
||||
<string name="message_compose_description_add_bcc">BCCに宛先を追加します</string>
|
||||
<string name="message_compose_description_delete_quoted_text">引用文を削除します</string>
|
||||
<string name="message_compose_description_edit_quoted_text">引用文を編集します</string>
|
||||
|
||||
<string name="message_view_from_format">送信者: <xliff:g id="name">%s</xliff:g> <<xliff:g id="email">%s</xliff:g>></string>
|
||||
<string name="message_to_label">宛先:</string>
|
||||
@ -287,8 +293,11 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="message_view_status_attachment_not_saved">SDカードに添付ファイルを保存できません</string>
|
||||
<string name="message_view_show_pictures_instructions">\"画像表示\"ボタンを押下すると描画します</string>
|
||||
<string name="message_view_show_pictures_action">画像表示</string>
|
||||
<string name="message_view_fetching_attachment_toast">添付取込中</string>
|
||||
<string name="message_view_no_viewer">添付ファイルのビューワー見つけられません .<xliff:g id="mimetype">%s</xliff:g></string>
|
||||
<string name="message_view_show_message_action">メッセージ表示</string>
|
||||
<string name="message_view_show_attachments_action">添付ファイル表示</string>
|
||||
<string name="message_view_show_more_attachments_action">他…</string>
|
||||
<string name="message_view_fetching_attachment_toast">添付ファイル取得中</string>
|
||||
<string name="message_view_no_viewer"><xliff:g id="mimetype">%s</xliff:g>のビューワーが見つかりません</string>
|
||||
|
||||
<string name="message_view_download_remainder">すべてダウンロード</string>
|
||||
|
||||
@ -544,6 +553,8 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="account_settings_notification_opens_unread_summary">通知を開いた際に未読メールを検索する</string>
|
||||
<string name="account_settings_notification_unread_count_label">未読件数の表示</string>
|
||||
<string name="account_settings_notification_unread_count_summary">通知バーに未読メッセージの件数を表示する</string>
|
||||
<string name="account_settings_mark_message_as_read_on_view_label">開くと同時に既読にする</string>
|
||||
<string name="account_settings_mark_message_as_read_on_view_summary">メッセージを参照したときに既読にする</string>
|
||||
|
||||
<string name="account_settings_enable_move_buttons_label">メール整理ボタンを有効にする</string>
|
||||
<string name="account_settings_enable_move_buttons_summary">アーカイブ、移動、迷惑メールボタンを表示</string>
|
||||
@ -777,6 +788,7 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
|
||||
<string name="sort_by">並べ替え...</string>
|
||||
<string name="sort_by_date">日付</string>
|
||||
<string name="sort_by_arrival">受信順</string>
|
||||
<string name="sort_by_sender">送信者</string>
|
||||
<string name="sort_by_subject">件名</string>
|
||||
<string name="sort_by_flag">フラグ</string>
|
||||
@ -795,7 +807,9 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
|
||||
<string name="provider_note_live">このプログラムでPOPアクセスが許可されているのは一部の「Plus」アカウントだけです。有料の「Plus」アカウントがなければ、正しいメールアドレスとパスワードを入力してもログインできません。これらのアカウントにはブラウザからアクセスしてください。</string>
|
||||
|
||||
<string name="provider_note_yahoojp">Yahoo! JapanでPOP3アクセスを使う場合は、Yahoo!メールサイトの「メールの設定」にてPOPアクセスが許可されていることを確認してください。</string>
|
||||
<string name="provider_note_yahoojp">Yahoo! JapanでPOP3アクセスを行う場合は、Yahoo!メールサイトの「メールの設定」にてPOPアクセスが許可されていることを確認してください。</string>
|
||||
|
||||
<string name="provider_note_auonejp">au oneでIMAPアクセスを行う場合は、au oneポータルサイトの「メール」→「設定」ページにて「IMAPを有効にする」をチェックしてください。</string>
|
||||
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_title">証明書が無効です</string>
|
||||
<string name="account_setup_failed_dlg_invalid_certificate_accept">許可</string>
|
||||
@ -1112,4 +1126,29 @@ K-9 Mail セットアップにようこそ。\nK-9 は標準のAndroidメール
|
||||
<string name="import_dialog_error_message">設定をインポートするためのアプリケーションがありません。Androidマーケットからファイルマネージャをインストールしてください。</string>
|
||||
<string name="open_market">マーケット</string>
|
||||
<string name="close">閉じる</string>
|
||||
|
||||
<string name="webview_contextmenu_link_view_action">開く</string>
|
||||
<string name="webview_contextmenu_link_share_action">リンクを共有</string>
|
||||
<string name="webview_contextmenu_link_copy_action">リンクをコピー</string>
|
||||
<string name="webview_contextmenu_link_clipboard_label">リンク</string>
|
||||
|
||||
<string name="webview_contextmenu_image_title">画像</string>
|
||||
<string name="webview_contextmenu_image_view_action">表示</string>
|
||||
<string name="webview_contextmenu_image_save_action">画像を保存</string>
|
||||
<string name="webview_contextmenu_image_download_action">画像をダウンロード</string>
|
||||
<string name="webview_contextmenu_image_copy_action">画像のURLをコピー</string>
|
||||
<string name="webview_contextmenu_image_clipboard_label">画像のURL</string>
|
||||
|
||||
<string name="webview_contextmenu_phone_call_action">発信</string>
|
||||
<string name="webview_contextmenu_phone_save_action">連絡先に保存</string>
|
||||
<string name="webview_contextmenu_phone_copy_action">電話番号をコピー</string>
|
||||
<string name="webview_contextmenu_phone_clipboard_label">電話番号</string>
|
||||
|
||||
<string name="webview_contextmenu_email_send_action">メール送信</string>
|
||||
<string name="webview_contextmenu_email_save_action">連絡先に保存</string>
|
||||
<string name="webview_contextmenu_email_copy_action">メールアドレスをコピー</string>
|
||||
<string name="webview_contextmenu_email_clipboard_label">メールアドレス</string>
|
||||
|
||||
<string name="image_saved_as">\"<xliff:g id="filename">%s</xliff:g>\"に保存しました</string>
|
||||
<string name="image_saving_failed">画像の保存に失敗しました</string>
|
||||
</resources>
|
||||
|
@ -2,5 +2,5 @@
|
||||
<resources>
|
||||
<color name="message_list_item_background">#ffffff</color>
|
||||
<color name="message_list_item_footer_background">#eeeeee</color>
|
||||
<color name="message_view_header_background">#1a080808</color>
|
||||
<color name="message_view_header_background">#45bcbcbc</color>
|
||||
</resources>
|
||||
|
@ -263,6 +263,7 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
||||
<string name="message_compose_bcc_hint">Bcc</string>
|
||||
<string name="message_compose_subject_hint">Subject</string>
|
||||
<string name="message_compose_content_hint">Message text</string>
|
||||
<string name="message_compose_signature_hint">Signature</string>
|
||||
<string name="message_compose_quote_header_separator">-------- Original Message --------</string>
|
||||
<string name="message_compose_quote_header_subject">Subject:</string>
|
||||
<string name="message_compose_quote_header_send_date">Sent:</string>
|
||||
@ -276,6 +277,11 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
||||
<string name="message_compose_downloading_attachments_toast">Some attachments were not downloaded. They will be downloaded automatically before this message is sent.</string>
|
||||
<string name="message_compose_attachments_skipped_toast">Some attachments cannot be forwarded because they have not been downloaded.</string>
|
||||
<string name="message_compose_show_quoted_text_action">Quote message</string>
|
||||
<string name="message_compose_description_add_to">Add recipient (To)</string>
|
||||
<string name="message_compose_description_add_cc">Add recipient (CC)</string>
|
||||
<string name="message_compose_description_add_bcc">Add recipient (BCC)</string>
|
||||
<string name="message_compose_description_delete_quoted_text">Remove quoted text</string>
|
||||
<string name="message_compose_description_edit_quoted_text">Edit quoted text</string>
|
||||
|
||||
<string name="message_view_from_format">From: <xliff:g id="name">%s</xliff:g> <<xliff:g id="email">%s</xliff:g>></string>
|
||||
<string name="message_to_label">To:</string>
|
||||
@ -297,8 +303,8 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
||||
<string name="message_view_show_more_attachments_action">More…</string>
|
||||
<string name="message_view_fetching_attachment_toast">Fetching attachment.</string>
|
||||
<string name="message_view_no_viewer">Unable to find viewer for <xliff:g id="mimetype">%s</xliff:g>.</string>
|
||||
|
||||
<string name="message_view_download_remainder">Download complete message</string>
|
||||
<string name="message_view_downloading">Downloading…</string>
|
||||
|
||||
<!-- NOTE: The following message refers to strings with id 'account_setup_incoming_save_all_headers_label' and 'account_setup_incoming_title' -->
|
||||
<string name="message_additional_headers_not_downloaded">Not all headers have been downloaded or saved. Select \"Save all headers locally\" in the account\'s incoming server settings to enable this for the future.</string>
|
||||
@ -554,6 +560,8 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
||||
<string name="account_settings_notification_opens_unread_summary">Searches for unread messages when Notification is opened</string>
|
||||
<string name="account_settings_notification_unread_count_label">Show unread count</string>
|
||||
<string name="account_settings_notification_unread_count_summary">Show the number of unread messages in the notification bar.</string>
|
||||
<string name="account_settings_mark_message_as_read_on_view_label">Mark message as read when opening</string>
|
||||
<string name="account_settings_mark_message_as_read_on_view_summary">Mark a message as read when it is opened for viewing</string>
|
||||
|
||||
<string name="account_settings_enable_move_buttons_label">Enable refile buttons</string>
|
||||
<string name="account_settings_enable_move_buttons_summary">Show the Archive, Move, and Spam buttons.</string>
|
||||
@ -787,6 +795,7 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
||||
|
||||
<string name="sort_by">Sort by...</string>
|
||||
<string name="sort_by_date">Date</string>
|
||||
<string name="sort_by_arrival">Arrival</string>
|
||||
<string name="sort_by_sender">Sender</string>
|
||||
<string name="sort_by_subject">Subject</string>
|
||||
<string name="sort_by_flag">Star</string>
|
||||
@ -809,6 +818,7 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
||||
\"Plus\" account. Please launch the Web browser to gain access to
|
||||
these mail accounts.</string>
|
||||
<string name="provider_note_yahoojp">If you would like to use POP3 for this provider, You should permit to use POP3 on Yahoo mail settings page.</string>
|
||||
<string name="provider_note_auonejp">If you would like to use IMAP or POP3 for this provider, You should permit to use IMAP or POP3 on au one mail settings page.</string>
|
||||
<string name="provider_note_naver">If you would like to use IMAP or POP3 for this provider, You should permit to use IMAP or POP3 on Naver mail settings page.</string>
|
||||
<string name="provider_note_hanmail">If you would like to use IMAP or POP3 for this provider, You should permit to use IMAP or POP3 on Hanmail(Daum) mail settings page.</string>
|
||||
<string name="provider_note_paran">If you would like to use IMAP or POP3 for this provider, You should permit to use IMAP or POP3 on Paran mail settings page.</string>
|
||||
@ -1137,4 +1147,31 @@ Welcome to K-9 Mail setup. K-9 is an open source mail client for Android origin
|
||||
the import operation. Please install a file manager application from Android Market</string>
|
||||
<string name="open_market">Open Market</string>
|
||||
<string name="close">Close</string>
|
||||
|
||||
<string name="webview_empty_message">No text</string>
|
||||
|
||||
<string name="webview_contextmenu_link_view_action">Open for viewing</string>
|
||||
<string name="webview_contextmenu_link_share_action">Share link</string>
|
||||
<string name="webview_contextmenu_link_copy_action">Copy link to clipboard</string>
|
||||
<string name="webview_contextmenu_link_clipboard_label">Link</string>
|
||||
|
||||
<string name="webview_contextmenu_image_title">Image</string>
|
||||
<string name="webview_contextmenu_image_view_action">View image</string>
|
||||
<string name="webview_contextmenu_image_save_action">Save image</string>
|
||||
<string name="webview_contextmenu_image_download_action">Download image</string>
|
||||
<string name="webview_contextmenu_image_copy_action">Copy image URL to clipboard</string>
|
||||
<string name="webview_contextmenu_image_clipboard_label">Image URL</string>
|
||||
|
||||
<string name="webview_contextmenu_phone_call_action">Call number</string>
|
||||
<string name="webview_contextmenu_phone_save_action">Save to Contacts</string>
|
||||
<string name="webview_contextmenu_phone_copy_action">Copy phone number to clipboard</string>
|
||||
<string name="webview_contextmenu_phone_clipboard_label">Phone number</string>
|
||||
|
||||
<string name="webview_contextmenu_email_send_action">Send mail</string>
|
||||
<string name="webview_contextmenu_email_save_action">Save to Contacts</string>
|
||||
<string name="webview_contextmenu_email_copy_action">Copy email address to clipboard</string>
|
||||
<string name="webview_contextmenu_email_clipboard_label">Email address</string>
|
||||
|
||||
<string name="image_saved_as">Saved image as \"<xliff:g id="filename">%s</xliff:g>\"</string>
|
||||
<string name="image_saving_failed">Saving the image failed.</string>
|
||||
</resources>
|
||||
|
@ -81,6 +81,17 @@
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen
|
||||
android:title="@string/interaction_preferences">
|
||||
|
||||
<CheckBoxPreference
|
||||
android:persistent="false"
|
||||
android:key="mark_message_as_read_on_view"
|
||||
android:title="@string/account_settings_mark_message_as_read_on_view_label"
|
||||
android:summary="@string/account_settings_mark_message_as_read_on_view_summary" />
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen
|
||||
android:title="@string/account_settings_sync"
|
||||
android:key="incoming_prefs">
|
||||
|
@ -283,6 +283,11 @@
|
||||
<incoming uri="pop3+ssl+://pop.mail.yahoo.co.jp" username="$user" />
|
||||
<outgoing uri="smtp://smtp.mail.yahoo.co.jp:587" username="$user" />
|
||||
</provider>
|
||||
<provider id="auone" label="au one" domain="auone.jp"
|
||||
note="@string/provider_note_auonejp">
|
||||
<incoming uri="imap+ssl+://imap.gmail.com" username="$email" />
|
||||
<outgoing uri="smtp+ssl+://smtp.gmail.com" username="$email" />
|
||||
</provider>
|
||||
|
||||
<!-- Korean -->
|
||||
<provider id="naver" label="Naver" domain="naver.com"
|
||||
|
@ -151,6 +151,7 @@ public class Account implements BaseAccount {
|
||||
private String mSyncKey;
|
||||
private String mSecurityKey;
|
||||
private boolean mCryptoAutoEncrypt;
|
||||
private boolean mMarkMessageAsReadOnView;
|
||||
|
||||
private CryptoProvider mCryptoProvider = null;
|
||||
|
||||
@ -238,6 +239,7 @@ public class Account implements BaseAccount {
|
||||
mCryptoAutoSignature = false;
|
||||
mCryptoAutoEncrypt = false;
|
||||
mEnabled = true;
|
||||
mMarkMessageAsReadOnView = true;
|
||||
|
||||
searchableFolders = Searchable.ALL;
|
||||
|
||||
@ -395,6 +397,7 @@ public class Account implements BaseAccount {
|
||||
mEnabled = prefs.getBoolean(mUuid + ".enabled", true);
|
||||
mSyncKey = prefs.getString(mUuid + ".syncKey", "");
|
||||
mSecurityKey = prefs.getString(mUuid + ".securityKey", "");
|
||||
mMarkMessageAsReadOnView = prefs.getBoolean(mUuid + ".markMessageAsReadOnView", true);
|
||||
}
|
||||
|
||||
protected synchronized void delete(Preferences preferences) {
|
||||
@ -474,6 +477,7 @@ public class Account implements BaseAccount {
|
||||
editor.remove(mUuid + ".securityKey");
|
||||
editor.remove(mUuid + ".enableMoveButtons");
|
||||
editor.remove(mUuid + ".hideMoveButtonsEnum");
|
||||
editor.remove(mUuid + ".markMessageAsReadOnView");
|
||||
for (String type : networkTypes) {
|
||||
editor.remove(mUuid + ".useCompression." + type);
|
||||
}
|
||||
@ -634,7 +638,7 @@ public class Account implements BaseAccount {
|
||||
editor.putBoolean(mUuid + ".enabled", mEnabled);
|
||||
editor.putString(mUuid + ".syncKey", mSyncKey);
|
||||
editor.putString(mUuid + ".securityKey", mSecurityKey);
|
||||
|
||||
editor.putBoolean(mUuid + ".markMessageAsReadOnView", mMarkMessageAsReadOnView);
|
||||
editor.putBoolean(mUuid + ".vibrate", mNotificationSetting.shouldVibrate());
|
||||
editor.putInt(mUuid + ".vibratePattern", mNotificationSetting.getVibratePattern());
|
||||
editor.putInt(mUuid + ".vibrateTimes", mNotificationSetting.getVibrateTimes());
|
||||
@ -1547,4 +1551,12 @@ public class Account implements BaseAccount {
|
||||
public synchronized void setEnabled(boolean enabled) {
|
||||
mEnabled = enabled;
|
||||
}
|
||||
|
||||
public synchronized boolean isMarkMessageAsReadOnView() {
|
||||
return mMarkMessageAsReadOnView;
|
||||
}
|
||||
|
||||
public synchronized void setMarkMessageAsReadOnView(boolean value) {
|
||||
mMarkMessageAsReadOnView = value;
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,9 @@ import com.fsck.k9.service.ShutdownReceiver;
|
||||
import com.fsck.k9.service.StorageGoneReceiver;
|
||||
|
||||
public class K9 extends Application {
|
||||
public static final int THEME_LIGHT = 0;
|
||||
public static final int THEME_DARK = 1;
|
||||
|
||||
/**
|
||||
* Components that are interested in knowing when the K9 instance is
|
||||
* available and ready (Android invokes Application.onCreate() after other
|
||||
@ -75,7 +78,7 @@ public class K9 extends Application {
|
||||
}
|
||||
|
||||
private static String language = "";
|
||||
private static int theme = android.R.style.Theme_Light;
|
||||
private static int theme = THEME_LIGHT;
|
||||
|
||||
private static final FontSizes fontSizes = new FontSizes();
|
||||
|
||||
@ -571,7 +574,17 @@ public class K9 extends Application {
|
||||
}
|
||||
|
||||
K9.setK9Language(sprefs.getString("language", ""));
|
||||
K9.setK9Theme(sprefs.getInt("theme", android.R.style.Theme_Light));
|
||||
|
||||
int theme = sprefs.getInt("theme", THEME_LIGHT);
|
||||
|
||||
// We used to save the resource ID of the theme. So convert that to the new format if
|
||||
// necessary.
|
||||
if (theme == THEME_DARK || theme == android.R.style.Theme) {
|
||||
theme = THEME_DARK;
|
||||
} else {
|
||||
theme = THEME_LIGHT;
|
||||
}
|
||||
K9.setK9Theme(theme);
|
||||
}
|
||||
|
||||
private void maybeSetupStrictMode() {
|
||||
@ -628,6 +641,14 @@ public class K9 extends Application {
|
||||
language = nlanguage;
|
||||
}
|
||||
|
||||
public static int getK9ThemeResourceId(int theme) {
|
||||
return (theme == THEME_LIGHT) ? android.R.style.Theme_Light : android.R.style.Theme;
|
||||
}
|
||||
|
||||
public static int getK9ThemeResourceId() {
|
||||
return getK9ThemeResourceId(theme);
|
||||
}
|
||||
|
||||
public static int getK9Theme() {
|
||||
return theme;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import android.app.ProgressDialog;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnMultiChoiceClickListener;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
@ -45,12 +46,10 @@ import android.webkit.WebView;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CheckedTextView;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.ScrollView;
|
||||
@ -58,7 +57,6 @@ import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.AdapterView.OnItemSelectedListener;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
@ -927,8 +925,14 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(int id) {
|
||||
// Android recreates our dialogs on configuration changes even when they have been
|
||||
// dismissed. Make sure we have all information necessary before creating a new dialog.
|
||||
switch (id) {
|
||||
case DIALOG_REMOVE_ACCOUNT:
|
||||
case DIALOG_REMOVE_ACCOUNT: {
|
||||
if (mSelectedContextAccount == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ConfirmationDialog.create(this, id,
|
||||
R.string.account_delete_dlg_title,
|
||||
getString(R.string.account_delete_dlg_instructions_fmt,
|
||||
@ -939,23 +943,28 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
@Override
|
||||
public void run() {
|
||||
if (mSelectedContextAccount instanceof Account) {
|
||||
Account realAccount = (Account)mSelectedContextAccount;
|
||||
Account realAccount = (Account) mSelectedContextAccount;
|
||||
try {
|
||||
realAccount.getLocalStore().delete();
|
||||
} catch (Exception e) {
|
||||
// Ignore, this may lead to localStores on sd-cards that are
|
||||
// currently not inserted to be left
|
||||
// Ignore, this may lead to localStores on sd-cards that
|
||||
// are currently not inserted to be left
|
||||
}
|
||||
MessagingController.getInstance(getApplication())
|
||||
.notifyAccountCancel(Accounts.this, realAccount);
|
||||
Preferences.getPreferences(Accounts.this).deleteAccount(realAccount);
|
||||
Preferences.getPreferences(Accounts.this)
|
||||
.deleteAccount(realAccount);
|
||||
K9.setServicesEnabled(Accounts.this);
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
case DIALOG_CLEAR_ACCOUNT: {
|
||||
if (mSelectedContextAccount == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
case DIALOG_CLEAR_ACCOUNT:
|
||||
return ConfirmationDialog.create(this, id,
|
||||
R.string.account_clear_dlg_title,
|
||||
getString(R.string.account_clear_dlg_instructions_fmt,
|
||||
@ -966,14 +975,20 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
@Override
|
||||
public void run() {
|
||||
if (mSelectedContextAccount instanceof Account) {
|
||||
Account realAccount = (Account)mSelectedContextAccount;
|
||||
mHandler.workingAccount(realAccount, R.string.clearing_account);
|
||||
MessagingController.getInstance(getApplication()).clear(realAccount, null);
|
||||
Account realAccount = (Account) mSelectedContextAccount;
|
||||
mHandler.workingAccount(realAccount,
|
||||
R.string.clearing_account);
|
||||
MessagingController.getInstance(getApplication())
|
||||
.clear(realAccount, null);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
case DIALOG_RECREATE_ACCOUNT: {
|
||||
if (mSelectedContextAccount == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
case DIALOG_RECREATE_ACCOUNT:
|
||||
return ConfirmationDialog.create(this, id,
|
||||
R.string.account_recreate_dlg_title,
|
||||
getString(R.string.account_recreate_dlg_instructions_fmt,
|
||||
@ -984,13 +999,16 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
@Override
|
||||
public void run() {
|
||||
if (mSelectedContextAccount instanceof Account) {
|
||||
Account realAccount = (Account)mSelectedContextAccount;
|
||||
mHandler.workingAccount(realAccount, R.string.recreating_account);
|
||||
MessagingController.getInstance(getApplication()).recreate(realAccount, null);
|
||||
Account realAccount = (Account) mSelectedContextAccount;
|
||||
mHandler.workingAccount(realAccount,
|
||||
R.string.recreating_account);
|
||||
MessagingController.getInstance(getApplication())
|
||||
.recreate(realAccount, null);
|
||||
}
|
||||
}
|
||||
});
|
||||
case DIALOG_NO_FILE_MANAGER:
|
||||
}
|
||||
case DIALOG_NO_FILE_MANAGER: {
|
||||
return ConfirmationDialog.create(this, id,
|
||||
R.string.import_dialog_error_title,
|
||||
getString(R.string.import_dialog_error_message),
|
||||
@ -1005,29 +1023,30 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return super.onCreateDialog(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareDialog(int id, Dialog d) {
|
||||
|
||||
AlertDialog alert = (AlertDialog) d;
|
||||
switch (id) {
|
||||
case DIALOG_REMOVE_ACCOUNT:
|
||||
case DIALOG_REMOVE_ACCOUNT: {
|
||||
alert.setMessage(getString(R.string.account_delete_dlg_instructions_fmt,
|
||||
mSelectedContextAccount.getDescription()));
|
||||
break;
|
||||
case DIALOG_CLEAR_ACCOUNT:
|
||||
}
|
||||
case DIALOG_CLEAR_ACCOUNT: {
|
||||
alert.setMessage(getString(R.string.account_clear_dlg_instructions_fmt,
|
||||
mSelectedContextAccount.getDescription()));
|
||||
break;
|
||||
case DIALOG_RECREATE_ACCOUNT:
|
||||
}
|
||||
case DIALOG_RECREATE_ACCOUNT: {
|
||||
alert.setMessage(getString(R.string.account_recreate_dlg_instructions_fmt,
|
||||
mSelectedContextAccount.getDescription()));
|
||||
break;
|
||||
case DIALOG_NO_FILE_MANAGER:
|
||||
alert.setMessage(getString(R.string.import_dialog_error_message));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
super.onPrepareDialog(id, d);
|
||||
@ -1468,8 +1487,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
private static class ImportSelectionDialog implements NonConfigurationInstance {
|
||||
private ImportContents mImportContents;
|
||||
private Uri mUri;
|
||||
private Dialog mDialog;
|
||||
private ListView mImportSelectionView;
|
||||
private AlertDialog mDialog;
|
||||
private SparseBooleanArray mSelection;
|
||||
|
||||
|
||||
@ -1487,8 +1505,7 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
public boolean retain() {
|
||||
if (mDialog != null) {
|
||||
// Save the selection state of each list item
|
||||
mSelection = mImportSelectionView.getCheckedItemPositions();
|
||||
mImportSelectionView = null;
|
||||
mSelection = mDialog.getListView().getCheckedItemPositions();
|
||||
|
||||
mDialog.dismiss();
|
||||
mDialog = null;
|
||||
@ -1502,8 +1519,6 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
}
|
||||
|
||||
public void show(final Accounts activity, SparseBooleanArray selection) {
|
||||
final ListView importSelectionView = new ListView(activity);
|
||||
mImportSelectionView = importSelectionView;
|
||||
List<String> contents = new ArrayList<String>();
|
||||
|
||||
if (mImportContents.globalSettings) {
|
||||
@ -1514,25 +1529,15 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
contents.add(account.name);
|
||||
}
|
||||
|
||||
importSelectionView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
|
||||
importSelectionView.setAdapter(new ArrayAdapter<String>(activity,
|
||||
android.R.layout.simple_list_item_checked, contents));
|
||||
importSelectionView.setOnItemSelectedListener(new OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
|
||||
CheckedTextView ctv = (CheckedTextView)view;
|
||||
ctv.setChecked(!ctv.isChecked());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> arg0) {
|
||||
/* Do nothing */
|
||||
}
|
||||
});
|
||||
|
||||
int count = contents.size();
|
||||
boolean[] checkedItems = new boolean[count];
|
||||
if (selection != null) {
|
||||
for (int i = 0, end = contents.size(); i < end; i++) {
|
||||
importSelectionView.setItemChecked(i, selection.get(i));
|
||||
for (int i = 0; i < count; i++) {
|
||||
checkedItems[i] = selection.get(i);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < count; i++) {
|
||||
checkedItems[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1540,25 +1545,30 @@ public class Accounts extends K9ListActivity implements OnItemClickListener, OnC
|
||||
//TODO: listview footer: "Select all" / "Select none" buttons?
|
||||
//TODO: listview footer: "Overwrite existing accounts?" checkbox
|
||||
|
||||
OnMultiChoiceClickListener listener = new OnMultiChoiceClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
|
||||
((AlertDialog) dialog).getListView().setItemChecked(which, isChecked);
|
||||
}
|
||||
};
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setMultiChoiceItems(contents.toArray(new String[0]), checkedItems, listener);
|
||||
builder.setTitle(activity.getString(R.string.settings_import_selection));
|
||||
builder.setView(importSelectionView);
|
||||
builder.setInverseBackgroundForced(true);
|
||||
builder.setPositiveButton(R.string.okay_action,
|
||||
new DialogInterface.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
ListAdapter adapter = importSelectionView.getAdapter();
|
||||
int count = adapter.getCount();
|
||||
SparseBooleanArray pos = importSelectionView.getCheckedItemPositions();
|
||||
ListView listView = ((AlertDialog) dialog).getListView();
|
||||
SparseBooleanArray pos = listView.getCheckedItemPositions();
|
||||
|
||||
boolean includeGlobals = mImportContents.globalSettings ? pos.get(0) : false;
|
||||
List<String> accountUuids = new ArrayList<String>();
|
||||
int start = mImportContents.globalSettings ? 1 : 0;
|
||||
for (int i = start; i < count; i++) {
|
||||
for (int i = start, end = listView.getCount(); i < end; i++) {
|
||||
if (pos.get(i)) {
|
||||
accountUuids.add(mImportContents.accounts.get(i - start).uuid);
|
||||
accountUuids.add(mImportContents.accounts.get(i-start).uuid);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,243 +0,0 @@
|
||||
package com.fsck.k9.activity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.widget.BaseExpandableListAdapter;
|
||||
import android.widget.ExpandableListAdapter;
|
||||
import android.widget.ExpandableListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.Identity;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.Preferences;
|
||||
import com.fsck.k9.R;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Activity displaying list of accounts/identity for user choice
|
||||
*
|
||||
* @see K9ExpandableListActivity
|
||||
*/
|
||||
public class ChooseAccount extends K9ExpandableListActivity {
|
||||
private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[0];
|
||||
|
||||
/**
|
||||
* {@link Intent} extended data name for storing {@link Account#getUuid()
|
||||
* account UUID}
|
||||
*/
|
||||
public static final String EXTRA_ACCOUNT = ChooseAccount.class.getName() + "_account";
|
||||
|
||||
/**
|
||||
* {@link Intent} extended data name for storing serialized {@link Identity}
|
||||
*/
|
||||
public static final String EXTRA_IDENTITY = ChooseAccount.class.getName() + "_identity";
|
||||
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
||||
setContentView(R.layout.choose_account);
|
||||
|
||||
final ExpandableListView expandableListView = getExpandableListView();
|
||||
expandableListView.setItemsCanFocus(false);
|
||||
|
||||
final IdentitiesAdapter adapter = createAdapter();
|
||||
setListAdapter(adapter);
|
||||
|
||||
expandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
|
||||
@Override
|
||||
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
|
||||
int childPosition, long id) {
|
||||
final Identity identity = (Identity) adapter.getChild(groupPosition, childPosition);
|
||||
final Account account = (Account) adapter.getGroup(groupPosition);
|
||||
|
||||
if (!account.isAvailable(v.getContext())) {
|
||||
Log.i(K9.LOG_TAG, "Refusing selection of unavailable account");
|
||||
return true;
|
||||
}
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(EXTRA_ACCOUNT, account.getUuid());
|
||||
intent.putExtra(EXTRA_IDENTITY, identity);
|
||||
setResult(RESULT_OK, intent);
|
||||
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
final Bundle extras = getIntent().getExtras();
|
||||
final String uuid = extras.getString(EXTRA_ACCOUNT);
|
||||
if (uuid != null) {
|
||||
final Account[] accounts = adapter.getAccounts();
|
||||
final int length = accounts.length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
final Account account = accounts[i];
|
||||
if (uuid.equals(account.getUuid())) {
|
||||
// setSelectedChild() doesn't seem to obey the
|
||||
// shouldExpandGroup parameter (2.1), manually expanding
|
||||
// group
|
||||
expandableListView.expandGroup(i);
|
||||
|
||||
final List<Identity> identities = account.getIdentities();
|
||||
final Identity identity = (Identity) extras.getSerializable(EXTRA_IDENTITY);
|
||||
if (identity == null) {
|
||||
expandableListView.setSelectedChild(i, 0, true);
|
||||
break;
|
||||
}
|
||||
for (int j = 0; j < identities.size(); j++) {
|
||||
final Identity loopIdentity = identities.get(j);
|
||||
if (identity.equals(loopIdentity)) {
|
||||
expandableListView.setSelectedChild(i, j, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IdentitiesAdapter createAdapter() {
|
||||
return new IdentitiesAdapter(this, getLayoutInflater());
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically provides accounts/identities data for
|
||||
* {@link ExpandableListView#setAdapter(ExpandableListAdapter)}:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Groups represent {@link Account accounts}</li>
|
||||
* <li>Children represent {@link Identity identities} of the parent account</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static class IdentitiesAdapter extends BaseExpandableListAdapter {
|
||||
|
||||
private Context mContext;
|
||||
private LayoutInflater mLayoutInflater;
|
||||
private Account[] mAccounts;
|
||||
|
||||
public IdentitiesAdapter(final Context context, final LayoutInflater layoutInflater) {
|
||||
mContext = context;
|
||||
mLayoutInflater = layoutInflater;
|
||||
Preferences prefs = Preferences.getPreferences(mContext);
|
||||
mAccounts = prefs.getAvailableAccounts().toArray(EMPTY_ACCOUNT_ARRAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getChild(int groupPosition, int childPosition) {
|
||||
return getAccounts()[groupPosition].getIdentity(childPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getChildId(int groupPosition, int childPosition) {
|
||||
return Integer.valueOf(childPosition).longValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildrenCount(int groupPosition) {
|
||||
return getAccounts()[groupPosition].getIdentities().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGroup(int groupPosition) {
|
||||
return getAccounts()[groupPosition];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupCount() {
|
||||
return getAccounts().length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getGroupId(int groupPosition) {
|
||||
return Integer.valueOf(groupPosition).longValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
|
||||
ViewGroup parent) {
|
||||
final View v;
|
||||
if (convertView == null) {
|
||||
v = mLayoutInflater.inflate(R.layout.choose_account_item, parent, false);
|
||||
} else {
|
||||
v = convertView;
|
||||
}
|
||||
|
||||
final TextView description = (TextView) v.findViewById(R.id.description);
|
||||
final Account account = getAccounts()[groupPosition];
|
||||
description.setText(account.getDescription());
|
||||
description.setTextSize(TypedValue.COMPLEX_UNIT_SP, K9.getFontSizes().getAccountName());
|
||||
|
||||
// display unavailable accounts translucent
|
||||
/*
|
||||
* 20101030/fiouzy: NullPointerException on null getBackground()
|
||||
*
|
||||
if (account.isAvailable(parent.getContext()))
|
||||
{
|
||||
description.getBackground().setAlpha(255);
|
||||
description.getBackground().setAlpha(255);
|
||||
}
|
||||
else
|
||||
{
|
||||
description.getBackground().setAlpha(127);
|
||||
description.getBackground().setAlpha(127);
|
||||
}
|
||||
*/
|
||||
|
||||
v.findViewById(R.id.chip).setBackgroundColor(account.getChipColor());
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
|
||||
View convertView, ViewGroup parent) {
|
||||
final Account account = getAccounts()[groupPosition];
|
||||
final Identity identity = account.getIdentity(childPosition);
|
||||
|
||||
final View v;
|
||||
if (convertView == null) {
|
||||
v = mLayoutInflater.inflate(R.layout.choose_identity_item, parent, false);
|
||||
} else {
|
||||
v = convertView;
|
||||
}
|
||||
|
||||
final TextView name = (TextView) v.findViewById(R.id.name);
|
||||
final TextView description = (TextView) v.findViewById(R.id.description);
|
||||
name.setTextSize(TypedValue.COMPLEX_UNIT_SP, K9.getFontSizes().getAccountName());
|
||||
description.setTextSize(TypedValue.COMPLEX_UNIT_SP, K9.getFontSizes().getAccountDescription());
|
||||
|
||||
name.setText(identity.getDescription());
|
||||
description.setText(String.format("%s <%s>", identity.getName(), identity.getEmail()));
|
||||
|
||||
v.findViewById(R.id.chip).setBackgroundColor(account.getChipColor());
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
// returning false since accounts/identities are mutable
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChildSelectable(int groupPosition, int childPosition) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private Account[] getAccounts() {
|
||||
return mAccounts;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,11 @@
|
||||
|
||||
package com.fsck.k9.activity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
@ -19,42 +24,18 @@ import android.widget.EditText;
|
||||
import android.widget.Filter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import com.fsck.k9.*;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.Account.FolderMode;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.Preferences;
|
||||
import com.fsck.k9.R;
|
||||
import com.fsck.k9.controller.MessagingController;
|
||||
import com.fsck.k9.controller.MessagingListener;
|
||||
import com.fsck.k9.mail.Folder;
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
||||
public class ChooseFolder extends K9ListActivity {
|
||||
String mFolder;
|
||||
String mSelectFolder;
|
||||
Account mAccount;
|
||||
MessageReference mMessageReference;
|
||||
ArrayAdapter<String> mAdapter;
|
||||
private ChooseFolderHandler mHandler = new ChooseFolderHandler();
|
||||
String heldInbox = null;
|
||||
boolean hideCurrentFolder = true;
|
||||
boolean showOptionNone = false;
|
||||
boolean showDisplayableOnly = false;
|
||||
|
||||
/**
|
||||
* What folders to display.<br/>
|
||||
* Initialized to whatever is configured
|
||||
* but can be overridden via {@link #onOptionsItemSelected(MenuItem)}
|
||||
* while this activity is showing.
|
||||
*/
|
||||
private Account.FolderMode mMode;
|
||||
/**
|
||||
* Current filter used by our ArrayAdapter.<br/>
|
||||
* Created on the fly and invalidated if a new
|
||||
* set of folders is chosen via {@link #onOptionsItemSelected(MenuItem)}
|
||||
*/
|
||||
private FolderListFilter<String> myFilter = null;
|
||||
|
||||
public static final String EXTRA_ACCOUNT = "com.fsck.k9.ChooseFolder_account";
|
||||
public static final String EXTRA_CUR_FOLDER = "com.fsck.k9.ChooseFolder_curfolder";
|
||||
public static final String EXTRA_SEL_FOLDER = "com.fsck.k9.ChooseFolder_selfolder";
|
||||
@ -64,6 +45,34 @@ public class ChooseFolder extends K9ListActivity {
|
||||
public static final String EXTRA_SHOW_FOLDER_NONE = "com.fsck.k9.ChooseFolder_showOptionNone";
|
||||
public static final String EXTRA_SHOW_DISPLAYABLE_ONLY = "com.fsck.k9.ChooseFolder_showDisplayableOnly";
|
||||
|
||||
|
||||
String mFolder;
|
||||
String mSelectFolder;
|
||||
Account mAccount;
|
||||
MessageReference mMessageReference;
|
||||
ArrayAdapter<String> mAdapter;
|
||||
private ChooseFolderHandler mHandler = new ChooseFolderHandler();
|
||||
String mHeldInbox = null;
|
||||
boolean mHideCurrentFolder = true;
|
||||
boolean mShowOptionNone = false;
|
||||
boolean mShowDisplayableOnly = false;
|
||||
|
||||
/**
|
||||
* What folders to display.<br/>
|
||||
* Initialized to whatever is configured
|
||||
* but can be overridden via {@link #onOptionsItemSelected(MenuItem)}
|
||||
* while this activity is showing.
|
||||
*/
|
||||
private Account.FolderMode mMode;
|
||||
|
||||
/**
|
||||
* Current filter used by our ArrayAdapter.<br/>
|
||||
* Created on the fly and invalidated if a new
|
||||
* set of folders is chosen via {@link #onOptionsItemSelected(MenuItem)}
|
||||
*/
|
||||
private FolderListFilter<String> mMyFilter = null;
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@ -79,13 +88,13 @@ public class ChooseFolder extends K9ListActivity {
|
||||
mFolder = intent.getStringExtra(EXTRA_CUR_FOLDER);
|
||||
mSelectFolder = intent.getStringExtra(EXTRA_SEL_FOLDER);
|
||||
if (intent.getStringExtra(EXTRA_SHOW_CURRENT) != null) {
|
||||
hideCurrentFolder = false;
|
||||
mHideCurrentFolder = false;
|
||||
}
|
||||
if (intent.getStringExtra(EXTRA_SHOW_FOLDER_NONE) != null) {
|
||||
showOptionNone = true;
|
||||
mShowOptionNone = true;
|
||||
}
|
||||
if (intent.getStringExtra(EXTRA_SHOW_DISPLAYABLE_ONLY) != null) {
|
||||
showDisplayableOnly = true;
|
||||
mShowDisplayableOnly = true;
|
||||
}
|
||||
if (mFolder == null)
|
||||
mFolder = "";
|
||||
@ -104,57 +113,44 @@ public class ChooseFolder extends K9ListActivity {
|
||||
|
||||
setListAdapter(mAdapter);
|
||||
|
||||
|
||||
mMode = mAccount.getFolderTargetMode();
|
||||
MessagingController.getInstance(getApplication()).listFolders(mAccount, false, mListener);
|
||||
|
||||
|
||||
this.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(EXTRA_ACCOUNT, mAccount.getUuid());
|
||||
intent.putExtra(EXTRA_CUR_FOLDER, mFolder);
|
||||
Intent result = new Intent();
|
||||
result.putExtra(EXTRA_ACCOUNT, mAccount.getUuid());
|
||||
result.putExtra(EXTRA_CUR_FOLDER, mFolder);
|
||||
String destFolderName = (String)((TextView)view).getText();
|
||||
if (heldInbox != null && getString(R.string.special_mailbox_name_inbox).equals(destFolderName)) {
|
||||
destFolderName = heldInbox;
|
||||
if (mHeldInbox != null && getString(R.string.special_mailbox_name_inbox).equals(destFolderName)) {
|
||||
destFolderName = mHeldInbox;
|
||||
}
|
||||
intent.putExtra(EXTRA_NEW_FOLDER, destFolderName);
|
||||
intent.putExtra(EXTRA_MESSAGE, mMessageReference);
|
||||
setResult(RESULT_OK, intent);
|
||||
result.putExtra(EXTRA_NEW_FOLDER, destFolderName);
|
||||
result.putExtra(EXTRA_MESSAGE, mMessageReference);
|
||||
setResult(RESULT_OK, result);
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
class ChooseFolderHandler extends Handler {
|
||||
|
||||
private static final int MSG_PROGRESS = 2;
|
||||
|
||||
private static final int MSG_DATA_CHANGED = 3;
|
||||
private static final int MSG_SET_SELECTED_FOLDER = 4;
|
||||
private static final int MSG_PROGRESS = 1;
|
||||
private static final int MSG_SET_SELECTED_FOLDER = 2;
|
||||
|
||||
@Override
|
||||
public void handleMessage(android.os.Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_PROGRESS:
|
||||
case MSG_PROGRESS: {
|
||||
setProgressBarIndeterminateVisibility(msg.arg1 != 0);
|
||||
break;
|
||||
case MSG_DATA_CHANGED:
|
||||
mAdapter.notifyDataSetChanged();
|
||||
|
||||
/*
|
||||
* Only enable the text filter after the list has been
|
||||
* populated to avoid possible race conditions because our
|
||||
* FolderListFilter isn't really thread-safe.
|
||||
*/
|
||||
getListView().setTextFilterEnabled(true);
|
||||
break;
|
||||
case MSG_SET_SELECTED_FOLDER:
|
||||
}
|
||||
case MSG_SET_SELECTED_FOLDER: {
|
||||
getListView().setSelection(msg.arg1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void progress(boolean progress) {
|
||||
android.os.Message msg = new android.os.Message();
|
||||
@ -169,22 +165,18 @@ public class ChooseFolder extends K9ListActivity {
|
||||
msg.arg1 = position;
|
||||
sendMessage(msg);
|
||||
}
|
||||
|
||||
public void dataChanged() {
|
||||
sendEmptyMessage(MSG_DATA_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean onCreateOptionsMenu(Menu menu) {
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
getMenuInflater().inflate(R.menu.folder_select_option, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean onOptionsItemSelected(MenuItem item) {
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
|
||||
|
||||
case R.id.display_1st_class: {
|
||||
setDisplayMode(FolderMode.FIRST_CLASS);
|
||||
return true;
|
||||
@ -201,26 +193,22 @@ public class ChooseFolder extends K9ListActivity {
|
||||
setDisplayMode(FolderMode.ALL);
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.list_folders: {
|
||||
onRefresh();
|
||||
|
||||
return true;
|
||||
}
|
||||
case R.id.filter_folders: {
|
||||
onEnterFilter();
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void onRefresh() {
|
||||
|
||||
MessagingController.getInstance(getApplication()).listFolders(mAccount, true, mListener);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -232,51 +220,49 @@ public class ChooseFolder extends K9ListActivity {
|
||||
|
||||
final EditText input = new EditText(this);
|
||||
input.addTextChangedListener(new TextWatcher() {
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
mAdapter.getFilter().filter(input.getText().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count,
|
||||
int after) {
|
||||
}
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
/* not used */ }
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
}
|
||||
public void afterTextChanged(Editable s) { /* not used */ }
|
||||
});
|
||||
input.setHint(R.string.folder_list_filter_hint);
|
||||
filterAlert.setView(input);
|
||||
|
||||
filterAlert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
|
||||
String okay = getString(R.string.okay_action);
|
||||
filterAlert.setPositiveButton(okay, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
String value = input.getText().toString().trim();
|
||||
mAdapter.getFilter().filter(value);
|
||||
}
|
||||
});
|
||||
|
||||
filterAlert.setNegativeButton("Cancel",
|
||||
new DialogInterface.OnClickListener() {
|
||||
String cancel = getString(R.string.cancel_action);
|
||||
filterAlert.setNegativeButton(cancel, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int whichButton) {
|
||||
mAdapter.getFilter().filter("");
|
||||
}
|
||||
});
|
||||
|
||||
filterAlert.show();
|
||||
|
||||
}
|
||||
|
||||
private void setDisplayMode(FolderMode aMode) {
|
||||
mMode = aMode;
|
||||
// invalidate the current filter as it is working on an inval
|
||||
if (myFilter != null) {
|
||||
myFilter.invalidate();
|
||||
if (mMyFilter != null) {
|
||||
mMyFilter.invalidate();
|
||||
}
|
||||
//re-populate the list
|
||||
MessagingController.getInstance(getApplication()).listFolders(mAccount,
|
||||
false, mListener);
|
||||
MessagingController.getInstance(getApplication()).listFolders(mAccount, false, mListener);
|
||||
}
|
||||
|
||||
private MessagingListener mListener = new MessagingListener() {
|
||||
@ -316,34 +302,39 @@ public class ChooseFolder extends K9ListActivity {
|
||||
String name = folder.getRemoteName();
|
||||
|
||||
// Inbox needs to be compared case-insensitively
|
||||
if (hideCurrentFolder && (name.equals(mFolder) ||
|
||||
(mAccount.getInboxFolderName().equalsIgnoreCase(mFolder) && mAccount.getInboxFolderName().equalsIgnoreCase(name)))) {
|
||||
if (mHideCurrentFolder && (name.equals(mFolder) || (
|
||||
mAccount.getInboxFolderName().equalsIgnoreCase(mFolder) &&
|
||||
mAccount.getInboxFolderName().equalsIgnoreCase(name)))) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
folder.refresh(prefs);
|
||||
Folder.FolderClass fMode = folder.getDisplayClass();
|
||||
|
||||
if ((aMode == Account.FolderMode.FIRST_CLASS && fMode != Folder.FolderClass.FIRST_CLASS)
|
||||
|| (aMode == Account.FolderMode.FIRST_AND_SECOND_CLASS &&
|
||||
if ((aMode == Account.FolderMode.FIRST_CLASS &&
|
||||
fMode != Folder.FolderClass.FIRST_CLASS) || (
|
||||
aMode == Account.FolderMode.FIRST_AND_SECOND_CLASS &&
|
||||
fMode != Folder.FolderClass.FIRST_CLASS &&
|
||||
fMode != Folder.FolderClass.SECOND_CLASS)
|
||||
|| (aMode == Account.FolderMode.NOT_SECOND_CLASS && fMode == Folder.FolderClass.SECOND_CLASS)) {
|
||||
fMode != Folder.FolderClass.SECOND_CLASS) || (
|
||||
aMode == Account.FolderMode.NOT_SECOND_CLASS &&
|
||||
fMode == Folder.FolderClass.SECOND_CLASS)) {
|
||||
continue;
|
||||
}
|
||||
} catch (MessagingException me) {
|
||||
Log.e(K9.LOG_TAG, "Couldn't get prefs to check for displayability of folder " + folder.getName(), me);
|
||||
Log.e(K9.LOG_TAG, "Couldn't get prefs to check for displayability of folder " +
|
||||
folder.getName(), me);
|
||||
}
|
||||
|
||||
localFolders.add(folder.getRemoteName());
|
||||
|
||||
}
|
||||
|
||||
if (showOptionNone) {
|
||||
if (mShowOptionNone) {
|
||||
localFolders.add(K9.FOLDER_NONE);
|
||||
}
|
||||
|
||||
Collections.sort(localFolders, new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(String aName, String bName) {
|
||||
if (K9.FOLDER_NONE.equalsIgnoreCase(aName)) {
|
||||
return -1;
|
||||
@ -361,17 +352,22 @@ public class ChooseFolder extends K9ListActivity {
|
||||
return aName.compareToIgnoreCase(bName);
|
||||
}
|
||||
});
|
||||
mAdapter.setNotifyOnChange(false);
|
||||
int selectedFolder = -1;
|
||||
|
||||
/*
|
||||
* We're not allowed to change the adapter from a background thread, so we collect the
|
||||
* folder names and update the adapter in the UI thread (see finally block).
|
||||
*/
|
||||
final List<String> folderList = new ArrayList<String>();
|
||||
try {
|
||||
mAdapter.clear();
|
||||
int position = 0;
|
||||
for (String name : localFolders) {
|
||||
if (mAccount.getInboxFolderName().equalsIgnoreCase(name)) {
|
||||
mAdapter.add(getString(R.string.special_mailbox_name_inbox));
|
||||
heldInbox = name;
|
||||
} else if (!K9.ERROR_FOLDER_NAME.equals(name) && !account.getOutboxFolderName().equals(name)) {
|
||||
mAdapter.add(name);
|
||||
folderList.add(getString(R.string.special_mailbox_name_inbox));
|
||||
mHeldInbox = name;
|
||||
} else if (!K9.ERROR_FOLDER_NAME.equals(name) &&
|
||||
!account.getOutboxFolderName().equals(name)) {
|
||||
folderList.add(name);
|
||||
}
|
||||
|
||||
if (mSelectFolder != null) {
|
||||
@ -383,24 +379,35 @@ public class ChooseFolder extends K9ListActivity {
|
||||
if (name.equals(mSelectFolder)) {
|
||||
selectedFolder = position;
|
||||
}
|
||||
} else if (name.equals(mFolder) ||
|
||||
(mAccount.getInboxFolderName().equalsIgnoreCase(mFolder) && mAccount.getInboxFolderName().equalsIgnoreCase(name))) {
|
||||
} else if (name.equals(mFolder) || (
|
||||
mAccount.getInboxFolderName().equalsIgnoreCase(mFolder) &&
|
||||
mAccount.getInboxFolderName().equalsIgnoreCase(name))) {
|
||||
selectedFolder = position;
|
||||
}
|
||||
position++;
|
||||
}
|
||||
} finally {
|
||||
mAdapter.setNotifyOnChange(true);
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// runOnUiThread(
|
||||
// Now we're in the UI-thread, we can safely change the contents of the adapter.
|
||||
mAdapter.clear();
|
||||
for (String folderName: folderList) {
|
||||
mAdapter.add(folderName);
|
||||
}
|
||||
|
||||
mAdapter.notifyDataSetChanged();
|
||||
|
||||
/*
|
||||
* Only enable the text filter after the list has been
|
||||
* populated to avoid possible race conditions because our
|
||||
* FolderListFilter isn't really thread-safe.
|
||||
*/
|
||||
getListView().setTextFilterEnabled(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
mHandler.dataChanged();
|
||||
|
||||
if (selectedFolder != -1) {
|
||||
mHandler.setSelectedFolder(selectedFolder);
|
||||
}
|
||||
|
@ -32,12 +32,21 @@ class InsertableHtmlContent implements Serializable {
|
||||
}
|
||||
|
||||
public void setHeaderInsertionPoint(int headerInsertionPoint) {
|
||||
if (headerInsertionPoint < 0 || headerInsertionPoint > quotedContent.length()) {
|
||||
this.headerInsertionPoint = 0;
|
||||
} else {
|
||||
this.headerInsertionPoint = headerInsertionPoint;
|
||||
}
|
||||
}
|
||||
|
||||
public void setFooterInsertionPoint(int footerInsertionPoint) {
|
||||
int len = quotedContent.length();
|
||||
if (footerInsertionPoint < 0 || footerInsertionPoint > len) {
|
||||
this.footerInsertionPoint = len;
|
||||
} else {
|
||||
this.footerInsertionPoint = footerInsertionPoint;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the quoted content.
|
||||
|
@ -23,14 +23,8 @@ public class K9Activity extends Activity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
onCreate(icicle, true);
|
||||
}
|
||||
|
||||
public void onCreate(Bundle icicle, boolean useTheme) {
|
||||
setLanguage(this, K9.getK9Language());
|
||||
if (useTheme) {
|
||||
setTheme(K9.getK9Theme());
|
||||
}
|
||||
setTheme(K9.getK9ThemeResourceId());
|
||||
super.onCreate(icicle);
|
||||
setupFormats();
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
package com.fsck.k9.activity;
|
||||
|
||||
import android.app.ExpandableListActivity;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.fsck.k9.K9;
|
||||
|
||||
/**
|
||||
* @see ExpandableListActivity
|
||||
*/
|
||||
public class K9ExpandableListActivity extends ExpandableListActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(K9.getK9Theme());
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ public class K9ListActivity extends ListActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
K9Activity.setLanguage(this, K9.getK9Language());
|
||||
setTheme(K9.getK9Theme());
|
||||
setTheme(K9.getK9ThemeResourceId());
|
||||
super.onCreate(icicle);
|
||||
setupFormats();
|
||||
}
|
||||
|
@ -15,15 +15,18 @@ import com.fsck.k9.mail.*;
|
||||
import com.fsck.k9.view.MessageWebView;
|
||||
import org.apache.james.mime4j.codec.EncoderUtil;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.AlertDialog.Builder;
|
||||
import android.app.Dialog;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Parcelable;
|
||||
@ -31,14 +34,17 @@ import android.provider.OpenableColumns;
|
||||
import android.text.util.Rfc822Tokenizer;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View.OnFocusChangeListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.webkit.WebView;
|
||||
import android.widget.AutoCompleteTextView.Validator;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
@ -84,6 +90,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
private static final int DIALOG_REFUSE_TO_SAVE_DRAFT_MARKED_ENCRYPTED = 2;
|
||||
private static final int DIALOG_CONTINUE_WITHOUT_PUBLIC_KEY = 3;
|
||||
private static final int DIALOG_CONFIRM_DISCARD_ON_BACK = 4;
|
||||
private static final int DIALOG_CHOOSE_IDENTITY = 5;
|
||||
|
||||
private static final long INVALID_DRAFT_ID = MessagingController.INVALID_MESSAGE_ID;
|
||||
|
||||
@ -128,12 +135,11 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
private static final int MSG_DISCARDED_DRAFT = 6;
|
||||
|
||||
private static final int ACTIVITY_REQUEST_PICK_ATTACHMENT = 1;
|
||||
private static final int ACTIVITY_CHOOSE_IDENTITY = 2;
|
||||
private static final int ACTIVITY_CHOOSE_ACCOUNT = 3;
|
||||
private static final int CONTACT_PICKER_TO = 4;
|
||||
private static final int CONTACT_PICKER_CC = 5;
|
||||
private static final int CONTACT_PICKER_BCC = 6;
|
||||
private static final int CONTACT_PICKER_TO = 2;
|
||||
private static final int CONTACT_PICKER_CC = 3;
|
||||
private static final int CONTACT_PICKER_BCC = 4;
|
||||
|
||||
private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[0];
|
||||
|
||||
/**
|
||||
* Regular expression to remove the first localized "Re:" prefix in subjects.
|
||||
@ -186,7 +192,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
|
||||
private QuotedTextMode mQuotedTextMode = QuotedTextMode.NONE;
|
||||
|
||||
private TextView mFromView;
|
||||
private Button mChooseIdentityButton;
|
||||
private LinearLayout mCcWrapper;
|
||||
private LinearLayout mBccWrapper;
|
||||
private MultiAutoCompleteTextView mToView;
|
||||
@ -410,7 +416,14 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
mAddressAdapter = EmailAddressAdapter.getInstance(this);
|
||||
mAddressValidator = new EmailAddressValidator();
|
||||
|
||||
mFromView = (TextView) findViewById(R.id.from);
|
||||
mChooseIdentityButton = (Button) findViewById(R.id.identity);
|
||||
mChooseIdentityButton.setOnClickListener(this);
|
||||
|
||||
if (mAccount.getIdentities().size() == 1 &&
|
||||
Preferences.getPreferences(this).getAvailableAccounts().size() == 1) {
|
||||
mChooseIdentityButton.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
mToView = (MultiAutoCompleteTextView) findViewById(R.id.to);
|
||||
mCcView = (MultiAutoCompleteTextView) findViewById(R.id.cc);
|
||||
mBccView = (MultiAutoCompleteTextView) findViewById(R.id.bcc);
|
||||
@ -548,8 +561,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
mQuotedTextEdit.setOnClickListener(this);
|
||||
mQuotedTextDelete.setOnClickListener(this);
|
||||
|
||||
mFromView.setVisibility(View.GONE);
|
||||
|
||||
mToView.setAdapter(mAddressAdapter);
|
||||
mToView.setTokenizer(new Rfc822Tokenizer());
|
||||
mToView.setValidator(mAddressValidator);
|
||||
@ -607,8 +618,9 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
mReadReceipt = mAccount.isMessageReadReceiptAlways();
|
||||
mQuoteStyle = mAccount.getQuoteStyle();
|
||||
|
||||
if (!mSourceMessageProcessed) {
|
||||
updateFrom();
|
||||
|
||||
if (!mSourceMessageProcessed) {
|
||||
updateSignature();
|
||||
|
||||
if (ACTION_REPLY.equals(action) ||
|
||||
@ -940,7 +952,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
if (mQuotedTextMode != QuotedTextMode.NONE && mMessageFormat == MessageFormat.HTML) {
|
||||
mQuotedHtmlContent = (InsertableHtmlContent) savedInstanceState.getSerializable(STATE_KEY_HTML_QUOTE);
|
||||
if (mQuotedHtmlContent != null && mQuotedHtmlContent.getQuotedContent() != null) {
|
||||
mQuotedHTML.loadDataWithBaseURL("http://", mQuotedHtmlContent.getQuotedContent(), "text/html", "utf-8", null);
|
||||
mQuotedHTML.setText(mQuotedHtmlContent.getQuotedContent(), "text/html");
|
||||
}
|
||||
}
|
||||
mDraftId = savedInstanceState.getLong(STATE_KEY_DRAFT_ID);
|
||||
@ -1775,12 +1787,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
addAttachment(data.getData());
|
||||
mDraftNeedsSaving = true;
|
||||
break;
|
||||
case ACTIVITY_CHOOSE_IDENTITY:
|
||||
onIdentityChosen(data);
|
||||
break;
|
||||
case ACTIVITY_CHOOSE_ACCOUNT:
|
||||
onAccountChosen(data);
|
||||
break;
|
||||
case CONTACT_PICKER_TO:
|
||||
case CONTACT_PICKER_CC:
|
||||
case CONTACT_PICKER_BCC:
|
||||
@ -1810,15 +1816,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
startActivityForResult(mContacts.contactPickerIntent(), resultId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void onAccountChosen(final Intent intent) {
|
||||
final Bundle extras = intent.getExtras();
|
||||
final String uuid = extras.getString(ChooseAccount.EXTRA_ACCOUNT);
|
||||
final Identity identity = (Identity) extras.getSerializable(ChooseAccount.EXTRA_IDENTITY);
|
||||
|
||||
final Account account = Preferences.getPreferences(this).getAccount(uuid);
|
||||
|
||||
private void onAccountChosen(Account account, Identity identity) {
|
||||
if (!mAccount.equals(account)) {
|
||||
if (K9.DEBUG) {
|
||||
Log.v(K9.LOG_TAG, "Switching account from " + mAccount + " to " + account);
|
||||
@ -1862,11 +1860,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
switchToIdentity(identity);
|
||||
}
|
||||
|
||||
private void onIdentityChosen(Intent intent) {
|
||||
Bundle bundle = intent.getExtras();
|
||||
switchToIdentity((Identity) bundle.getSerializable(ChooseIdentity.EXTRA_IDENTITY));
|
||||
}
|
||||
|
||||
private void switchToIdentity(Identity identity) {
|
||||
mIdentity = identity;
|
||||
mIdentityChanged = true;
|
||||
@ -1876,10 +1869,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
}
|
||||
|
||||
private void updateFrom() {
|
||||
if (mIdentityChanged) {
|
||||
mFromView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
mFromView.setText(getString(R.string.message_view_from_format, mIdentity.getName(), mIdentity.getEmail()));
|
||||
mChooseIdentityButton.setText(mIdentity.getEmail());
|
||||
}
|
||||
|
||||
private void updateSignature() {
|
||||
@ -1922,6 +1912,9 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
MessagingController.getInstance(getApplication()).loadMessageForView(account, folderName, sourceMessageUid, null);
|
||||
}
|
||||
break;
|
||||
case R.id.identity:
|
||||
showDialog(DIALOG_CHOOSE_IDENTITY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1988,9 +1981,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
case R.id.add_attachment_video:
|
||||
onAddAttachment2("video/*");
|
||||
break;
|
||||
case R.id.choose_identity:
|
||||
onChooseIdentity();
|
||||
break;
|
||||
case R.id.read_receipt:
|
||||
onReadReceipt();
|
||||
default:
|
||||
@ -1999,25 +1989,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
return true;
|
||||
}
|
||||
|
||||
private void onChooseIdentity() {
|
||||
// keep things simple: trigger account choice only if there are more
|
||||
// than 1 account
|
||||
mIgnoreOnPause = true;
|
||||
if (Preferences.getPreferences(this).getAvailableAccounts().size() > 1) {
|
||||
final Intent intent = new Intent(this, ChooseAccount.class);
|
||||
intent.putExtra(ChooseAccount.EXTRA_ACCOUNT, mAccount.getUuid());
|
||||
intent.putExtra(ChooseAccount.EXTRA_IDENTITY, mIdentity);
|
||||
startActivityForResult(intent, ACTIVITY_CHOOSE_ACCOUNT);
|
||||
} else if (mAccount.getIdentities().size() > 1) {
|
||||
Intent intent = new Intent(this, ChooseIdentity.class);
|
||||
intent.putExtra(ChooseIdentity.EXTRA_ACCOUNT, mAccount.getUuid());
|
||||
startActivityForResult(intent, ACTIVITY_CHOOSE_IDENTITY);
|
||||
} else {
|
||||
Toast.makeText(this, getString(R.string.no_identities),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
@ -2147,6 +2118,21 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
}
|
||||
})
|
||||
.create();
|
||||
case DIALOG_CHOOSE_IDENTITY:
|
||||
Context context = new ContextWrapper(this);
|
||||
context.setTheme(K9.getK9ThemeResourceId(K9.THEME_LIGHT));
|
||||
Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(R.string.send_as);
|
||||
final IdentityAdapter adapter = new IdentityAdapter(context, getLayoutInflater());
|
||||
builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
IdentityContainer container = (IdentityContainer) adapter.getItem(which);
|
||||
onAccountChosen(container.account, container.identity);
|
||||
}
|
||||
});
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
return super.onCreateDialog(id);
|
||||
}
|
||||
@ -2288,10 +2274,17 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
}
|
||||
|
||||
if (ACTION_REPLY_ALL.equals(action)) {
|
||||
for (Address address : message.getRecipients(RecipientType.TO)) {
|
||||
if (message.getReplyTo().length > 0) {
|
||||
for (Address address : message.getFrom()) {
|
||||
if (!mAccount.isAnIdentity(address)) {
|
||||
addAddress(mToView, address);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Address address : message.getRecipients(RecipientType.TO)) {
|
||||
if (!mAccount.isAnIdentity(address) && !Utility.arrayContains(replyToAddresses, address)) {
|
||||
addAddress(mToView, address);
|
||||
}
|
||||
|
||||
}
|
||||
if (message.getRecipients(RecipientType.CC).length > 0) {
|
||||
@ -2394,7 +2387,15 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
if (k9identity.containsKey(IdentityField.ORIGINAL_MESSAGE)) {
|
||||
mMessageReference = null;
|
||||
try {
|
||||
mMessageReference = new MessageReference(k9identity.get(IdentityField.ORIGINAL_MESSAGE));
|
||||
String originalMessage = k9identity.get(IdentityField.ORIGINAL_MESSAGE);
|
||||
MessageReference messageReference = new MessageReference(originalMessage);
|
||||
|
||||
// Check if this is a valid account in our database
|
||||
Preferences prefs = Preferences.getPreferences(getApplicationContext());
|
||||
Account account = prefs.getAccount(messageReference.accountUuid);
|
||||
if (account != null) {
|
||||
mMessageReference = messageReference;
|
||||
}
|
||||
} catch (MessagingException e) {
|
||||
Log.e(K9.LOG_TAG, "Could not decode message reference in identity.", e);
|
||||
}
|
||||
@ -2419,19 +2420,19 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
updateFrom();
|
||||
|
||||
Integer bodyLength = k9identity.get(IdentityField.LENGTH) != null
|
||||
? Integer.parseInt(k9identity.get(IdentityField.LENGTH))
|
||||
? Integer.valueOf(k9identity.get(IdentityField.LENGTH))
|
||||
: 0;
|
||||
Integer bodyOffset = k9identity.get(IdentityField.OFFSET) != null
|
||||
? Integer.parseInt(k9identity.get(IdentityField.OFFSET))
|
||||
? Integer.valueOf(k9identity.get(IdentityField.OFFSET))
|
||||
: 0;
|
||||
Integer bodyFooterOffset = k9identity.get(IdentityField.FOOTER_OFFSET) != null
|
||||
? Integer.parseInt(k9identity.get(IdentityField.FOOTER_OFFSET))
|
||||
? Integer.valueOf(k9identity.get(IdentityField.FOOTER_OFFSET))
|
||||
: null;
|
||||
Integer bodyPlainLength = k9identity.get(IdentityField.PLAIN_LENGTH) != null
|
||||
? Integer.parseInt(k9identity.get(IdentityField.PLAIN_LENGTH))
|
||||
? Integer.valueOf(k9identity.get(IdentityField.PLAIN_LENGTH))
|
||||
: null;
|
||||
Integer bodyPlainOffset = k9identity.get(IdentityField.PLAIN_OFFSET) != null
|
||||
? Integer.parseInt(k9identity.get(IdentityField.PLAIN_OFFSET))
|
||||
? Integer.valueOf(k9identity.get(IdentityField.PLAIN_OFFSET))
|
||||
: null;
|
||||
mQuoteStyle = k9identity.get(IdentityField.QUOTE_STYLE) != null
|
||||
? QuoteStyle.valueOf(k9identity.get(IdentityField.QUOTE_STYLE))
|
||||
@ -2481,7 +2482,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
} else {
|
||||
mQuotedHtmlContent.setFooterInsertionPoint(bodyOffset);
|
||||
}
|
||||
mQuotedHTML.loadDataWithBaseURL("http://", mQuotedHtmlContent.getQuotedContent(), "text/html", "utf-8", null);
|
||||
mQuotedHTML.setText(mQuotedHtmlContent.getQuotedContent(), "text/html");
|
||||
}
|
||||
}
|
||||
if (bodyPlainOffset != null && bodyPlainLength != null) {
|
||||
@ -2664,7 +2665,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
// Add the HTML reply header to the top of the content.
|
||||
mQuotedHtmlContent = quoteOriginalHtmlMessage(mSourceMessage, content, mQuoteStyle);
|
||||
// Load the message with the reply header.
|
||||
mQuotedHTML.loadDataWithBaseURL("http://", mQuotedHtmlContent.getQuotedContent(), "text/html", "utf-8", null);
|
||||
mQuotedHTML.setText(mQuotedHtmlContent.getQuotedContent(), "text/html");
|
||||
mQuotedText.setText(quoteOriginalTextMessage(mSourceMessage,
|
||||
getBodyTextFromMessage(mSourceMessage, MessageFormat.TEXT), mQuoteStyle));
|
||||
|
||||
@ -3176,4 +3177,139 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
|
||||
|
||||
return insertable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to store an {@link Identity} instance together with the {@link Account} it belongs to.
|
||||
*
|
||||
* @see IdentityAdapter
|
||||
*/
|
||||
static class IdentityContainer {
|
||||
public final Identity identity;
|
||||
public final Account account;
|
||||
|
||||
IdentityContainer(Identity identity, Account account) {
|
||||
this.identity = identity;
|
||||
this.account = account;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapter for the <em>Choose identity</em> list view.
|
||||
*
|
||||
* <p>
|
||||
* Account names are displayed as section headers, identities as selectable list items.
|
||||
* </p>
|
||||
*/
|
||||
static class IdentityAdapter extends BaseAdapter {
|
||||
private LayoutInflater mLayoutInflater;
|
||||
private List<Object> mItems;
|
||||
private FontSizes mFontSizes;
|
||||
|
||||
public IdentityAdapter(Context context, LayoutInflater layoutInflater) {
|
||||
mLayoutInflater = layoutInflater;
|
||||
mFontSizes = K9.getFontSizes();
|
||||
|
||||
List<Object> items = new ArrayList<Object>();
|
||||
Preferences prefs = Preferences.getPreferences(context.getApplicationContext());
|
||||
Account[] accounts = prefs.getAvailableAccounts().toArray(EMPTY_ACCOUNT_ARRAY);
|
||||
for (Account account : accounts) {
|
||||
items.add(account);
|
||||
List<Identity> identities = account.getIdentities();
|
||||
for (Identity identity : identities) {
|
||||
items.add(new IdentityContainer(identity, account));
|
||||
}
|
||||
}
|
||||
mItems = items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mItems.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewTypeCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
return (mItems.get(position) instanceof Account) ? 0 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(int position) {
|
||||
return (mItems.get(position) instanceof IdentityContainer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return mItems.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
Object item = mItems.get(position);
|
||||
|
||||
View view = null;
|
||||
if (item instanceof Account) {
|
||||
if (convertView != null && convertView.getTag() instanceof AccountHolder) {
|
||||
view = convertView;
|
||||
} else {
|
||||
view = mLayoutInflater.inflate(R.layout.choose_account_item, parent, false);
|
||||
AccountHolder holder = new AccountHolder();
|
||||
holder.name = (TextView) view.findViewById(R.id.name);
|
||||
holder.chip = view.findViewById(R.id.chip);
|
||||
view.setTag(holder);
|
||||
}
|
||||
|
||||
Account account = (Account) item;
|
||||
AccountHolder holder = (AccountHolder) view.getTag();
|
||||
holder.name.setText(account.getDescription());
|
||||
holder.chip.setBackgroundColor(account.getChipColor());
|
||||
} else if (item instanceof IdentityContainer) {
|
||||
if (convertView != null && convertView.getTag() instanceof IdentityHolder) {
|
||||
view = convertView;
|
||||
} else {
|
||||
view = mLayoutInflater.inflate(R.layout.choose_identity_item, parent, false);
|
||||
IdentityHolder holder = new IdentityHolder();
|
||||
holder.name = (TextView) view.findViewById(R.id.name);
|
||||
holder.description = (TextView) view.findViewById(R.id.description);
|
||||
view.setTag(holder);
|
||||
}
|
||||
|
||||
IdentityContainer identityContainer = (IdentityContainer) item;
|
||||
Identity identity = identityContainer.identity;
|
||||
IdentityHolder holder = (IdentityHolder) view.getTag();
|
||||
holder.name.setText(identity.getDescription());
|
||||
holder.description.setText(getIdentityDescription(identity));
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
static class AccountHolder {
|
||||
public TextView name;
|
||||
public View chip;
|
||||
}
|
||||
|
||||
static class IdentityHolder {
|
||||
public TextView name;
|
||||
public TextView description;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getIdentityDescription(Identity identity) {
|
||||
return String.format("%s <%s>", identity.getName(), identity.getEmail());
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import com.fsck.k9.mail.store.LocalStore.LocalMessage;
|
||||
public class MessageInfoHolder {
|
||||
public String date;
|
||||
public Date compareDate;
|
||||
public Date compareArrival;
|
||||
public String compareSubject;
|
||||
public CharSequence sender;
|
||||
public String senderAddress;
|
||||
|
@ -185,6 +185,15 @@ public class MessageList
|
||||
|
||||
}
|
||||
|
||||
public static class ArrivalComparator implements Comparator<MessageInfoHolder> {
|
||||
|
||||
@Override
|
||||
public int compare(MessageInfoHolder object1, MessageInfoHolder object2) {
|
||||
return object1.compareArrival.compareTo(object2.compareArrival);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class SubjectComparator implements Comparator<MessageInfoHolder> {
|
||||
|
||||
@Override
|
||||
@ -234,6 +243,7 @@ public class MessageList
|
||||
final Map<SORT_TYPE, Comparator<MessageInfoHolder>> map = new EnumMap<SORT_TYPE, Comparator<MessageInfoHolder>>(SORT_TYPE.class);
|
||||
map.put(SORT_TYPE.SORT_ATTACHMENT, new AttachmentComparator());
|
||||
map.put(SORT_TYPE.SORT_DATE, new DateComparator());
|
||||
map.put(SORT_TYPE.SORT_ARRIVAL, new ArrivalComparator());
|
||||
map.put(SORT_TYPE.SORT_FLAGGED, new FlaggedComparator());
|
||||
map.put(SORT_TYPE.SORT_SENDER, new SenderComparator());
|
||||
map.put(SORT_TYPE.SORT_SUBJECT, new SubjectComparator());
|
||||
@ -460,7 +470,7 @@ public class MessageList
|
||||
|
||||
{
|
||||
// add the date comparator if not already specified
|
||||
if (sortType != SORT_TYPE.SORT_DATE) {
|
||||
if (sortType != SORT_TYPE.SORT_DATE && sortType != SORT_TYPE.SORT_ARRIVAL) {
|
||||
final Comparator<MessageInfoHolder> comparator = SORT_COMPARATORS.get(SORT_TYPE.SORT_DATE);
|
||||
if (sortDateAscending) {
|
||||
chain.add(comparator);
|
||||
@ -1443,6 +1453,10 @@ public class MessageList
|
||||
changeSort(SORT_TYPE.SORT_DATE);
|
||||
return true;
|
||||
}
|
||||
case R.id.set_sort_arrival: {
|
||||
changeSort(SORT_TYPE.SORT_ARRIVAL);
|
||||
return true;
|
||||
}
|
||||
case R.id.set_sort_subject: {
|
||||
changeSort(SORT_TYPE.SORT_SUBJECT);
|
||||
return true;
|
||||
|
@ -289,7 +289,7 @@ public class MessageView extends K9Activity implements OnClickListener {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle, false);
|
||||
super.onCreate(icicle);
|
||||
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
setContentView(R.layout.message_view);
|
||||
@ -758,17 +758,16 @@ public class MessageView extends K9Activity implements OnClickListener {
|
||||
mPrevious.requestFocus();
|
||||
}
|
||||
|
||||
private void onMarkAsUnread() {
|
||||
private void onToggleRead() {
|
||||
if (mMessage != null) {
|
||||
mController.setFlag(mAccount, mMessage.getFolder().getName(),
|
||||
new Message[] { mMessage }, Flag.SEEN, false);
|
||||
new Message[] { mMessage }, Flag.SEEN, !mMessage.isSet(Flag.SEEN));
|
||||
mMessageView.setHeaders(mMessage, mAccount);
|
||||
String subject = mMessage.getSubject();
|
||||
setTitle(subject);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void onDownloadRemainder() {
|
||||
if (mMessage.isSet(Flag.X_DOWNLOADED_FULL)) {
|
||||
return;
|
||||
@ -835,7 +834,7 @@ public class MessageView extends K9Activity implements OnClickListener {
|
||||
onSendAlternate();
|
||||
break;
|
||||
case R.id.mark_as_unread:
|
||||
onMarkAsUnread();
|
||||
onToggleRead();
|
||||
break;
|
||||
case R.id.flag:
|
||||
onFlag();
|
||||
@ -946,6 +945,12 @@ public class MessageView extends K9Activity implements OnClickListener {
|
||||
additionalHeadersItem.setTitle(mMessageView.additionalHeadersVisible() ?
|
||||
R.string.hide_full_header_action : R.string.show_full_header_action);
|
||||
}
|
||||
|
||||
if (mMessage != null) {
|
||||
int actionTitle = mMessage.isSet(Flag.SEEN) ?
|
||||
R.string.mark_as_unread_action : R.string.mark_as_read_action;
|
||||
menu.findItem(R.id.mark_as_unread).setTitle(actionTitle);
|
||||
}
|
||||
}
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
@ -977,7 +982,8 @@ public class MessageView extends K9Activity implements OnClickListener {
|
||||
public void run() {
|
||||
if (!clonedMessage.isSet(Flag.X_DOWNLOADED_FULL) &&
|
||||
!clonedMessage.isSet(Flag.X_DOWNLOADED_PARTIAL)) {
|
||||
mMessageView.loadBodyFromUrl("file:///android_asset/downloading.html");
|
||||
String text = getString(R.string.message_view_downloading);
|
||||
mMessageView.showStatusMessage(text);
|
||||
}
|
||||
mMessageView.setHeaders(clonedMessage, account);
|
||||
mMessageView.setOnFlagListener(new OnClickListener() {
|
||||
@ -1030,7 +1036,7 @@ public class MessageView extends K9Activity implements OnClickListener {
|
||||
}
|
||||
if ((MessageView.this.mMessage == null) ||
|
||||
!MessageView.this.mMessage.isSet(Flag.X_DOWNLOADED_PARTIAL)) {
|
||||
mMessageView.loadBodyFromUrl("file:///android_asset/empty.html");
|
||||
mMessageView.showStatusMessage(getString(R.string.webview_empty_message));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -48,6 +48,7 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
private static final String PREFERENCE_SCREEN_PUSH_ADVANCED = "push_advanced";
|
||||
|
||||
private static final String PREFERENCE_DESCRIPTION = "account_description";
|
||||
private static final String PREFERENCE_MARK_MESSAGE_AS_READ_ON_VIEW = "mark_message_as_read_on_view";
|
||||
private static final String PREFERENCE_COMPOSITION = "composition";
|
||||
private static final String PREFERENCE_MANAGE_IDENTITIES = "manage_identities";
|
||||
private static final String PREFERENCE_FREQUENCY = "account_check_frequency";
|
||||
@ -94,9 +95,7 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
private static final String PREFERENCE_CRYPTO_APP = "crypto_app";
|
||||
private static final String PREFERENCE_CRYPTO_AUTO_SIGNATURE = "crypto_auto_signature";
|
||||
private static final String PREFERENCE_CRYPTO_AUTO_ENCRYPT = "crypto_auto_encrypt";
|
||||
|
||||
private static final String PREFERENCE_LOCAL_STORAGE_PROVIDER = "local_storage_provider";
|
||||
|
||||
private static final String PREFERENCE_CATEGORY_FOLDERS = "folders";
|
||||
private static final String PREFERENCE_ARCHIVE_FOLDER = "archive_folder";
|
||||
private static final String PREFERENCE_DRAFTS_FOLDER = "drafts_folder";
|
||||
@ -114,6 +113,7 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
private PreferenceScreen mComposingScreen;
|
||||
|
||||
private EditTextPreference mAccountDescription;
|
||||
private CheckBoxPreference mMarkMessageAsReadOnView;
|
||||
private ListPreference mCheckFrequency;
|
||||
private ListPreference mDisplayCount;
|
||||
private ListPreference mMessageAge;
|
||||
@ -157,10 +157,7 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
private ListPreference mCryptoApp;
|
||||
private CheckBoxPreference mCryptoAutoSignature;
|
||||
private CheckBoxPreference mCryptoAutoEncrypt;
|
||||
|
||||
private ListPreference mLocalStorageProvider;
|
||||
|
||||
|
||||
private ListPreference mArchiveFolder;
|
||||
private ListPreference mDraftsFolder;
|
||||
private ListPreference mSentFolder;
|
||||
@ -204,6 +201,9 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
}
|
||||
});
|
||||
|
||||
mMarkMessageAsReadOnView = (CheckBoxPreference) findPreference(PREFERENCE_MARK_MESSAGE_AS_READ_ON_VIEW);
|
||||
mMarkMessageAsReadOnView.setChecked(mAccount.isMarkMessageAsReadOnView());
|
||||
|
||||
mMessageFormat = (ListPreference) findPreference(PREFERENCE_MESSAGE_FORMAT);
|
||||
mMessageFormat.setValue(mAccount.getMessageFormat().name());
|
||||
mMessageFormat.setSummary(mMessageFormat.getEntry());
|
||||
@ -672,6 +672,7 @@ public class AccountSettings extends K9PreferenceActivity {
|
||||
}
|
||||
|
||||
mAccount.setDescription(mAccountDescription.getText());
|
||||
mAccount.setMarkMessageAsReadOnView(mMarkMessageAsReadOnView.isChecked());
|
||||
mAccount.setNotifyNewMail(mAccountNotify.isChecked());
|
||||
mAccount.setNotifySelfNewMail(mAccountNotifySelf.isChecked());
|
||||
mAccount.setShowOngoing(mAccountNotifySync.isChecked());
|
||||
|
@ -148,7 +148,7 @@ public class Prefs extends K9PreferenceActivity {
|
||||
entryVector.toArray(EMPTY_CHAR_SEQUENCE_ARRAY),
|
||||
entryValueVector.toArray(EMPTY_CHAR_SEQUENCE_ARRAY));
|
||||
|
||||
final String theme = (K9.getK9Theme() == android.R.style.Theme) ? "dark" : "light";
|
||||
final String theme = (K9.getK9Theme() == K9.THEME_DARK) ? "dark" : "light";
|
||||
mTheme = setupListPreference(PREFERENCE_THEME, theme);
|
||||
|
||||
findPreference(PREFERENCE_FONT_SIZE).setOnPreferenceClickListener(
|
||||
@ -348,7 +348,7 @@ public class Prefs extends K9PreferenceActivity {
|
||||
SharedPreferences preferences = Preferences.getPreferences(this).getPreferences();
|
||||
|
||||
K9.setK9Language(mLanguage.getValue());
|
||||
K9.setK9Theme(mTheme.getValue().equals("dark") ? android.R.style.Theme : android.R.style.Theme_Light);
|
||||
K9.setK9Theme(mTheme.getValue().equals("dark") ? K9.THEME_DARK : K9.THEME_LIGHT);
|
||||
K9.setAnimations(mAnimations.isChecked());
|
||||
K9.setGesturesEnabled(mGestures.isChecked());
|
||||
K9.setCompactLayouts(compactLayouts.isChecked());
|
||||
|
@ -148,6 +148,7 @@ public class MessagingController implements Runnable {
|
||||
|
||||
public enum SORT_TYPE {
|
||||
SORT_DATE(R.string.sort_earliest_first, R.string.sort_latest_first, false),
|
||||
SORT_ARRIVAL(R.string.sort_earliest_first, R.string.sort_latest_first, false),
|
||||
SORT_SUBJECT(R.string.sort_subject_alpha, R.string.sort_subject_re_alpha, true),
|
||||
SORT_SENDER(R.string.sort_sender_alpha, R.string.sort_sender_re_alpha, true),
|
||||
SORT_UNREAD(R.string.sort_unread_first, R.string.sort_unread_last, true),
|
||||
@ -450,7 +451,7 @@ public class MessagingController implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private void doRefreshRemote(final Account account, MessagingListener listener) {
|
||||
private void doRefreshRemote(final Account account, final MessagingListener listener) {
|
||||
// It is possible that multiple threads may try to refresh the same account at the same time.
|
||||
// Currently, this can happen immediately after the account is setup initially, and is
|
||||
// generally a bad thing. Let's use a hack to prevent this from happening.
|
||||
@ -459,14 +460,14 @@ public class MessagingController implements Runnable {
|
||||
put("doRefreshRemote", listener, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
doRefreshRemoteSynchronous(account);
|
||||
doRefreshRemoteSynchronous(account, listener);
|
||||
mCurrentlyRefreshing.remove(account);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void doRefreshRemoteSynchronous(final Account account) {
|
||||
private void doRefreshRemoteSynchronous(final Account account, final MessagingListener listener) {
|
||||
List<? extends Folder> localFolders = null;
|
||||
try {
|
||||
Store remoteStore = account.getRemoteStore();
|
||||
@ -481,14 +482,14 @@ public class MessagingController implements Runnable {
|
||||
localFolders = localStore.getPersonalNamespaces(false);
|
||||
Folder[] folderArray = localFolders.toArray(EMPTY_FOLDER_ARRAY);
|
||||
|
||||
for (MessagingListener l : getListeners()) {
|
||||
for (MessagingListener l : getListeners(listener)) {
|
||||
l.listFolders(account, folderArray);
|
||||
}
|
||||
for (MessagingListener l : getListeners()) {
|
||||
for (MessagingListener l : getListeners(listener)) {
|
||||
l.listFoldersFinished(account);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
for (MessagingListener l : getListeners()) {
|
||||
for (MessagingListener l : getListeners(listener)) {
|
||||
l.listFoldersFailed(account, "");
|
||||
}
|
||||
addErrorMessage(account, null, e);
|
||||
@ -645,7 +646,7 @@ public class MessagingController implements Runnable {
|
||||
Log.i(K9.LOG_TAG, "searchLocalMessages ("
|
||||
+ "accountUuids=" + Utility.combine(accountUuids, ',')
|
||||
+ ", folderNames = " + Utility.combine(folderNames, ',')
|
||||
+ ", messages.size() = " + (messages != null ? messages.length : null)
|
||||
+ ", messages.size() = " + (messages != null ? messages.length : -1)
|
||||
+ ", query = " + query
|
||||
+ ", integrate = " + integrate
|
||||
+ ", requiredFlags = " + Utility.combine(requiredFlags, ',')
|
||||
@ -2238,7 +2239,7 @@ public class MessagingController implements Runnable {
|
||||
PendingCommand command = new PendingCommand();
|
||||
command.command = PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW;
|
||||
|
||||
int length = 3 + uids.length;
|
||||
int length = 4 + uids.length;
|
||||
command.arguments = new String[length];
|
||||
command.arguments[0] = srcFolder;
|
||||
command.arguments[1] = destFolder;
|
||||
@ -2418,6 +2419,7 @@ public class MessagingController implements Runnable {
|
||||
String newUid = remoteUidMap.get(remoteSrcUid);
|
||||
|
||||
Message localDestMessage = localDestFolder.getMessage(localDestUid);
|
||||
if (localDestMessage != null) {
|
||||
localDestMessage.setUid(newUid);
|
||||
localDestFolder.changeUid((LocalMessage)localDestMessage);
|
||||
for (MessagingListener l : getListeners()) {
|
||||
@ -2425,6 +2427,7 @@ public class MessagingController implements Runnable {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
closeFolder(remoteSrcFolder);
|
||||
closeFolder(remoteDestFolder);
|
||||
@ -2997,7 +3000,7 @@ public class MessagingController implements Runnable {
|
||||
|| message.getId() == 0) {
|
||||
throw new IllegalArgumentException("Message not found: folder=" + folder + ", uid=" + uid);
|
||||
}
|
||||
if (!message.isSet(Flag.SEEN)) {
|
||||
if (account.isMarkMessageAsReadOnView() && !message.isSet(Flag.SEEN)) {
|
||||
message.setFlag(Flag.SEEN, true);
|
||||
setFlag(new Message[] { message }, Flag.SEEN, true);
|
||||
}
|
||||
@ -4333,9 +4336,13 @@ public class MessagingController implements Runnable {
|
||||
}
|
||||
|
||||
NotificationSetting n = account.getNotificationSetting();
|
||||
|
||||
configureNotification(notif, (n.shouldRing() ? n.getRingtone() : null), (n.shouldVibrate() ? n.getVibration() : null),
|
||||
(n.isLed() ? n.getLedColor() : null), K9.NOTIFICATION_LED_BLINK_SLOW, ringAndVibrate);
|
||||
configureNotification(
|
||||
notif,
|
||||
(n.shouldRing()) ? n.getRingtone() : null,
|
||||
(n.shouldVibrate()) ? n.getVibration() : null,
|
||||
(n.isLed()) ? Integer.valueOf(n.getLedColor()) : null,
|
||||
K9.NOTIFICATION_LED_BLINK_SLOW,
|
||||
ringAndVibrate);
|
||||
|
||||
notifMgr.notify(account.getAccountNumber(), notif);
|
||||
}
|
||||
|
63
src/com/fsck/k9/helper/ClipboardManager.java
Normal file
63
src/com/fsck/k9/helper/ClipboardManager.java
Normal file
@ -0,0 +1,63 @@
|
||||
package com.fsck.k9.helper;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
|
||||
|
||||
/**
|
||||
* Helper class to access the system clipboard
|
||||
*
|
||||
* @see ClipboardManagerApi1
|
||||
* @see ClipboardManagerApi11
|
||||
*/
|
||||
public abstract class ClipboardManager {
|
||||
/**
|
||||
* Instance of the API-specific class that interfaces with the clipboard API.
|
||||
*/
|
||||
private static ClipboardManager sInstance = null;
|
||||
|
||||
/**
|
||||
* Get API-specific instance of the {@code ClipboardManager} class
|
||||
*
|
||||
* @param context
|
||||
* A {@link Context} instance.
|
||||
*
|
||||
* @return Appropriate {@link ClipboardManager} instance for this device.
|
||||
*/
|
||||
public static ClipboardManager getInstance(Context context) {
|
||||
Context appContext = context.getApplicationContext();
|
||||
|
||||
if (sInstance == null) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
||||
sInstance = new ClipboardManagerApi1(appContext);
|
||||
} else {
|
||||
sInstance = new ClipboardManagerApi11(appContext);
|
||||
}
|
||||
}
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
|
||||
protected Context mContext;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context
|
||||
* A {@link Context} instance.
|
||||
*/
|
||||
protected ClipboardManager(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a text string to the system clipboard
|
||||
*
|
||||
* @param label
|
||||
* User-visible label for the content.
|
||||
* @param text
|
||||
* The actual text to be copied to the clipboard.
|
||||
*/
|
||||
public abstract void setText(String label, String text);
|
||||
}
|
22
src/com/fsck/k9/helper/ClipboardManagerApi1.java
Normal file
22
src/com/fsck/k9/helper/ClipboardManagerApi1.java
Normal file
@ -0,0 +1,22 @@
|
||||
package com.fsck.k9.helper;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.ClipboardManager;
|
||||
|
||||
/**
|
||||
* Access the system clipboard using the now deprecated {@link ClipboardManager}
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ClipboardManagerApi1 extends com.fsck.k9.helper.ClipboardManager {
|
||||
|
||||
public ClipboardManagerApi1(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setText(String label, String text) {
|
||||
ClipboardManager clipboardManager =
|
||||
(ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
clipboardManager.setText(text);
|
||||
}
|
||||
}
|
23
src/com/fsck/k9/helper/ClipboardManagerApi11.java
Normal file
23
src/com/fsck/k9/helper/ClipboardManagerApi11.java
Normal file
@ -0,0 +1,23 @@
|
||||
package com.fsck.k9.helper;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.Context;
|
||||
import android.content.ClipboardManager;
|
||||
|
||||
/**
|
||||
* Access the system clipboard using the new {@link ClipboardManager} introduced with API 11
|
||||
*/
|
||||
public class ClipboardManagerApi11 extends com.fsck.k9.helper.ClipboardManager {
|
||||
|
||||
public ClipboardManagerApi11(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setText(String label, String text) {
|
||||
ClipboardManager clipboardManager =
|
||||
(ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText(label, text);
|
||||
clipboardManager.setPrimaryClip(clip);
|
||||
}
|
||||
}
|
@ -104,6 +104,14 @@ public abstract class Contacts {
|
||||
*/
|
||||
public abstract void createContact(Address email);
|
||||
|
||||
/**
|
||||
* Start the activity to add a phone number to an existing contact or add a new one.
|
||||
*
|
||||
* @param phoneNumber
|
||||
* The phone number to add to a contact, or to use when creating a new contact.
|
||||
*/
|
||||
public abstract void addPhoneContact(String phoneNumber);
|
||||
|
||||
/**
|
||||
* Check whether the provided email address belongs to one of the contacts.
|
||||
*
|
||||
|
@ -9,6 +9,8 @@ import android.provider.ContactsContract;
|
||||
import android.provider.ContactsContract.Contacts;
|
||||
import android.provider.ContactsContract.Intents;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Email;
|
||||
import android.provider.ContactsContract.Intents.Insert;
|
||||
|
||||
import com.fsck.k9.mail.Address;
|
||||
import com.fsck.k9.K9;
|
||||
|
||||
@ -85,6 +87,15 @@ public class ContactsSdk5 extends com.fsck.k9.helper.Contacts {
|
||||
mContext.startActivity(contactIntent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPhoneContact(final String phoneNumber) {
|
||||
Intent addIntent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
|
||||
addIntent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
|
||||
addIntent.putExtra(Insert.PHONE, Uri.decode(phoneNumber));
|
||||
addIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mContext.startActivity(addIntent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInContacts(final String emailAddress) {
|
||||
boolean result = false;
|
||||
|
@ -49,6 +49,7 @@ public class MessageHelper {
|
||||
try {
|
||||
LocalMessage message = (LocalMessage) m;
|
||||
target.message = message;
|
||||
target.compareArrival = message.getInternalDate();
|
||||
target.compareDate = message.getSentDate();
|
||||
if (target.compareDate == null) {
|
||||
target.compareDate = message.getInternalDate();
|
||||
|
@ -19,6 +19,29 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Utility {
|
||||
/**
|
||||
* Regular expression that represents characters we won't allow in file names.
|
||||
*
|
||||
* <p>
|
||||
* Allowed are:
|
||||
* <ul>
|
||||
* <li>word characters (letters, digits, and underscores): {@code \w}</li>
|
||||
* <li>spaces: {@code " "}</li>
|
||||
* <li>special characters: {@code !}, {@code #}, {@code $}, {@code %}, {@code &}, {@code '},
|
||||
* {@code (}, {@code )}, {@code -}, {@code @}, {@code ^}, {@code `}, <code>{</code>,
|
||||
* <code>}</code>, {@code ~}, {@code .}, {@code ,}</li>
|
||||
* </ul></p>
|
||||
*
|
||||
* @see #sanitizeFilename(String)
|
||||
*/
|
||||
private static final String INVALID_CHARACTERS = "[^\\w !#$%&'()\\-@\\^`{}~.,]+";
|
||||
|
||||
/**
|
||||
* Invalid characters in a file name are replaced by this character.
|
||||
*
|
||||
* @see #sanitizeFilename(String)
|
||||
*/
|
||||
private static final String REPLACEMENT_CHARACTER = "_";
|
||||
|
||||
// \u00A0 (non-breaking space) happens to be used by French MUA
|
||||
|
||||
@ -605,4 +628,16 @@ public class Utility {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace characters we don't allow in file names with a replacement character.
|
||||
*
|
||||
* @param filename
|
||||
* The original file name.
|
||||
*
|
||||
* @return The sanitized file name containing only allowed characters.
|
||||
*/
|
||||
public static String sanitizeFilename(String filename) {
|
||||
return filename.replaceAll(INVALID_CHARACTERS, REPLACEMENT_CHARACTER);
|
||||
}
|
||||
}
|
||||
|
@ -953,19 +953,23 @@ public class MimeUtility {
|
||||
}
|
||||
header = header.replaceAll("\r|\n", "");
|
||||
String[] parts = header.split(";");
|
||||
if (name == null) {
|
||||
if (name == null && parts.length > 0) {
|
||||
return parts[0];
|
||||
}
|
||||
for (String part : parts) {
|
||||
if (part.trim().toLowerCase(Locale.US).startsWith(name.toLowerCase(Locale.US))) {
|
||||
String parameter = part.split("=", 2)[1].trim();
|
||||
if (parameter.startsWith("\"") && parameter.endsWith("\"")) {
|
||||
return parameter.substring(1, parameter.length() - 1);
|
||||
String[] partParts = part.split("=", 2);
|
||||
if (partParts.length == 2) {
|
||||
String parameter = partParts[1].trim();
|
||||
int len = parameter.length();
|
||||
if (len >= 2 && parameter.startsWith("\"") && parameter.endsWith("\"")) {
|
||||
return parameter.substring(1, len - 1);
|
||||
} else {
|
||||
return parameter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -2178,8 +2182,11 @@ public class MimeUtility {
|
||||
}
|
||||
|
||||
private static String getJisVariantFromAddress(String address) {
|
||||
if (address == null)
|
||||
return null;
|
||||
if (isInDomain(address, "docomo.ne.jp") || isInDomain(address, "dwmail.jp") ||
|
||||
isInDomain(address, "pdx.ne.jp") || isInDomain(address, "willcom.com"))
|
||||
isInDomain(address, "pdx.ne.jp") || isInDomain(address, "willcom.com") ||
|
||||
isInDomain(address, "emnet.ne.jp") || isInDomain(address, "emobile.ne.jp"))
|
||||
return "docomo";
|
||||
else if (isInDomain(address, "softbank.ne.jp") || isInDomain(address, "vodafone.ne.jp") ||
|
||||
isInDomain(address, "disney.ne.jp") || isInDomain(address, "vertuclub.ne.jp"))
|
||||
@ -3256,4 +3263,80 @@ public class MimeUtility {
|
||||
|
||||
return charset;
|
||||
}
|
||||
|
||||
public static ViewableContainer extractPartsFromDraft(Message message)
|
||||
throws MessagingException {
|
||||
|
||||
Body body = message.getBody();
|
||||
if (message.isMimeType("multipart/mixed") && body instanceof MimeMultipart) {
|
||||
MimeMultipart multipart = (MimeMultipart) body;
|
||||
|
||||
ViewableContainer container;
|
||||
int count = multipart.getCount();
|
||||
if (count >= 1) {
|
||||
// The first part is either a text/plain or a multipart/alternative
|
||||
BodyPart firstPart = multipart.getBodyPart(0);
|
||||
container = extractTextual(firstPart);
|
||||
|
||||
// The rest should be attachments
|
||||
for (int i = 1; i < count; i++) {
|
||||
BodyPart bodyPart = multipart.getBodyPart(i);
|
||||
container.attachments.add(bodyPart);
|
||||
}
|
||||
} else {
|
||||
container = new ViewableContainer("", "", new ArrayList<Part>());
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
return extractTextual(message);
|
||||
}
|
||||
|
||||
private static ViewableContainer extractTextual(Part part) throws MessagingException {
|
||||
String text = "";
|
||||
String html = "";
|
||||
List<Part> attachments = new ArrayList<Part>();
|
||||
|
||||
Body firstBody = part.getBody();
|
||||
if (part.isMimeType("text/plain")) {
|
||||
String bodyText = getTextFromPart(part);
|
||||
if (bodyText != null) {
|
||||
text = fixDraftTextBody(bodyText);
|
||||
}
|
||||
} else if (part.isMimeType("multipart/alternative") &&
|
||||
firstBody instanceof MimeMultipart) {
|
||||
MimeMultipart multipart = (MimeMultipart) firstBody;
|
||||
for (int i = 0, count = multipart.getCount(); i < count; i++) {
|
||||
BodyPart bodyPart = multipart.getBodyPart(i);
|
||||
String bodyText = getTextFromPart(bodyPart);
|
||||
if (bodyText != null) {
|
||||
if (text.length() == 0 && bodyPart.isMimeType("text/plain")) {
|
||||
text = fixDraftTextBody(bodyText);
|
||||
} else if (html.length() == 0 && bodyPart.isMimeType("text/html")) {
|
||||
html = fixDraftTextBody(bodyText);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ViewableContainer(text, html, attachments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix line endings of text bodies in draft messages.
|
||||
*
|
||||
* <p>
|
||||
* We create drafts with LF line endings. The values in the identity header are based on that.
|
||||
* So we replace CRLF with LF when loading messages (from the server).
|
||||
* </p>
|
||||
*
|
||||
* @param text
|
||||
* The body text with CRLF line endings
|
||||
*
|
||||
* @return The text with LF line endings
|
||||
*/
|
||||
private static String fixDraftTextBody(String text) {
|
||||
return text.replace("\r\n", "\n");
|
||||
}
|
||||
}
|
||||
|
@ -409,7 +409,7 @@ public class ImapResponseParser {
|
||||
|
||||
|
||||
public Object getKeyedValue(Object key) {
|
||||
for (int i = 0, count = size(); i < count; i++) {
|
||||
for (int i = 0, count = size() - 1; i < count; i++) {
|
||||
if (equalsIgnoreCase(get(i), key)) {
|
||||
return get(i + 1);
|
||||
}
|
||||
@ -434,7 +434,7 @@ public class ImapResponseParser {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0, count = size(); i < count; i++) {
|
||||
for (int i = 0, count = size() - 1; i < count; i++) {
|
||||
if (equalsIgnoreCase(key, get(i))) {
|
||||
return true;
|
||||
}
|
||||
@ -443,7 +443,7 @@ public class ImapResponseParser {
|
||||
}
|
||||
|
||||
public int getKeyIndex(Object key) {
|
||||
for (int i = 0, count = size(); i < count; i++) {
|
||||
for (int i = 0, count = size() - 1; i < count; i++) {
|
||||
if (equalsIgnoreCase(key, get(i))) {
|
||||
return i;
|
||||
}
|
||||
|
@ -1104,15 +1104,6 @@ public class ImapStore extends Store {
|
||||
try {
|
||||
String remoteDestName = encodeString(encodeFolderName(iFolder.getPrefixedName()));
|
||||
|
||||
if (!exists(remoteDestName)) {
|
||||
// If the remote trash folder doesn't exist we try to create it.
|
||||
if (K9.DEBUG) {
|
||||
Log.i(K9.LOG_TAG, "Attempting to create remote folder '" + remoteDestName +
|
||||
"' for " + getLogId());
|
||||
}
|
||||
iFolder.create(FolderType.HOLDS_MESSAGES);
|
||||
}
|
||||
|
||||
//TODO: Split this into multiple commands if the command exceeds a certain length.
|
||||
mConnection.sendCommand(String.format("UID COPY %s %s",
|
||||
Utility.combine(uids, ','),
|
||||
@ -1667,16 +1658,19 @@ public class ImapStore extends Store {
|
||||
|
||||
if (fetchList.containsKey("BODY")) {
|
||||
int index = fetchList.getKeyIndex("BODY") + 2;
|
||||
int size = fetchList.size();
|
||||
if (index < size) {
|
||||
result = fetchList.getObject(index);
|
||||
|
||||
// Check if there's an origin octet
|
||||
if (result instanceof String) {
|
||||
String originOctet = (String)result;
|
||||
if (originOctet.startsWith("<")) {
|
||||
String originOctet = (String) result;
|
||||
if (originOctet.startsWith("<") && (index + 1) < size) {
|
||||
result = fetchList.getObject(index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -2738,13 +2732,8 @@ public class ImapStore extends Store {
|
||||
private static final long serialVersionUID = 3725007182205882394L;
|
||||
String mAlertText;
|
||||
|
||||
public ImapException(String message, String alertText, Throwable throwable) {
|
||||
super(message, throwable);
|
||||
this.mAlertText = alertText;
|
||||
}
|
||||
|
||||
public ImapException(String message, String alertText) {
|
||||
super(message);
|
||||
super(message, true);
|
||||
this.mAlertText = alertText;
|
||||
}
|
||||
|
||||
|
@ -2163,12 +2163,29 @@ public class LocalStore extends Store implements Serializable {
|
||||
deleteAttachments(message.getUid());
|
||||
}
|
||||
|
||||
boolean isDraft = (message.getHeader(K9.IDENTITY_HEADER) != null);
|
||||
|
||||
List<Part> attachments;
|
||||
String text;
|
||||
String html;
|
||||
if (isDraft) {
|
||||
// Don't modify the text/plain or text/html part of our own
|
||||
// draft messages because this will cause the values stored in
|
||||
// the identity header to be wrong.
|
||||
ViewableContainer container =
|
||||
MimeUtility.extractPartsFromDraft(message);
|
||||
|
||||
text = container.text;
|
||||
html = container.html;
|
||||
attachments = container.attachments;
|
||||
} else {
|
||||
ViewableContainer container =
|
||||
MimeUtility.extractTextAndAttachments(mApplication, message);
|
||||
|
||||
List<Part> attachments = container.attachments;
|
||||
String text = container.text;
|
||||
String html = HtmlConverter.convertEmoji2Img(container.html);
|
||||
attachments = container.attachments;
|
||||
text = container.text;
|
||||
html = HtmlConverter.convertEmoji2Img(container.html);
|
||||
}
|
||||
|
||||
String preview = calculateContentPreview(text);
|
||||
|
||||
|
@ -96,6 +96,9 @@ public class AccountSettings {
|
||||
s.put("localStorageProvider", Settings.versions(
|
||||
new V(1, new StorageProviderSetting())
|
||||
));
|
||||
s.put("markMessageAsReadOnView", Settings.versions(
|
||||
new V(7, new BooleanSetting(true))
|
||||
));
|
||||
s.put("maxPushFolders", Settings.versions(
|
||||
new V(1, new IntegerRangeSetting(0, 100, 10))
|
||||
));
|
||||
|
@ -7,6 +7,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
public class Editor implements android.content.SharedPreferences.Editor {
|
||||
private Storage storage;
|
||||
@ -138,4 +139,9 @@ public class Editor implements android.content.SharedPreferences.Editor {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public android.content.SharedPreferences.Editor putStringSet(String arg0, Set<String> arg1) {
|
||||
throw new RuntimeException("Not implemented");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ public class GlobalSettings {
|
||||
new V(1, new BooleanSetting(false))
|
||||
));
|
||||
s.put("theme", Settings.versions(
|
||||
new V(1, new ThemeSetting(android.R.style.Theme_Light))
|
||||
new V(1, new ThemeSetting(K9.THEME_LIGHT))
|
||||
));
|
||||
s.put("useGalleryBugWorkaround", Settings.versions(
|
||||
new V(1, new GalleryBugWorkaroundSetting())
|
||||
@ -291,29 +291,26 @@ public class GlobalSettings {
|
||||
/**
|
||||
* The theme setting.
|
||||
*/
|
||||
public static class ThemeSetting extends PseudoEnumSetting<Integer> {
|
||||
private final Map<Integer, String> mMapping;
|
||||
public static class ThemeSetting extends SettingsDescription {
|
||||
private static final String THEME_LIGHT = "light";
|
||||
private static final String THEME_DARK = "dark";
|
||||
|
||||
public ThemeSetting(int defaultValue) {
|
||||
super(defaultValue);
|
||||
|
||||
Map<Integer, String> mapping = new HashMap<Integer, String>();
|
||||
mapping.put(android.R.style.Theme_Light, "light");
|
||||
mapping.put(android.R.style.Theme, "dark");
|
||||
mMapping = Collections.unmodifiableMap(mapping);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Integer, String> getMapping() {
|
||||
return mMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromString(String value) throws InvalidSettingValueException {
|
||||
try {
|
||||
Integer theme = Integer.parseInt(value);
|
||||
if (mMapping.containsKey(theme)) {
|
||||
return theme;
|
||||
if (theme == K9.THEME_LIGHT ||
|
||||
// We used to store the resource ID of the theme in the preference storage,
|
||||
// but don't use the database upgrade mechanism to update the values. So
|
||||
// we have to deal with the old format here.
|
||||
theme == android.R.style.Theme_Light) {
|
||||
return K9.THEME_LIGHT;
|
||||
} else if (theme == K9.THEME_DARK || theme == android.R.style.Theme) {
|
||||
return K9.THEME_DARK;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
/* do nothing */
|
||||
@ -321,6 +318,22 @@ public class GlobalSettings {
|
||||
|
||||
throw new InvalidSettingValueException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fromPrettyString(String value) throws InvalidSettingValueException {
|
||||
if (THEME_LIGHT.equals(value)) {
|
||||
return K9.THEME_LIGHT;
|
||||
} else if (THEME_DARK.equals(value)) {
|
||||
return K9.THEME_DARK;
|
||||
}
|
||||
|
||||
throw new InvalidSettingValueException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toPrettyString(Object value) {
|
||||
return (((Integer)value).intValue() == K9.THEME_LIGHT) ? THEME_LIGHT : THEME_DARK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,7 +35,7 @@ public class Settings {
|
||||
*
|
||||
* @see SettingsExporter
|
||||
*/
|
||||
public static final int VERSION = 6;
|
||||
public static final int VERSION = 7;
|
||||
|
||||
public static Map<String, Object> validate(int version, Map<String,
|
||||
TreeMap<Integer, SettingsDescription>> settings,
|
||||
|
@ -15,6 +15,7 @@ import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
@ -399,4 +400,10 @@ public class Storage implements SharedPreferences {
|
||||
Log.e(K9.LOG_TAG, "Error writing key '" + key + "', value = '" + value + "'");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Set<String> getStringSet(String arg0, Set<String> arg1) {
|
||||
throw new RuntimeException("Not implemented");
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,5 @@
|
||||
package com.fsck.k9.provider;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
@ -46,6 +33,19 @@ import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mail.store.LocalStore;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class MessageProvider extends ContentProvider {
|
||||
|
||||
public static interface MessageColumns extends BaseColumns {
|
||||
@ -714,6 +714,12 @@ public class MessageProvider extends ContentProvider {
|
||||
checkClosed();
|
||||
mCursor.unregisterDataSetObserver(observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType(int columnIndex) {
|
||||
checkClosed();
|
||||
return mCursor.getType(columnIndex);
|
||||
}
|
||||
}
|
||||
|
||||
protected class ThrottlingQueryHandler implements QueryHandler {
|
||||
|
@ -123,7 +123,7 @@ public class RemoteControlService extends CoreService {
|
||||
|
||||
String theme = intent.getStringExtra(K9_THEME);
|
||||
if (theme != null) {
|
||||
K9.setK9Theme(K9RemoteControl.K9_THEME_DARK.equals(theme) ? android.R.style.Theme : android.R.style.Theme_Light);
|
||||
K9.setK9Theme(K9RemoteControl.K9_THEME_DARK.equals(theme) ? K9.THEME_DARK : K9.THEME_LIGHT);
|
||||
}
|
||||
|
||||
SharedPreferences sPrefs = preferences.getPreferences();
|
||||
|
@ -43,27 +43,6 @@ import com.fsck.k9.mail.store.LocalStore.LocalAttachmentBodyPart;
|
||||
import com.fsck.k9.provider.AttachmentProvider;
|
||||
|
||||
public class AttachmentView extends FrameLayout implements OnClickListener, OnLongClickListener {
|
||||
/**
|
||||
* Regular expression that represents characters we won't allow in file names.
|
||||
*
|
||||
* <p>
|
||||
* Allowed are:
|
||||
* <ul>
|
||||
* <li>word characters (letters, digits, and underscores): {@code \w}</li>
|
||||
* <li>spaces: {@code " "}</li>
|
||||
* <li>special characters: {@code !}, {@code #}, {@code $}, {@code %}, {@code &}, {@code '},
|
||||
* {@code (}, {@code )}, {@code -}, {@code @}, {@code ^}, {@code `}, <code>{</code>,
|
||||
* <code>}</code>, {@code ~}, {@code .}, {@code ,}</li>
|
||||
* </ul></p>
|
||||
*/
|
||||
private static final String INVALID_CHARACTERS = "[^\\w !#$%&'()\\-@\\^`{}~.,]+";
|
||||
|
||||
/**
|
||||
* Invalid characters in a file name are replaced by this character.
|
||||
*/
|
||||
private static final String REPLACEMENT_CHARACTER = "_";
|
||||
|
||||
|
||||
private Context mContext;
|
||||
public Button viewButton;
|
||||
public Button downloadButton;
|
||||
@ -259,7 +238,7 @@ public class AttachmentView extends FrameLayout implements OnClickListener, OnLo
|
||||
*/
|
||||
public void writeFile(File directory) {
|
||||
try {
|
||||
String filename = sanitizeFilename(name);
|
||||
String filename = Utility.sanitizeFilename(name);
|
||||
File file = Utility.createUniqueFile(directory, filename);
|
||||
Uri uri = AttachmentProvider.getAttachmentUri(mAccount, part.getAttachmentId());
|
||||
InputStream in = mContext.getContentResolver().openInputStream(uri);
|
||||
@ -278,18 +257,6 @@ public class AttachmentView extends FrameLayout implements OnClickListener, OnLo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace characters we don't allow in file names with a replacement character.
|
||||
*
|
||||
* @param filename
|
||||
* The original file name.
|
||||
*
|
||||
* @return The sanitized file name containing only allowed characters.
|
||||
*/
|
||||
private String sanitizeFilename(String filename) {
|
||||
return filename.replaceAll(INVALID_CHARACTERS, REPLACEMENT_CHARACTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* saves the file to the defaultpath setting in the config, or if the config
|
||||
* is not set => to the Environment
|
||||
|
@ -50,6 +50,7 @@ public class MessageHeader extends ScrollView implements OnClickListener {
|
||||
|
||||
private View mChip;
|
||||
private View mChip2;
|
||||
private View mChip3;
|
||||
private CheckBox mFlagged;
|
||||
private int defaultSubjectColor;
|
||||
private LinearLayout mToContainerView;
|
||||
@ -63,6 +64,8 @@ public class MessageHeader extends ScrollView implements OnClickListener {
|
||||
private ImageView mShowAdditionalHeadersIcon;
|
||||
private SavedState mSavedState;
|
||||
|
||||
private OnLayoutChangedListener mOnLayoutChangedListener;
|
||||
|
||||
/**
|
||||
* Pair class is only available since API Level 5, so we need
|
||||
* this helper class unfortunately
|
||||
@ -96,12 +99,12 @@ public class MessageHeader extends ScrollView implements OnClickListener {
|
||||
mAdditionalHeadersView = (TextView) findViewById(R.id.additional_headers_view);
|
||||
mChip = findViewById(R.id.chip);
|
||||
mChip2 = findViewById(R.id.chip2);
|
||||
mChip3 = findViewById(R.id.chip3);
|
||||
mDateView = (TextView) findViewById(R.id.date);
|
||||
mTimeView = (TextView) findViewById(R.id.time);
|
||||
mFlagged = (CheckBox) findViewById(R.id.flagged);
|
||||
mShowAdditionalHeadersIcon = (ImageView) findViewById(R.id.show_additional_headers_icon);
|
||||
|
||||
|
||||
defaultSubjectColor = mSubjectView.getCurrentTextColor();
|
||||
mSubjectView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mFontSizes.getMessageViewSubject());
|
||||
mTimeView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mFontSizes.getMessageViewTime());
|
||||
@ -117,12 +120,16 @@ public class MessageHeader extends ScrollView implements OnClickListener {
|
||||
((TextView) findViewById(R.id.cc_label)).setTextSize(TypedValue.COMPLEX_UNIT_SP, mFontSizes.getMessageViewCC());
|
||||
|
||||
findViewById(R.id.show_additional_headers_area).setOnClickListener(this);
|
||||
findViewById(R.id.additional_headers_row).setOnClickListener(this);
|
||||
mFromView.setOnClickListener(this);
|
||||
mToView.setOnClickListener(this);
|
||||
mCcView.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
switch (view.getId()) {
|
||||
case R.id.additional_headers_row:
|
||||
case R.id.show_additional_headers_area: {
|
||||
onShowAdditionalHeaders();
|
||||
break;
|
||||
@ -131,6 +138,11 @@ public class MessageHeader extends ScrollView implements OnClickListener {
|
||||
onAddSenderToContacts();
|
||||
break;
|
||||
}
|
||||
case R.id.to:
|
||||
case R.id.cc: {
|
||||
expand((TextView)view, ((TextView)view).getEllipsize() != null);
|
||||
layoutChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,6 +264,8 @@ public class MessageHeader extends ScrollView implements OnClickListener {
|
||||
mChip.getBackground().setAlpha(chipColorAlpha);
|
||||
mChip2.setBackgroundColor(chipColor);
|
||||
mChip2.getBackground().setAlpha(chipColorAlpha);
|
||||
mChip3.setBackgroundColor(chipColor);
|
||||
mChip3.getBackground().setAlpha(chipColorAlpha);
|
||||
|
||||
setVisibility(View.VISIBLE);
|
||||
|
||||
@ -269,8 +283,26 @@ public class MessageHeader extends ScrollView implements OnClickListener {
|
||||
int currentVisibility = mAdditionalHeadersView.getVisibility();
|
||||
if (currentVisibility == View.VISIBLE) {
|
||||
hideAdditionalHeaders();
|
||||
expand(mToView, false);
|
||||
expand(mCcView, false);
|
||||
} else {
|
||||
showAdditionalHeaders();
|
||||
expand(mToView, true);
|
||||
expand(mCcView, true);
|
||||
}
|
||||
layoutChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand or collapse a TextView by removing or adding the 2 lines limitation
|
||||
*/
|
||||
private void expand(TextView v, boolean expand) {
|
||||
if (expand) {
|
||||
v.setMaxLines(Integer.MAX_VALUE);
|
||||
v.setEllipsize(null);
|
||||
} else {
|
||||
v.setMaxLines(2);
|
||||
v.setEllipsize(android.text.TextUtils.TruncateAt.END);
|
||||
}
|
||||
}
|
||||
|
||||
@ -378,4 +410,18 @@ public class MessageHeader extends ScrollView implements OnClickListener {
|
||||
out.writeInt((this.additionalHeadersVisible) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnLayoutChangedListener {
|
||||
void onLayoutChanged();
|
||||
}
|
||||
|
||||
public void setOnLayoutChangedListener(OnLayoutChangedListener listener) {
|
||||
mOnLayoutChangedListener = listener;
|
||||
}
|
||||
|
||||
private void layoutChanged() {
|
||||
if (mOnLayoutChangedListener != null) {
|
||||
mOnLayoutChangedListener.onLayoutChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +72,12 @@ public class MessageWebView extends WebView {
|
||||
this.setScrollBarStyle(SCROLLBARS_INSIDE_OVERLAY);
|
||||
this.setLongClickable(true);
|
||||
|
||||
if (K9.getK9Theme() == K9.THEME_DARK) {
|
||||
// Black theme should get a black webview background
|
||||
// we'll set the background of the messages on load
|
||||
this.setBackgroundColor(0xff000000);
|
||||
}
|
||||
|
||||
final WebSettings webSettings = this.getSettings();
|
||||
|
||||
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
|
||||
@ -104,6 +110,19 @@ public class MessageWebView extends WebView {
|
||||
|
||||
}
|
||||
|
||||
public void setText(String text, String contentType) {
|
||||
String content = text;
|
||||
if (K9.getK9Theme() == K9.THEME_DARK) {
|
||||
// It's a little wrong to just throw in the <style> before the opening <html>
|
||||
// but it's less wrong than trying to edit the html stream
|
||||
content = "<style>* { background: black ! important; color: white !important }" +
|
||||
":link, :link * { color: #CCFF33 !important }" +
|
||||
":visited, :visited * { color: #551A8B !important }</style> "
|
||||
+ content;
|
||||
}
|
||||
loadDataWithBaseURL("http://", content, contentType, "utf-8", null);
|
||||
}
|
||||
|
||||
/*
|
||||
* Emulate the shift key being pressed to trigger the text selection mode
|
||||
* of a WebView.
|
||||
|
@ -7,16 +7,26 @@ import android.content.Intent;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MenuItem.OnMenuItemClickListener;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View.*;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebView.HitTestResult;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.R;
|
||||
@ -25,15 +35,51 @@ import com.fsck.k9.controller.MessagingController;
|
||||
import com.fsck.k9.controller.MessagingListener;
|
||||
import com.fsck.k9.crypto.CryptoProvider;
|
||||
import com.fsck.k9.crypto.PgpData;
|
||||
import com.fsck.k9.helper.ClipboardManager;
|
||||
import com.fsck.k9.helper.Contacts;
|
||||
import com.fsck.k9.helper.Utility;
|
||||
import com.fsck.k9.mail.*;
|
||||
import com.fsck.k9.mail.internet.MimeUtility;
|
||||
import com.fsck.k9.mail.store.LocalStore;
|
||||
import com.fsck.k9.mail.store.LocalStore.LocalMessage;
|
||||
import com.fsck.k9.provider.AttachmentProvider.AttachmentProviderColumns;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class SingleMessageView extends LinearLayout implements OnClickListener {
|
||||
public class SingleMessageView extends LinearLayout implements OnClickListener,
|
||||
MessageHeader.OnLayoutChangedListener, OnCreateContextMenuListener {
|
||||
private static final int MENU_ITEM_LINK_VIEW = Menu.FIRST;
|
||||
private static final int MENU_ITEM_LINK_SHARE = Menu.FIRST + 1;
|
||||
private static final int MENU_ITEM_LINK_COPY = Menu.FIRST + 2;
|
||||
|
||||
private static final int MENU_ITEM_IMAGE_VIEW = Menu.FIRST;
|
||||
private static final int MENU_ITEM_IMAGE_SAVE = Menu.FIRST + 1;
|
||||
private static final int MENU_ITEM_IMAGE_COPY = Menu.FIRST + 2;
|
||||
|
||||
private static final int MENU_ITEM_PHONE_CALL = Menu.FIRST;
|
||||
private static final int MENU_ITEM_PHONE_SAVE = Menu.FIRST + 1;
|
||||
private static final int MENU_ITEM_PHONE_COPY = Menu.FIRST + 2;
|
||||
|
||||
private static final int MENU_ITEM_EMAIL_SEND = Menu.FIRST;
|
||||
private static final int MENU_ITEM_EMAIL_SAVE = Menu.FIRST + 1;
|
||||
private static final int MENU_ITEM_EMAIL_COPY = Menu.FIRST + 2;
|
||||
|
||||
private static final String[] ATTACHMENT_PROJECTION = new String[] {
|
||||
AttachmentProviderColumns._ID,
|
||||
AttachmentProviderColumns.DISPLAY_NAME
|
||||
};
|
||||
private static final int DISPLAY_NAME_INDEX = 1;
|
||||
|
||||
|
||||
private boolean mScreenReaderEnabled;
|
||||
private MessageCryptoView mCryptoView;
|
||||
private MessageWebView mMessageContentView;
|
||||
@ -56,15 +102,20 @@ public class SingleMessageView extends LinearLayout implements OnClickListener {
|
||||
private View mAttachmentsContainer;
|
||||
private LinearLayout mInsideAttachmentsContainer;
|
||||
private SavedState mSavedState;
|
||||
private ClipboardManager mClipboardManager;
|
||||
|
||||
|
||||
public void initialize(Activity activity) {
|
||||
mMessageContentView = (MessageWebView) findViewById(R.id.message_content);
|
||||
mAccessibleMessageContentView = (AccessibleWebView) findViewById(R.id.accessible_message_content);
|
||||
mMessageContentView.configure();
|
||||
activity.registerForContextMenu(mMessageContentView);
|
||||
mMessageContentView.setOnCreateContextMenuListener(this);
|
||||
|
||||
mHeaderPlaceHolder = (LinearLayout) findViewById(R.id.message_view_header_container);
|
||||
|
||||
mHeaderContainer = (MessageHeader) findViewById(R.id.header_container);
|
||||
mHeaderContainer.setOnLayoutChangedListener(this);
|
||||
|
||||
mAttachmentsContainer = findViewById(R.id.attachments_container);
|
||||
mInsideAttachmentsContainer = (LinearLayout) findViewById(R.id.inside_attachments_container);
|
||||
@ -112,6 +163,210 @@ public class SingleMessageView extends LinearLayout implements OnClickListener {
|
||||
mShowMessageAction.setOnClickListener(this);
|
||||
mShowAttachmentsAction.setOnClickListener(this);
|
||||
mShowPicturesAction.setOnClickListener(this);
|
||||
|
||||
mClipboardManager = ClipboardManager.getInstance(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu);
|
||||
|
||||
WebView webview = (WebView) v;
|
||||
WebView.HitTestResult result = webview.getHitTestResult();
|
||||
int type = result.getType();
|
||||
Context context = getContext();
|
||||
|
||||
switch (type) {
|
||||
case HitTestResult.SRC_ANCHOR_TYPE: {
|
||||
final String url = result.getExtra();
|
||||
OnMenuItemClickListener listener = new OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_ITEM_LINK_VIEW: {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
getContext().startActivity(intent);
|
||||
break;
|
||||
}
|
||||
case MENU_ITEM_LINK_SHARE: {
|
||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||
intent.setType("text/plain");
|
||||
intent.putExtra(Intent.EXTRA_TEXT, url);
|
||||
getContext().startActivity(intent);
|
||||
break;
|
||||
}
|
||||
case MENU_ITEM_LINK_COPY: {
|
||||
String label = getContext().getString(
|
||||
R.string.webview_contextmenu_link_clipboard_label);
|
||||
mClipboardManager.setText(label, url);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
menu.setHeaderTitle(url);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_LINK_VIEW, 0,
|
||||
context.getString(R.string.webview_contextmenu_link_view_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_LINK_SHARE, 1,
|
||||
context.getString(R.string.webview_contextmenu_link_share_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_LINK_COPY, 2,
|
||||
context.getString(R.string.webview_contextmenu_link_copy_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
break;
|
||||
}
|
||||
case HitTestResult.IMAGE_TYPE:
|
||||
case HitTestResult.SRC_IMAGE_ANCHOR_TYPE: {
|
||||
final String url = result.getExtra();
|
||||
final boolean externalImage = url.startsWith("http");
|
||||
OnMenuItemClickListener listener = new OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_ITEM_IMAGE_VIEW: {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
if (!externalImage) {
|
||||
// Grant read permission if this points to our
|
||||
// AttachmentProvider
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
}
|
||||
getContext().startActivity(intent);
|
||||
break;
|
||||
}
|
||||
case MENU_ITEM_IMAGE_SAVE: {
|
||||
new DownloadImageTask().execute(url);
|
||||
break;
|
||||
}
|
||||
case MENU_ITEM_IMAGE_COPY: {
|
||||
String label = getContext().getString(
|
||||
R.string.webview_contextmenu_image_clipboard_label);
|
||||
mClipboardManager.setText(label, url);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
menu.setHeaderTitle((externalImage) ?
|
||||
url : context.getString(R.string.webview_contextmenu_image_title));
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_IMAGE_VIEW, 0,
|
||||
context.getString(R.string.webview_contextmenu_image_view_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_IMAGE_SAVE, 1,
|
||||
(externalImage) ?
|
||||
context.getString(R.string.webview_contextmenu_image_download_action) :
|
||||
context.getString(R.string.webview_contextmenu_image_save_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
if (externalImage) {
|
||||
menu.add(Menu.NONE, MENU_ITEM_IMAGE_COPY, 2,
|
||||
context.getString(R.string.webview_contextmenu_image_copy_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case HitTestResult.PHONE_TYPE: {
|
||||
final String phoneNumber = result.getExtra();
|
||||
OnMenuItemClickListener listener = new OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_ITEM_PHONE_CALL: {
|
||||
Uri uri = Uri.parse(WebView.SCHEME_TEL + phoneNumber);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
getContext().startActivity(intent);
|
||||
break;
|
||||
}
|
||||
case MENU_ITEM_PHONE_SAVE: {
|
||||
Contacts contacts = Contacts.getInstance(getContext());
|
||||
contacts.addPhoneContact(phoneNumber);
|
||||
break;
|
||||
}
|
||||
case MENU_ITEM_PHONE_COPY: {
|
||||
String label = getContext().getString(
|
||||
R.string.webview_contextmenu_phone_clipboard_label);
|
||||
mClipboardManager.setText(label, phoneNumber);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
menu.setHeaderTitle(phoneNumber);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_PHONE_CALL, 0,
|
||||
context.getString(R.string.webview_contextmenu_phone_call_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_PHONE_SAVE, 1,
|
||||
context.getString(R.string.webview_contextmenu_phone_save_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_PHONE_COPY, 2,
|
||||
context.getString(R.string.webview_contextmenu_phone_copy_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
break;
|
||||
}
|
||||
case WebView.HitTestResult.EMAIL_TYPE: {
|
||||
final String email = result.getExtra();
|
||||
OnMenuItemClickListener listener = new OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_ITEM_EMAIL_SEND: {
|
||||
Uri uri = Uri.parse(WebView.SCHEME_MAILTO + email);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
getContext().startActivity(intent);
|
||||
break;
|
||||
}
|
||||
case MENU_ITEM_EMAIL_SAVE: {
|
||||
Contacts contacts = Contacts.getInstance(getContext());
|
||||
contacts.createContact(new Address(email));
|
||||
break;
|
||||
}
|
||||
case MENU_ITEM_EMAIL_COPY: {
|
||||
String label = getContext().getString(
|
||||
R.string.webview_contextmenu_email_clipboard_label);
|
||||
mClipboardManager.setText(label, email);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
menu.setHeaderTitle(email);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_EMAIL_SEND, 0,
|
||||
context.getString(R.string.webview_contextmenu_email_send_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_EMAIL_SAVE, 1,
|
||||
context.getString(R.string.webview_contextmenu_email_save_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
menu.add(Menu.NONE, MENU_ITEM_EMAIL_COPY, 2,
|
||||
context.getString(R.string.webview_contextmenu_email_copy_action))
|
||||
.setOnMenuItemClickListener(listener);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -269,9 +524,13 @@ public class SingleMessageView extends LinearLayout implements OnClickListener {
|
||||
resetView();
|
||||
|
||||
String type;
|
||||
String text = pgpData.getDecryptedData();
|
||||
String text = null;
|
||||
if (pgpData != null) {
|
||||
text = pgpData.getDecryptedData();
|
||||
}
|
||||
if (text != null) {
|
||||
type = "text/plain";
|
||||
type = "text/html";
|
||||
text = "<html><body><pre>" + text + "</pre></body></html>";
|
||||
} else {
|
||||
// getTextForDisplay() always returns HTML-ified content.
|
||||
text = message.getTextForDisplay();
|
||||
@ -283,7 +542,7 @@ public class SingleMessageView extends LinearLayout implements OnClickListener {
|
||||
loadBodyFromText(emailText, contentType);
|
||||
updateCryptoLayout(account.getCryptoProvider(), pgpData, message);
|
||||
} else {
|
||||
loadBodyFromUrl("file:///android_asset/empty.html");
|
||||
showStatusMessage(getContext().getString(R.string.webview_empty_message));
|
||||
}
|
||||
|
||||
mHasAttachments = message.hasAttachments();
|
||||
@ -335,17 +594,19 @@ public class SingleMessageView extends LinearLayout implements OnClickListener {
|
||||
}
|
||||
}
|
||||
|
||||
public void loadBodyFromUrl(String url) {
|
||||
mMessageContentView.loadUrl(url);
|
||||
public void showStatusMessage(String status) {
|
||||
String text = "<html><body><div style=\"text-align:center; color: grey;\">" +
|
||||
status +
|
||||
"</div></body></html>";
|
||||
loadBodyFromText(text, "text/html");
|
||||
mCryptoView.hide();
|
||||
|
||||
}
|
||||
|
||||
private void loadBodyFromText(String emailText, String contentType) {
|
||||
if (mScreenReaderEnabled) {
|
||||
mAccessibleMessageContentView.loadDataWithBaseURL("http://", emailText, contentType, "utf-8", null);
|
||||
} else {
|
||||
mMessageContentView.loadDataWithBaseURL("http://", emailText, contentType, "utf-8", null);
|
||||
mMessageContentView.setText(emailText, contentType);
|
||||
mMessageContentView.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
@ -508,6 +769,13 @@ public class SingleMessageView extends LinearLayout implements OnClickListener {
|
||||
mSavedState = savedState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayoutChanged() {
|
||||
if (mMessageContentView != null) {
|
||||
mMessageContentView.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
static class SavedState extends BaseSavedState {
|
||||
boolean attachmentViewVisible;
|
||||
boolean hiddenAttachmentsVisible;
|
||||
@ -547,4 +815,117 @@ public class SingleMessageView extends LinearLayout implements OnClickListener {
|
||||
out.writeInt((this.showPictures) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
class DownloadImageTask extends AsyncTask<String, Void, String> {
|
||||
@Override
|
||||
protected String doInBackground(String... params) {
|
||||
String urlString = params[0];
|
||||
try {
|
||||
boolean externalImage = urlString.startsWith("http");
|
||||
|
||||
String filename = null;
|
||||
String mimeType = null;
|
||||
InputStream in = null;
|
||||
|
||||
try {
|
||||
if (externalImage) {
|
||||
URL url = new URL(urlString);
|
||||
URLConnection conn = url.openConnection();
|
||||
in = conn.getInputStream();
|
||||
|
||||
String path = url.getPath();
|
||||
|
||||
// Try to get the filename from the URL
|
||||
int start = path.lastIndexOf("/");
|
||||
if (start != -1 && start + 1 < path.length()) {
|
||||
filename = URLDecoder.decode(path.substring(start + 1), "UTF-8");
|
||||
} else {
|
||||
// Use a dummy filename if necessary
|
||||
filename = "saved_image";
|
||||
}
|
||||
|
||||
// Get the MIME type if we couldn't find a file extension
|
||||
if (filename.indexOf('.') == -1) {
|
||||
mimeType = conn.getContentType();
|
||||
}
|
||||
} else {
|
||||
ContentResolver contentResolver = getContext().getContentResolver();
|
||||
Uri uri = Uri.parse(urlString);
|
||||
|
||||
// Get the filename from AttachmentProvider
|
||||
Cursor cursor = contentResolver.query(uri, ATTACHMENT_PROJECTION, null, null, null);
|
||||
if (cursor != null) {
|
||||
try {
|
||||
if (cursor.moveToNext()) {
|
||||
filename = cursor.getString(DISPLAY_NAME_INDEX);
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
// Use a dummy filename if necessary
|
||||
if (filename == null) {
|
||||
filename = "saved_image";
|
||||
}
|
||||
|
||||
// Get the MIME type if we couldn't find a file extension
|
||||
if (filename.indexOf('.') == -1) {
|
||||
mimeType = contentResolver.getType(uri);
|
||||
}
|
||||
|
||||
in = contentResolver.openInputStream(uri);
|
||||
}
|
||||
|
||||
// Do we still need an extension?
|
||||
if (filename.indexOf('.') == -1) {
|
||||
// Use JPEG as fallback
|
||||
String extension = "jpeg";
|
||||
if (mimeType != null) {
|
||||
// Try to find an extension for the given MIME type
|
||||
String ext = MimeUtility.getExtensionByMimeType(mimeType);
|
||||
if (ext != null) {
|
||||
extension = ext;
|
||||
}
|
||||
}
|
||||
filename += "." + extension;
|
||||
}
|
||||
|
||||
String sanitized = Utility.sanitizeFilename(filename);
|
||||
|
||||
File directory = new File(K9.getAttachmentDefaultPath());
|
||||
File file = Utility.createUniqueFile(directory, sanitized);
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
try {
|
||||
IOUtils.copy(in, out);
|
||||
out.flush();
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
|
||||
return file.getName();
|
||||
|
||||
} finally {
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String filename) {
|
||||
String text;
|
||||
if (filename == null) {
|
||||
text = getContext().getString(R.string.image_saving_failed);
|
||||
} else {
|
||||
text = getContext().getString(R.string.image_saved_as, filename);
|
||||
}
|
||||
|
||||
Toast.makeText(getContext(), text, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,143 +0,0 @@
|
||||
package com.fsck.k9.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.ScrollView;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.controller.MessagingListener;
|
||||
|
||||
/**
|
||||
* An extension of {@link ScrollView} that allows scrolling to be selectively disabled.
|
||||
*/
|
||||
public class ToggleScrollView extends ScrollView {
|
||||
private GestureDetector mDetector;
|
||||
private boolean mScrolling = true;
|
||||
private int mCurrentYPosition;
|
||||
private double mScrollPercentage;
|
||||
private ScrollToLastLocationListener mListener;
|
||||
|
||||
public ToggleScrollView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mDetector = new GestureDetector(new YScrollDetector());
|
||||
}
|
||||
|
||||
public void setScrolling(boolean enable) {
|
||||
mScrolling = enable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
return (mScrolling) ? super.onTouchEvent(ev) : true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
if (!mScrolling) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This doesn't quite get us to diagonal scrolling, but it's somewhat better than what we've
|
||||
// currently got. This is based on
|
||||
// http://stackoverflow.com/questions/2646028/android-horizontalscrollview-within-scrollview-touch-handling
|
||||
boolean result = super.onInterceptTouchEvent(ev);
|
||||
// Let the original ScrollView handle ACTION_DOWN so we can stop the scroll when someone touches the screen.
|
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN || mDetector.onTouchEvent(ev)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return false if we're scrolling in the x direction. That is, decline to consume the event and
|
||||
// let the parent class take a stab at it.
|
||||
class YScrollDetector extends GestureDetector.SimpleOnGestureListener {
|
||||
@Override
|
||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
||||
try {
|
||||
if (Math.abs(distanceY) > Math.abs(distanceX)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// nothing
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the current percentage by which this view has been scrolled.
|
||||
* @return Scroll percentage based on the top edge of the screen, from 0 to 100. This number should never really
|
||||
* be 100, unless the screen is of 0 height...
|
||||
*/
|
||||
public double getScrollPercentage() {
|
||||
// We save only the Y coordinate instead of the percentage because I don't know how expensive the
|
||||
// computeVerticalScrollRange() call is.
|
||||
final int scrollRange = computeVerticalScrollRange();
|
||||
if (scrollRange == 0) {
|
||||
return 0;
|
||||
}
|
||||
return (double) mCurrentYPosition / scrollRange;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the percentage by which we should scroll the page once we get the load complete event. This is
|
||||
* based on the top edge of the view.
|
||||
* @param percentage Percentage of page to scroll to.
|
||||
*/
|
||||
public void setScrollPercentage(final double percentage) {
|
||||
Log.d(K9.LOG_TAG, "ToggleView: Setting last scroll percentage to " + percentage);
|
||||
this.mScrollPercentage = percentage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override {@link ScrollView#onScrollChanged(int, int, int, int)} to record the current x/y position. We use this
|
||||
* to save our current position for future scrolling.
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @param oldx
|
||||
* @param oldy
|
||||
*/
|
||||
@Override
|
||||
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
|
||||
super.onScrollChanged(x, y, oldx, oldy);
|
||||
|
||||
this.mCurrentYPosition = y;
|
||||
// I wish Android has a TRACE log level so I wouldn't have to comment this out. This one is really noisy.
|
||||
// Log.d(K9.LOG_TAG, "ToggleScrollView: mCurrentYPosition=" + y + " scrollRange=" + computeVerticalScrollRange() + " pct=" + getScrollPercentage());
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a {@link MessagingListener} which listens for when the a message has finished being displayed on the
|
||||
* screen. We'll scroll the message to the user's last known location once it's done.
|
||||
*/
|
||||
class ScrollToLastLocationListener extends MessagingListener {
|
||||
public void messageViewFinished() {
|
||||
// Don't scroll if our last position was at the top.
|
||||
if (mScrollPercentage != 0.0) {
|
||||
final int scrollRange = computeVerticalScrollRange();
|
||||
final int newY = (int)(mScrollPercentage * scrollRange);
|
||||
Log.d(K9.LOG_TAG, "ToggleScrollView: requested " + (100 * mScrollPercentage) + "%, " +
|
||||
"scrolling to " + newY + "/" + scrollRange);
|
||||
scrollTo(0, newY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the {@link MessagingListener} for this <code>ScrollView</code>.
|
||||
* @return
|
||||
*/
|
||||
public MessagingListener getListener() {
|
||||
if (this.mListener != null) {
|
||||
return this.mListener;
|
||||
} else {
|
||||
return this.mListener = new ScrollToLastLocationListener();
|
||||
}
|
||||
}
|
||||
}
|
39
tests/src/com/fsck/k9/mail/internet/MimeUtilityTest.java
Normal file
39
tests/src/com/fsck/k9/mail/internet/MimeUtilityTest.java
Normal file
@ -0,0 +1,39 @@
|
||||
package com.fsck.k9.mail.internet;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
public class MimeUtilityTest extends AndroidTestCase {
|
||||
|
||||
public void testGetHeaderParameter() {
|
||||
String result;
|
||||
|
||||
/* Test edge cases */
|
||||
result = MimeUtility.getHeaderParameter(";", null);
|
||||
assertEquals(null, result);
|
||||
|
||||
result = MimeUtility.getHeaderParameter("name", "name");
|
||||
assertEquals(null, result);
|
||||
|
||||
result = MimeUtility.getHeaderParameter("name=", "name");
|
||||
assertEquals("", result);
|
||||
|
||||
result = MimeUtility.getHeaderParameter("name=\"", "name");
|
||||
assertEquals("\"", result);
|
||||
|
||||
/* Test expected cases */
|
||||
result = MimeUtility.getHeaderParameter("name=value", "name");
|
||||
assertEquals("value", result);
|
||||
|
||||
result = MimeUtility.getHeaderParameter("name = value", "name");
|
||||
assertEquals("value", result);
|
||||
|
||||
result = MimeUtility.getHeaderParameter("name=\"value\"", "name");
|
||||
assertEquals("value", result);
|
||||
|
||||
result = MimeUtility.getHeaderParameter("name = \"value\"" , "name");
|
||||
assertEquals("value", result);
|
||||
|
||||
result = MimeUtility.getHeaderParameter("name=\"\"", "name");
|
||||
assertEquals("", result);
|
||||
}
|
||||
}
|
@ -59,6 +59,36 @@ public class ImapResponseParserTest extends TestCase {
|
||||
assertEquals("token2", respTextCode.get(1));
|
||||
}
|
||||
|
||||
public void testImapListMethods() throws IOException {
|
||||
ImapList list = new ImapList();
|
||||
list.add("ONE");
|
||||
list.add("TWO");
|
||||
list.add("THREE");
|
||||
|
||||
assertTrue(list.containsKey("ONE"));
|
||||
assertTrue(list.containsKey("TWO"));
|
||||
assertFalse(list.containsKey("THREE"));
|
||||
assertFalse(list.containsKey("nonexistent"));
|
||||
|
||||
assertEquals("TWO", list.getKeyedValue("ONE"));
|
||||
assertEquals("THREE", list.getKeyedValue("TWO"));
|
||||
assertNull(list.getKeyedValue("THREE"));
|
||||
assertNull(list.getKeyedValue("nonexistent"));
|
||||
|
||||
assertEquals(0, list.getKeyIndex("ONE"));
|
||||
assertEquals(1, list.getKeyIndex("TWO"));
|
||||
|
||||
try {
|
||||
list.getKeyIndex("THREE");
|
||||
fail("IllegalArgumentException should have been thrown");
|
||||
} catch (IllegalArgumentException e) { /* do nothing */ }
|
||||
|
||||
try {
|
||||
list.getKeyIndex("nonexistent");
|
||||
fail("IllegalArgumentException should have been thrown");
|
||||
} catch (IllegalArgumentException e) { /* do nothing */ }
|
||||
}
|
||||
|
||||
private ImapResponseParser createParser(String response) {
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(response.getBytes());
|
||||
PeekableInputStream pin = new PeekableInputStream(in);
|
||||
|
Loading…
Reference in New Issue
Block a user