parent
bd03437c71
commit
faf8e980be
|
@ -8,7 +8,7 @@ buildscript {
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.github.ben-manes:gradle-versions-plugin:0.13.0'
|
classpath 'com.github.ben-manes:gradle-versions-plugin:0.13.0'
|
||||||
classpath 'com.android.tools.build:gradle:2.2.2'
|
classpath 'com.android.tools.build:gradle:2.2.3'
|
||||||
classpath 'com.google.gms:google-services:3.0.0'
|
classpath 'com.google.gms:google-services:3.0.0'
|
||||||
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
|
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
|
||||||
classpath('fr.avianey.androidsvgdrawable:gradle-plugin:3.0.0') {
|
classpath('fr.avianey.androidsvgdrawable:gradle-plugin:3.0.0') {
|
||||||
|
|
|
@ -2,6 +2,9 @@ package org.mariotaku.twidere.annotation;
|
||||||
|
|
||||||
import android.support.annotation.StringDef;
|
import android.support.annotation.StringDef;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by mariotaku on 16/1/28.
|
* Created by mariotaku on 16/1/28.
|
||||||
*/
|
*/
|
||||||
|
@ -15,6 +18,7 @@ import android.support.annotation.StringDef;
|
||||||
CustomTabType.SEARCH_STATUSES,
|
CustomTabType.SEARCH_STATUSES,
|
||||||
CustomTabType.LIST_TIMELINE,
|
CustomTabType.LIST_TIMELINE,
|
||||||
})
|
})
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface CustomTabType {
|
public @interface CustomTabType {
|
||||||
String HOME_TIMELINE = "home_timeline";
|
String HOME_TIMELINE = "home_timeline";
|
||||||
String NOTIFICATIONS_TIMELINE = "notifications_timeline";
|
String NOTIFICATIONS_TIMELINE = "notifications_timeline";
|
||||||
|
|
|
@ -30,7 +30,7 @@ import com.hannesdorfmann.parcelableplease.annotation.ParcelableThisPlease;
|
||||||
import org.mariotaku.commons.objectcursor.LoganSquareCursorFieldConverter;
|
import org.mariotaku.commons.objectcursor.LoganSquareCursorFieldConverter;
|
||||||
import org.mariotaku.library.objectcursor.annotation.CursorField;
|
import org.mariotaku.library.objectcursor.annotation.CursorField;
|
||||||
import org.mariotaku.library.objectcursor.annotation.CursorObject;
|
import org.mariotaku.library.objectcursor.annotation.CursorObject;
|
||||||
import org.mariotaku.twidere.model.draft.ActionExtra;
|
import org.mariotaku.twidere.model.draft.ActionExtras;
|
||||||
import org.mariotaku.twidere.model.util.DraftExtrasConverter;
|
import org.mariotaku.twidere.model.util.DraftExtrasConverter;
|
||||||
import org.mariotaku.twidere.model.util.UserKeysCursorFieldConverter;
|
import org.mariotaku.twidere.model.util.UserKeysCursorFieldConverter;
|
||||||
import org.mariotaku.twidere.provider.TwidereDataStore;
|
import org.mariotaku.twidere.provider.TwidereDataStore;
|
||||||
|
@ -69,7 +69,7 @@ public class Draft implements Parcelable {
|
||||||
@Nullable
|
@Nullable
|
||||||
@ParcelableThisPlease
|
@ParcelableThisPlease
|
||||||
@CursorField(value = Drafts.ACTION_EXTRAS, converter = DraftExtrasConverter.class)
|
@CursorField(value = Drafts.ACTION_EXTRAS, converter = DraftExtrasConverter.class)
|
||||||
public ActionExtra action_extras;
|
public ActionExtras action_extras;
|
||||||
|
|
||||||
|
|
||||||
public Draft() {
|
public Draft() {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||||
|
@ -85,7 +86,7 @@ public class ParcelableLocation implements Parcelable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static ParcelableLocation valueOf(@Nullable final String locationString) {
|
public static ParcelableLocation valueOf(@NonNull final String locationString) {
|
||||||
if (locationString == null) return null;
|
if (locationString == null) return null;
|
||||||
final String[] longlat = locationString.split(",");
|
final String[] longlat = locationString.split(",");
|
||||||
if (longlat.length != 2) {
|
if (longlat.length != 2) {
|
||||||
|
@ -106,7 +107,9 @@ public class ParcelableLocation implements Parcelable {
|
||||||
public static class Converter implements CursorFieldConverter<ParcelableLocation> {
|
public static class Converter implements CursorFieldConverter<ParcelableLocation> {
|
||||||
@Override
|
@Override
|
||||||
public ParcelableLocation parseField(Cursor cursor, int columnIndex, ParameterizedType fieldType) {
|
public ParcelableLocation parseField(Cursor cursor, int columnIndex, ParameterizedType fieldType) {
|
||||||
return valueOf(cursor.getString(columnIndex));
|
final String locationString = cursor.getString(columnIndex);
|
||||||
|
if (locationString == null) return null;
|
||||||
|
return valueOf(locationString);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -5,5 +5,5 @@ import android.os.Parcelable;
|
||||||
/**
|
/**
|
||||||
* Created by mariotaku on 16/2/21.
|
* Created by mariotaku on 16/2/21.
|
||||||
*/
|
*/
|
||||||
public interface ActionExtra extends Parcelable {
|
public interface ActionExtras extends Parcelable {
|
||||||
}
|
}
|
|
@ -1,51 +0,0 @@
|
||||||
package org.mariotaku.twidere.model.draft;
|
|
||||||
|
|
||||||
import android.os.Parcel;
|
|
||||||
|
|
||||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
|
||||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
|
||||||
import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
|
|
||||||
import com.hannesdorfmann.parcelableplease.annotation.ParcelableThisPlease;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by mariotaku on 16/2/21.
|
|
||||||
*/
|
|
||||||
@ParcelablePlease
|
|
||||||
@JsonObject
|
|
||||||
public class SendDirectMessageActionExtra implements ActionExtra {
|
|
||||||
@ParcelableThisPlease
|
|
||||||
@JsonField(name = "recipient_id")
|
|
||||||
String recipientId;
|
|
||||||
|
|
||||||
public String getRecipientId() {
|
|
||||||
return recipientId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRecipientId(String recipientId) {
|
|
||||||
this.recipientId = recipientId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int describeContents() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
|
||||||
SendDirectMessageActionExtraParcelablePlease.writeToParcel(this, dest, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final Creator<SendDirectMessageActionExtra> CREATOR = new Creator<SendDirectMessageActionExtra>() {
|
|
||||||
@Override
|
|
||||||
public SendDirectMessageActionExtra createFromParcel(Parcel source) {
|
|
||||||
SendDirectMessageActionExtra target = new SendDirectMessageActionExtra();
|
|
||||||
SendDirectMessageActionExtraParcelablePlease.readFromParcel(target, source);
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SendDirectMessageActionExtra[] newArray(int size) {
|
|
||||||
return new SendDirectMessageActionExtra[size];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
package org.mariotaku.twidere.model.draft;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
|
||||||
|
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||||
|
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||||
|
import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
|
||||||
|
import com.hannesdorfmann.parcelableplease.annotation.ParcelableThisPlease;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by mariotaku on 16/2/21.
|
||||||
|
*/
|
||||||
|
@ParcelablePlease
|
||||||
|
@JsonObject
|
||||||
|
public class SendDirectMessageActionExtras implements ActionExtras {
|
||||||
|
@ParcelableThisPlease
|
||||||
|
@JsonField(name = "recipient_id")
|
||||||
|
String recipientId;
|
||||||
|
|
||||||
|
public String getRecipientId() {
|
||||||
|
return recipientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRecipientId(String recipientId) {
|
||||||
|
this.recipientId = recipientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
SendDirectMessageActionExtrasParcelablePlease.writeToParcel(this, dest, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
SendDirectMessageActionExtras that = (SendDirectMessageActionExtras) o;
|
||||||
|
|
||||||
|
return recipientId != null ? recipientId.equals(that.recipientId) : that.recipientId == null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return recipientId != null ? recipientId.hashCode() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Creator<SendDirectMessageActionExtras> CREATOR = new Creator<SendDirectMessageActionExtras>() {
|
||||||
|
@Override
|
||||||
|
public SendDirectMessageActionExtras createFromParcel(Parcel source) {
|
||||||
|
SendDirectMessageActionExtras target = new SendDirectMessageActionExtras();
|
||||||
|
SendDirectMessageActionExtrasParcelablePlease.readFromParcel(target, source);
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SendDirectMessageActionExtras[] newArray(int size) {
|
||||||
|
return new SendDirectMessageActionExtras[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ import org.mariotaku.twidere.model.ParcelableStatus;
|
||||||
*/
|
*/
|
||||||
@ParcelablePlease
|
@ParcelablePlease
|
||||||
@JsonObject
|
@JsonObject
|
||||||
public class UpdateStatusActionExtra implements ActionExtra {
|
public class UpdateStatusActionExtras implements ActionExtras {
|
||||||
@ParcelableThisPlease
|
@ParcelableThisPlease
|
||||||
@JsonField(name = "in_reply_to_status")
|
@JsonField(name = "in_reply_to_status")
|
||||||
ParcelableStatus inReplyToStatus;
|
ParcelableStatus inReplyToStatus;
|
||||||
|
@ -78,20 +78,47 @@ public class UpdateStatusActionExtra implements ActionExtra {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
UpdateStatusActionExtraParcelablePlease.writeToParcel(this, dest, flags);
|
UpdateStatusActionExtrasParcelablePlease.writeToParcel(this, dest, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Creator<UpdateStatusActionExtra> CREATOR = new Creator<UpdateStatusActionExtra>() {
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
UpdateStatusActionExtras that = (UpdateStatusActionExtras) o;
|
||||||
|
|
||||||
|
if (possiblySensitive != that.possiblySensitive) return false;
|
||||||
|
if (displayCoordinates != that.displayCoordinates) return false;
|
||||||
|
if (inReplyToStatus != null ? !inReplyToStatus.equals(that.inReplyToStatus) : that.inReplyToStatus != null)
|
||||||
|
return false;
|
||||||
|
if (repostStatusId != null ? !repostStatusId.equals(that.repostStatusId) : that.repostStatusId != null)
|
||||||
|
return false;
|
||||||
|
return attachmentUrl != null ? attachmentUrl.equals(that.attachmentUrl) : that.attachmentUrl == null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = inReplyToStatus != null ? inReplyToStatus.hashCode() : 0;
|
||||||
|
result = 31 * result + (possiblySensitive ? 1 : 0);
|
||||||
|
result = 31 * result + (repostStatusId != null ? repostStatusId.hashCode() : 0);
|
||||||
|
result = 31 * result + (displayCoordinates ? 1 : 0);
|
||||||
|
result = 31 * result + (attachmentUrl != null ? attachmentUrl.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Creator<UpdateStatusActionExtras> CREATOR = new Creator<UpdateStatusActionExtras>() {
|
||||||
@Override
|
@Override
|
||||||
public UpdateStatusActionExtra createFromParcel(Parcel source) {
|
public UpdateStatusActionExtras createFromParcel(Parcel source) {
|
||||||
UpdateStatusActionExtra target = new UpdateStatusActionExtra();
|
UpdateStatusActionExtras target = new UpdateStatusActionExtras();
|
||||||
UpdateStatusActionExtraParcelablePlease.readFromParcel(target, source);
|
UpdateStatusActionExtrasParcelablePlease.readFromParcel(target, source);
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UpdateStatusActionExtra[] newArray(int size) {
|
public UpdateStatusActionExtras[] newArray(int size) {
|
||||||
return new UpdateStatusActionExtra[size];
|
return new UpdateStatusActionExtras[size];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -8,9 +8,9 @@ import com.bluelinelabs.logansquare.LoganSquare;
|
||||||
|
|
||||||
import org.mariotaku.library.objectcursor.converter.CursorFieldConverter;
|
import org.mariotaku.library.objectcursor.converter.CursorFieldConverter;
|
||||||
import org.mariotaku.twidere.model.Draft;
|
import org.mariotaku.twidere.model.Draft;
|
||||||
import org.mariotaku.twidere.model.draft.ActionExtra;
|
import org.mariotaku.twidere.model.draft.ActionExtras;
|
||||||
import org.mariotaku.twidere.model.draft.SendDirectMessageActionExtra;
|
import org.mariotaku.twidere.model.draft.SendDirectMessageActionExtras;
|
||||||
import org.mariotaku.twidere.model.draft.UpdateStatusActionExtra;
|
import org.mariotaku.twidere.model.draft.UpdateStatusActionExtras;
|
||||||
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts;
|
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -19,33 +19,30 @@ import java.lang.reflect.ParameterizedType;
|
||||||
/**
|
/**
|
||||||
* Created by mariotaku on 16/2/20.
|
* Created by mariotaku on 16/2/20.
|
||||||
*/
|
*/
|
||||||
public class DraftExtrasConverter implements CursorFieldConverter<ActionExtra> {
|
public class DraftExtrasConverter implements CursorFieldConverter<ActionExtras> {
|
||||||
@Override
|
@Override
|
||||||
public ActionExtra parseField(Cursor cursor, int columnIndex, ParameterizedType fieldType) throws IOException {
|
public ActionExtras parseField(Cursor cursor, int columnIndex, ParameterizedType fieldType) throws IOException {
|
||||||
final String actionType = cursor.getString(cursor.getColumnIndex(Drafts.ACTION_TYPE));
|
final String actionType = cursor.getString(cursor.getColumnIndex(Drafts.ACTION_TYPE));
|
||||||
if (TextUtils.isEmpty(actionType)) return null;
|
final String json = cursor.getString(columnIndex);
|
||||||
|
if (TextUtils.isEmpty(actionType) || TextUtils.isEmpty(json)) return null;
|
||||||
switch (actionType) {
|
switch (actionType) {
|
||||||
case "0":
|
case "0":
|
||||||
case "1":
|
case "1":
|
||||||
case Draft.Action.UPDATE_STATUS:
|
case Draft.Action.UPDATE_STATUS:
|
||||||
case Draft.Action.REPLY:
|
case Draft.Action.REPLY:
|
||||||
case Draft.Action.QUOTE: {
|
case Draft.Action.QUOTE: {
|
||||||
final String string = cursor.getString(columnIndex);
|
return LoganSquare.parse(json, UpdateStatusActionExtras.class);
|
||||||
if (TextUtils.isEmpty(string)) return null;
|
|
||||||
return LoganSquare.parse(string, UpdateStatusActionExtra.class);
|
|
||||||
}
|
}
|
||||||
case "2":
|
case "2":
|
||||||
case Draft.Action.SEND_DIRECT_MESSAGE: {
|
case Draft.Action.SEND_DIRECT_MESSAGE: {
|
||||||
final String string = cursor.getString(columnIndex);
|
return LoganSquare.parse(json, SendDirectMessageActionExtras.class);
|
||||||
if (TextUtils.isEmpty(string)) return null;
|
|
||||||
return LoganSquare.parse(string, SendDirectMessageActionExtra.class);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeField(ContentValues values, ActionExtra object, String columnName, ParameterizedType fieldType) throws IOException {
|
public void writeField(ContentValues values, ActionExtras object, String columnName, ParameterizedType fieldType) throws IOException {
|
||||||
if (object == null) return;
|
if (object == null) return;
|
||||||
values.put(columnName, LoganSquare.serialize(object));
|
values.put(columnName, LoganSquare.serialize(object));
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,6 +125,7 @@ dependencies {
|
||||||
androidTestCompile "com.android.support:support-annotations:$android_support_lib_version"
|
androidTestCompile "com.android.support:support-annotations:$android_support_lib_version"
|
||||||
androidTestCompile 'com.android.support.test:runner:0.5'
|
androidTestCompile 'com.android.support.test:runner:0.5'
|
||||||
androidTestCompile 'com.android.support.test:rules:0.5'
|
androidTestCompile 'com.android.support.test:rules:0.5'
|
||||||
|
androidTestCompile 'commons-io:commons-io:2.5'
|
||||||
|
|
||||||
compile 'com.android.support:multidex:1.0.1'
|
compile 'com.android.support:multidex:1.0.1'
|
||||||
compile "com.android.support:support-v4:$android_support_lib_version"
|
compile "com.android.support:support-v4:$android_support_lib_version"
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
package org.mariotaku.twidere
|
package org.mariotaku.twidere
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
import android.support.test.InstrumentationRegistry
|
import android.support.test.InstrumentationRegistry
|
||||||
import android.support.test.runner.AndroidJUnit4
|
import android.support.test.runner.AndroidJUnit4
|
||||||
|
import org.apache.commons.io.IOUtils
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mariotaku.twidere.extension.readMimeMessageFrom
|
import org.mariotaku.twidere.extension.readMimeMessageFrom
|
||||||
import org.mariotaku.twidere.extension.writeMimeMessageTo
|
import org.mariotaku.twidere.extension.writeMimeMessageTo
|
||||||
import org.mariotaku.twidere.model.Draft
|
import org.mariotaku.twidere.model.*
|
||||||
import org.mariotaku.twidere.model.ParcelableMedia
|
|
||||||
import org.mariotaku.twidere.model.ParcelableMediaUpdate
|
|
||||||
import org.mariotaku.twidere.model.UserKey
|
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
@ -24,16 +23,24 @@ class DraftExtensionsTest {
|
||||||
fun testMimeMessageProcessing() {
|
fun testMimeMessageProcessing() {
|
||||||
val context = InstrumentationRegistry.getTargetContext()
|
val context = InstrumentationRegistry.getTargetContext()
|
||||||
val draft = Draft()
|
val draft = Draft()
|
||||||
|
draft.action_type = Draft.Action.UPDATE_STATUS
|
||||||
draft.timestamp = System.currentTimeMillis()
|
draft.timestamp = System.currentTimeMillis()
|
||||||
draft.account_keys = arrayOf(UserKey("user1", "twitter.com"), UserKey("user2", "twitter.com"))
|
draft.account_keys = arrayOf(UserKey("user1", "twitter.com"), UserKey("user2", "twitter.com"))
|
||||||
draft.text = "Hello world"
|
draft.text = "Hello world 测试"
|
||||||
draft.media = arrayOf(ParcelableMediaUpdate().apply {
|
draft.location = ParcelableLocation(-11.956, 99.625) // Randomly generated
|
||||||
this.uri = "file:///system/media/audio/ringtones/Atria.ogg"
|
draft.media = arrayOf(
|
||||||
this.type = ParcelableMedia.Type.VIDEO
|
"file:///system/media/audio/ringtones/Atria.ogg",
|
||||||
this.alt_text = String(CharArray(420).apply {
|
"file:///system/media/audio/ringtones/Callisto.ogg",
|
||||||
fill('A')
|
"file:///system/media/audio/ringtones/Dione.ogg"
|
||||||
})
|
).map { uri ->
|
||||||
})
|
ParcelableMediaUpdate().apply {
|
||||||
|
this.uri = uri
|
||||||
|
this.type = ParcelableMedia.Type.VIDEO
|
||||||
|
this.alt_text = String(CharArray(420).apply {
|
||||||
|
fill('A')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}.toTypedArray()
|
||||||
val output = ByteArrayOutputStream()
|
val output = ByteArrayOutputStream()
|
||||||
draft.writeMimeMessageTo(context, output)
|
draft.writeMimeMessageTo(context, output)
|
||||||
val input = ByteArrayInputStream(output.toByteArray())
|
val input = ByteArrayInputStream(output.toByteArray())
|
||||||
|
@ -44,10 +51,16 @@ class DraftExtensionsTest {
|
||||||
Assert.assertArrayEquals(draft.account_keys?.sortedArray(), newDraft.account_keys?.sortedArray())
|
Assert.assertArrayEquals(draft.account_keys?.sortedArray(), newDraft.account_keys?.sortedArray())
|
||||||
Assert.assertEquals(TimeUnit.MILLISECONDS.toSeconds(draft.timestamp), TimeUnit.MILLISECONDS.toSeconds(newDraft.timestamp))
|
Assert.assertEquals(TimeUnit.MILLISECONDS.toSeconds(draft.timestamp), TimeUnit.MILLISECONDS.toSeconds(newDraft.timestamp))
|
||||||
Assert.assertEquals(draft.text, newDraft.text)
|
Assert.assertEquals(draft.text, newDraft.text)
|
||||||
|
Assert.assertEquals(draft.location, newDraft.location)
|
||||||
|
Assert.assertEquals(draft.action_type, newDraft.action_type)
|
||||||
|
Assert.assertEquals(draft.action_extras, newDraft.action_extras)
|
||||||
draft.media?.forEachIndexed { idx, expected ->
|
draft.media?.forEachIndexed { idx, expected ->
|
||||||
val actual = newDraft.media!![idx]
|
val actual = newDraft.media!![idx]
|
||||||
Assert.assertEquals(expected.alt_text, actual.alt_text)
|
Assert.assertEquals(expected.alt_text, actual.alt_text)
|
||||||
Assert.assertEquals(expected.type, actual.type)
|
Assert.assertEquals(expected.type, actual.type)
|
||||||
|
val stl = context.contentResolver.openInputStream(Uri.parse(expected.uri))
|
||||||
|
val str = context.contentResolver.openInputStream(Uri.parse(actual.uri))
|
||||||
|
Assert.assertTrue(IOUtils.contentEquals(stl, str))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -29,6 +29,9 @@
|
||||||
<category android:name="android.intent.category.DEFAULT"/>
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name="org.mariotaku.twidere.activity.DropboxAuthStarterActivity"
|
||||||
|
android:theme="@style/Theme.Twidere.NoDisplay"/>
|
||||||
<activity
|
<activity
|
||||||
android:name="com.dropbox.core.android.AuthActivity"
|
android:name="com.dropbox.core.android.AuthActivity"
|
||||||
android:configChanges="orientation|keyboard"
|
android:configChanges="orientation|keyboard"
|
||||||
|
@ -42,5 +45,7 @@
|
||||||
<category android:name="android.intent.category.DEFAULT"/>
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<service android:name="org.mariotaku.twidere.service.DropboxDataSyncService"/>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
|
@ -0,0 +1,16 @@
|
||||||
|
package org.mariotaku.twidere.activity
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import com.dropbox.core.android.Auth
|
||||||
|
import org.mariotaku.twidere.Constants.DROPBOX_APP_KEY
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by mariotaku on 2016/12/7.
|
||||||
|
*/
|
||||||
|
class DropboxAuthStarterActivity : BaseActivity() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
Auth.startOAuth2Authentication(this, DROPBOX_APP_KEY)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package org.mariotaku.twidere.service
|
||||||
|
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.SyncResult
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.IBinder
|
||||||
|
import org.mariotaku.twidere.IDataSyncService
|
||||||
|
import org.mariotaku.twidere.activity.DropboxAuthStarterActivity
|
||||||
|
import org.mariotaku.twidere.model.SyncAuthInfo
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by mariotaku on 2016/12/7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class DropboxDataSyncService : Service() {
|
||||||
|
private val serviceInterface: ServiceInterface
|
||||||
|
|
||||||
|
init {
|
||||||
|
serviceInterface = ServiceInterface(WeakReference(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBind(intent: Intent?): IBinder {
|
||||||
|
return serviceInterface.asBinder()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAuthInfo(): SyncAuthInfo? {
|
||||||
|
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAuthRequestIntent(info: SyncAuthInfo?): Intent {
|
||||||
|
return Intent(this, DropboxAuthStarterActivity::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onPerformSync(info: SyncAuthInfo, extras: Bundle?, syncResult: SyncResult) {
|
||||||
|
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ServiceInterface(val service: WeakReference<DropboxDataSyncService>) : IDataSyncService.Stub() {
|
||||||
|
|
||||||
|
override fun getAuthInfo(): SyncAuthInfo? {
|
||||||
|
return service.get().getAuthInfo()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAuthRequestIntent(info: SyncAuthInfo?): Intent {
|
||||||
|
return service.get().getAuthRequestIntent(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPerformSync(info: SyncAuthInfo, extras: Bundle?, syncResult: SyncResult) {
|
||||||
|
service.get().onPerformSync(info, extras, syncResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ import android.content.Context;
|
||||||
import org.mariotaku.twidere.model.AccountDetails;
|
import org.mariotaku.twidere.model.AccountDetails;
|
||||||
import org.mariotaku.twidere.model.Draft;
|
import org.mariotaku.twidere.model.Draft;
|
||||||
import org.mariotaku.twidere.model.ParcelableStatusUpdate;
|
import org.mariotaku.twidere.model.ParcelableStatusUpdate;
|
||||||
import org.mariotaku.twidere.model.draft.UpdateStatusActionExtra;
|
import org.mariotaku.twidere.model.draft.UpdateStatusActionExtras;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by mariotaku on 16/2/12.
|
* Created by mariotaku on 16/2/12.
|
||||||
|
@ -25,8 +25,8 @@ public class ParcelableStatusUpdateUtils {
|
||||||
statusUpdate.text = draft.text;
|
statusUpdate.text = draft.text;
|
||||||
statusUpdate.location = draft.location;
|
statusUpdate.location = draft.location;
|
||||||
statusUpdate.media = draft.media;
|
statusUpdate.media = draft.media;
|
||||||
if (draft.action_extras instanceof UpdateStatusActionExtra) {
|
if (draft.action_extras instanceof UpdateStatusActionExtras) {
|
||||||
final UpdateStatusActionExtra extra = (UpdateStatusActionExtra) draft.action_extras;
|
final UpdateStatusActionExtras extra = (UpdateStatusActionExtras) draft.action_extras;
|
||||||
statusUpdate.in_reply_to_status = extra.getInReplyToStatus();
|
statusUpdate.in_reply_to_status = extra.getInReplyToStatus();
|
||||||
statusUpdate.is_possibly_sensitive = extra.isPossiblySensitive();
|
statusUpdate.is_possibly_sensitive = extra.isPossiblySensitive();
|
||||||
statusUpdate.display_coordinates = extra.getDisplayCoordinates();
|
statusUpdate.display_coordinates = extra.getDisplayCoordinates();
|
||||||
|
|
|
@ -42,7 +42,7 @@ import org.mariotaku.twidere.model.ParcelableUser;
|
||||||
import org.mariotaku.twidere.model.ParcelableUserMention;
|
import org.mariotaku.twidere.model.ParcelableUserMention;
|
||||||
import org.mariotaku.twidere.model.ParcelableUserValuesCreator;
|
import org.mariotaku.twidere.model.ParcelableUserValuesCreator;
|
||||||
import org.mariotaku.twidere.model.UserKey;
|
import org.mariotaku.twidere.model.UserKey;
|
||||||
import org.mariotaku.twidere.model.draft.SendDirectMessageActionExtra;
|
import org.mariotaku.twidere.model.draft.SendDirectMessageActionExtras;
|
||||||
import org.mariotaku.twidere.model.util.ParcelableActivityExtensionsKt;
|
import org.mariotaku.twidere.model.util.ParcelableActivityExtensionsKt;
|
||||||
import org.mariotaku.twidere.model.util.ParcelableDirectMessageUtils;
|
import org.mariotaku.twidere.model.util.ParcelableDirectMessageUtils;
|
||||||
import org.mariotaku.twidere.model.util.ParcelableStatusUtils;
|
import org.mariotaku.twidere.model.util.ParcelableStatusUtils;
|
||||||
|
@ -121,7 +121,7 @@ public final class ContentValuesCreator implements TwidereConstants {
|
||||||
values.put(Drafts.MEDIA, JsonSerializer.serialize(Arrays.asList(mediaArray),
|
values.put(Drafts.MEDIA, JsonSerializer.serialize(Arrays.asList(mediaArray),
|
||||||
ParcelableMediaUpdate.class));
|
ParcelableMediaUpdate.class));
|
||||||
}
|
}
|
||||||
final SendDirectMessageActionExtra extra = new SendDirectMessageActionExtra();
|
final SendDirectMessageActionExtras extra = new SendDirectMessageActionExtras();
|
||||||
extra.setRecipientId(recipientId);
|
extra.setRecipientId(recipientId);
|
||||||
values.put(Drafts.ACTION_EXTRAS, JsonSerializer.serialize(extra));
|
values.put(Drafts.ACTION_EXTRAS, JsonSerializer.serialize(extra));
|
||||||
return values;
|
return values;
|
||||||
|
|
|
@ -31,7 +31,6 @@ import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.mariotaku.twidere.BuildConfig;
|
import org.mariotaku.twidere.BuildConfig;
|
||||||
import org.mariotaku.twidere.Constants;
|
|
||||||
import org.mariotaku.twidere.IStatusShortener;
|
import org.mariotaku.twidere.IStatusShortener;
|
||||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||||
import org.mariotaku.twidere.model.ParcelableStatusUpdate;
|
import org.mariotaku.twidere.model.ParcelableStatusUpdate;
|
||||||
|
@ -40,8 +39,10 @@ import org.mariotaku.twidere.model.UserKey;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public final class StatusShortenerInterface extends AbsServiceInterface<IStatusShortener>
|
import static org.mariotaku.twidere.TwidereConstants.LOGTAG;
|
||||||
implements Constants {
|
import static org.mariotaku.twidere.constant.IntentConstants.INTENT_ACTION_EXTENSION_SHORTEN_STATUS;
|
||||||
|
|
||||||
|
public final class StatusShortenerInterface extends AbsServiceInterface<IStatusShortener> {
|
||||||
|
|
||||||
protected StatusShortenerInterface(Context context, String shortenerName, Bundle metaData) {
|
protected StatusShortenerInterface(Context context, String shortenerName, Bundle metaData) {
|
||||||
super(context, shortenerName, metaData);
|
super(context, shortenerName, metaData);
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.mariotaku.twidere.util.io;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by mariotaku on 2016/12/8.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public final class CountOnlyOutputStream extends OutputStream {
|
||||||
|
private int count;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(int i) throws IOException {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
|
@ -77,7 +77,7 @@ import org.mariotaku.twidere.constant.KeyboardShortcutConstants
|
||||||
import org.mariotaku.twidere.fragment.BaseDialogFragment
|
import org.mariotaku.twidere.fragment.BaseDialogFragment
|
||||||
import org.mariotaku.twidere.fragment.ProgressDialogFragment
|
import org.mariotaku.twidere.fragment.ProgressDialogFragment
|
||||||
import org.mariotaku.twidere.model.*
|
import org.mariotaku.twidere.model.*
|
||||||
import org.mariotaku.twidere.model.draft.UpdateStatusActionExtra
|
import org.mariotaku.twidere.model.draft.UpdateStatusActionExtras
|
||||||
import org.mariotaku.twidere.model.util.AccountUtils
|
import org.mariotaku.twidere.model.util.AccountUtils
|
||||||
import org.mariotaku.twidere.model.util.ParcelableLocationUtils
|
import org.mariotaku.twidere.model.util.ParcelableLocationUtils
|
||||||
import org.mariotaku.twidere.preference.ServicePickerPreference
|
import org.mariotaku.twidere.preference.ServicePickerPreference
|
||||||
|
@ -178,8 +178,11 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
if (currentTask != null && currentTask!!.status == AsyncTask.Status.RUNNING) return
|
if (currentTask != null && currentTask!!.status == AsyncTask.Status.RUNNING) return
|
||||||
if (hasComposingStatus()) {
|
if (!shouldSkipDraft && hasComposingStatus() ) {
|
||||||
shouldSkipDraft = false
|
saveToDrafts()
|
||||||
|
Toast.makeText(this, R.string.status_saved_to_draft, Toast.LENGTH_SHORT).show()
|
||||||
|
shouldSkipDraft = true
|
||||||
|
finish()
|
||||||
} else {
|
} else {
|
||||||
shouldSkipDraft = true
|
shouldSkipDraft = true
|
||||||
discardTweet()
|
discardTweet()
|
||||||
|
@ -429,7 +432,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
draft.text = text
|
draft.text = text
|
||||||
draft.media = media
|
draft.media = media
|
||||||
draft.location = recentLocation
|
draft.location = recentLocation
|
||||||
draft.action_extras = UpdateStatusActionExtra().apply {
|
draft.timestamp = System.currentTimeMillis()
|
||||||
|
draft.action_extras = UpdateStatusActionExtras().apply {
|
||||||
this.inReplyToStatus = this@ComposeActivity.inReplyToStatus
|
this.inReplyToStatus = this@ComposeActivity.inReplyToStatus
|
||||||
this.isPossiblySensitive = this@ComposeActivity.possiblySensitive
|
this.isPossiblySensitive = this@ComposeActivity.possiblySensitive
|
||||||
}
|
}
|
||||||
|
@ -837,8 +841,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
addMedia(Arrays.asList(*draft.media))
|
addMedia(Arrays.asList(*draft.media))
|
||||||
}
|
}
|
||||||
recentLocation = draft.location
|
recentLocation = draft.location
|
||||||
if (draft.action_extras is UpdateStatusActionExtra) {
|
if (draft.action_extras is UpdateStatusActionExtras) {
|
||||||
val extra = draft.action_extras as UpdateStatusActionExtra?
|
val extra = draft.action_extras as UpdateStatusActionExtras?
|
||||||
possiblySensitive = extra!!.isPossiblySensitive
|
possiblySensitive = extra!!.isPossiblySensitive
|
||||||
inReplyToStatus = extra.inReplyToStatus
|
inReplyToStatus = extra.inReplyToStatus
|
||||||
}
|
}
|
||||||
|
@ -871,16 +875,16 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
}
|
}
|
||||||
when (draft.action_type) {
|
when (draft.action_type) {
|
||||||
Draft.Action.REPLY -> {
|
Draft.Action.REPLY -> {
|
||||||
if (draft.action_extras is UpdateStatusActionExtra) {
|
if (draft.action_extras is UpdateStatusActionExtras) {
|
||||||
showReplyLabel((draft.action_extras as UpdateStatusActionExtra).inReplyToStatus)
|
showReplyLabel((draft.action_extras as UpdateStatusActionExtras).inReplyToStatus)
|
||||||
} else {
|
} else {
|
||||||
hideLabel()
|
hideLabel()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Draft.Action.QUOTE -> {
|
Draft.Action.QUOTE -> {
|
||||||
if (draft.action_extras is UpdateStatusActionExtra) {
|
if (draft.action_extras is UpdateStatusActionExtras) {
|
||||||
showQuoteLabel((draft.action_extras as UpdateStatusActionExtra).inReplyToStatus)
|
showQuoteLabel((draft.action_extras as UpdateStatusActionExtras).inReplyToStatus)
|
||||||
} else {
|
} else {
|
||||||
hideLabel()
|
hideLabel()
|
||||||
return false
|
return false
|
||||||
|
@ -1280,7 +1284,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
update.media = media
|
update.media = media
|
||||||
update.in_reply_to_status = inReplyToStatus
|
update.in_reply_to_status = inReplyToStatus
|
||||||
update.is_possibly_sensitive = isPossiblySensitive
|
update.is_possibly_sensitive = isPossiblySensitive
|
||||||
update.attachment_url = (draft?.action_extras as? UpdateStatusActionExtra)?.attachmentUrl
|
update.attachment_url = (draft?.action_extras as? UpdateStatusActionExtras)?.attachmentUrl
|
||||||
BackgroundOperationService.updateStatusesAsync(this, action, update)
|
BackgroundOperationService.updateStatusesAsync(this, action, update)
|
||||||
if (preferences.getBoolean(KEY_NO_CLOSE_AFTER_TWEET_SENT, false) && inReplyToStatus == null) {
|
if (preferences.getBoolean(KEY_NO_CLOSE_AFTER_TWEET_SENT, false) && inReplyToStatus == null) {
|
||||||
possiblySensitive = false
|
possiblySensitive = false
|
||||||
|
|
|
@ -48,7 +48,7 @@ class DraftsAdapter(context: Context) : SimpleCursorAdapter(context, R.layout.li
|
||||||
private val mediaPreviewStyle: Int
|
private val mediaPreviewStyle: Int
|
||||||
|
|
||||||
private var mTextSize: Float = 0.toFloat()
|
private var mTextSize: Float = 0.toFloat()
|
||||||
private var mIndices: DraftCursorIndices? = null
|
private var indices: DraftCursorIndices? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
GeneralComponentHelper.build(context).inject(this)
|
GeneralComponentHelper.build(context).inject(this)
|
||||||
|
@ -58,7 +58,7 @@ class DraftsAdapter(context: Context) : SimpleCursorAdapter(context, R.layout.li
|
||||||
|
|
||||||
override fun bindView(view: View, context: Context, cursor: Cursor) {
|
override fun bindView(view: View, context: Context, cursor: Cursor) {
|
||||||
val holder = view.tag as DraftViewHolder
|
val holder = view.tag as DraftViewHolder
|
||||||
val indices = mIndices!!
|
val indices = indices!!
|
||||||
val accountKeys = UserKey.arrayOf(cursor.getString(indices.account_keys))
|
val accountKeys = UserKey.arrayOf(cursor.getString(indices.account_keys))
|
||||||
val text = cursor.getString(indices.text)
|
val text = cursor.getString(indices.text)
|
||||||
val mediaUpdates = JsonSerializer.parseArray(cursor.getString(indices.media), ParcelableMediaUpdate::class.java)
|
val mediaUpdates = JsonSerializer.parseArray(cursor.getString(indices.media), ParcelableMediaUpdate::class.java)
|
||||||
|
@ -115,11 +115,16 @@ class DraftsAdapter(context: Context) : SimpleCursorAdapter(context, R.layout.li
|
||||||
override fun swapCursor(c: Cursor?): Cursor? {
|
override fun swapCursor(c: Cursor?): Cursor? {
|
||||||
val old = super.swapCursor(c)
|
val old = super.swapCursor(c)
|
||||||
if (c != null) {
|
if (c != null) {
|
||||||
mIndices = DraftCursorIndices(c)
|
indices = DraftCursorIndices(c)
|
||||||
}
|
}
|
||||||
return old
|
return old
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getDraft(position: Int): Draft {
|
||||||
|
cursor.moveToPosition(position)
|
||||||
|
return indices!!.newObject(cursor)
|
||||||
|
}
|
||||||
|
|
||||||
private fun getActionName(context: Context, actionType: String): String? {
|
private fun getActionName(context: Context, actionType: String): String? {
|
||||||
if (TextUtils.isEmpty(actionType)) return context.getString(R.string.update_status)
|
if (TextUtils.isEmpty(actionType)) return context.getString(R.string.update_status)
|
||||||
when (actionType) {
|
when (actionType) {
|
||||||
|
|
|
@ -2,27 +2,30 @@ package org.mariotaku.twidere.extension
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import com.bluelinelabs.logansquare.LoganSquare
|
||||||
|
import com.nostra13.universalimageloader.utils.IoUtils
|
||||||
import org.apache.james.mime4j.dom.Header
|
import org.apache.james.mime4j.dom.Header
|
||||||
import org.apache.james.mime4j.dom.MessageServiceFactory
|
import org.apache.james.mime4j.dom.MessageServiceFactory
|
||||||
import org.apache.james.mime4j.dom.address.Mailbox
|
import org.apache.james.mime4j.dom.address.Mailbox
|
||||||
import org.apache.james.mime4j.dom.field.*
|
import org.apache.james.mime4j.dom.field.*
|
||||||
import org.apache.james.mime4j.message.AbstractMessage
|
import org.apache.james.mime4j.message.*
|
||||||
import org.apache.james.mime4j.message.BodyPart
|
|
||||||
import org.apache.james.mime4j.message.MultipartImpl
|
|
||||||
import org.apache.james.mime4j.message.SimpleContentHandler
|
|
||||||
import org.apache.james.mime4j.parser.MimeStreamParser
|
import org.apache.james.mime4j.parser.MimeStreamParser
|
||||||
import org.apache.james.mime4j.storage.StorageBodyFactory
|
import org.apache.james.mime4j.storage.StorageBodyFactory
|
||||||
import org.apache.james.mime4j.stream.BodyDescriptor
|
import org.apache.james.mime4j.stream.BodyDescriptor
|
||||||
import org.apache.james.mime4j.stream.MimeConfig
|
import org.apache.james.mime4j.stream.MimeConfig
|
||||||
|
import org.apache.james.mime4j.stream.RawField
|
||||||
|
import org.apache.james.mime4j.util.MimeUtil
|
||||||
import org.mariotaku.ktextension.convert
|
import org.mariotaku.ktextension.convert
|
||||||
import org.mariotaku.ktextension.toInt
|
import org.mariotaku.ktextension.toInt
|
||||||
import org.mariotaku.ktextension.toString
|
import org.mariotaku.ktextension.toString
|
||||||
import org.mariotaku.twidere.extension.model.getMimeType
|
import org.mariotaku.twidere.extension.model.getMimeType
|
||||||
import org.mariotaku.twidere.model.Draft
|
import org.mariotaku.twidere.model.*
|
||||||
import org.mariotaku.twidere.model.ParcelableMedia
|
import org.mariotaku.twidere.model.Draft.Action
|
||||||
import org.mariotaku.twidere.model.ParcelableMediaUpdate
|
import org.mariotaku.twidere.model.draft.SendDirectMessageActionExtras
|
||||||
import org.mariotaku.twidere.model.UserKey
|
import org.mariotaku.twidere.model.draft.UpdateStatusActionExtras
|
||||||
import org.mariotaku.twidere.util.collection.NonEmptyHashMap
|
import org.mariotaku.twidere.util.collection.NonEmptyHashMap
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
|
@ -45,44 +48,64 @@ fun Draft.writeMimeMessageTo(context: Context, st: OutputStream) {
|
||||||
|
|
||||||
message.date = Date(this.timestamp)
|
message.date = Date(this.timestamp)
|
||||||
message.setFrom(this.account_keys?.map { Mailbox(it.id, it.host) })
|
message.setFrom(this.account_keys?.map { Mailbox(it.id, it.host) })
|
||||||
|
if (message.header == null) {
|
||||||
|
message.header = HeaderImpl()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.location?.let { location ->
|
||||||
|
message.header.addField(RawField("X-GeoLocation", location.toString()))
|
||||||
|
}
|
||||||
|
this.action_type?.let { type ->
|
||||||
|
message.header.addField(RawField("X-Action-Type", type))
|
||||||
|
}
|
||||||
|
|
||||||
val multipart = MultipartImpl("mixed")
|
val multipart = MultipartImpl("mixed")
|
||||||
multipart.addBodyPart(BodyPart().apply {
|
multipart.addBodyPart(BodyPart().apply {
|
||||||
setText(bodyFactory.textBody(this@writeMimeMessageTo.text))
|
setText(bodyFactory.textBody(this@writeMimeMessageTo.text, Charsets.UTF_8.name()))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.action_extras?.let { extras ->
|
||||||
|
multipart.addBodyPart(BodyPart().apply {
|
||||||
|
setText(bodyFactory.textBody(LoganSquare.serialize(extras)), "json")
|
||||||
|
this.filename = "twidere.action.extras.json"
|
||||||
|
})
|
||||||
|
}
|
||||||
this.media?.forEach { mediaItem ->
|
this.media?.forEach { mediaItem ->
|
||||||
multipart.addBodyPart(BodyPart().apply {
|
multipart.addBodyPart(BodyPart().apply {
|
||||||
val uri = Uri.parse(mediaItem.uri)
|
val uri = Uri.parse(mediaItem.uri)
|
||||||
val storage = storageProvider.store(contentResolver.openInputStream(uri))
|
|
||||||
val mimeType = mediaItem.getMimeType(contentResolver) ?: "application/octet-stream"
|
val mimeType = mediaItem.getMimeType(contentResolver) ?: "application/octet-stream"
|
||||||
val parameters = NonEmptyHashMap<String, String?>()
|
val parameters = NonEmptyHashMap<String, String?>()
|
||||||
parameters["alt_text"] = mediaItem.alt_text
|
parameters["alt_text"] = mediaItem.alt_text
|
||||||
parameters["media_type"] = mediaItem.type.toString()
|
parameters["media_type"] = mediaItem.type.toString()
|
||||||
this.setBody(bodyFactory.binaryBody(storage), mimeType, parameters)
|
val storage = storageProvider.store(contentResolver.openInputStream(uri))
|
||||||
this.filename = uri.lastPathSegment
|
this.filename = uri.lastPathSegment
|
||||||
|
this.contentTransferEncoding = MimeUtil.ENC_BASE64
|
||||||
|
this.setBody(bodyFactory.binaryBody(storage), mimeType, parameters)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
message.setMultipart(multipart)
|
message.setMultipart(multipart)
|
||||||
writer.writeMessage(message, st)
|
writer.writeMessage(message, st)
|
||||||
|
st.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Draft.readMimeMessageFrom(context: Context, st: InputStream) {
|
fun Draft.readMimeMessageFrom(context: Context, st: InputStream) {
|
||||||
val config = MimeConfig()
|
val config = MimeConfig()
|
||||||
val parser = MimeStreamParser(config)
|
val parser = MimeStreamParser(config)
|
||||||
parser.setContentHandler(DraftContentHandler(this))
|
parser.isContentDecoding = true
|
||||||
|
parser.setContentHandler(DraftContentHandler(context, this))
|
||||||
parser.parse(st)
|
parser.parse(st)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DraftContentHandler(private val draft: Draft) : SimpleContentHandler() {
|
private class DraftContentHandler(private val context: Context, private val draft: Draft) : SimpleContentHandler() {
|
||||||
private val processingStack = Stack<SimpleContentHandler>()
|
private val processingStack = Stack<SimpleContentHandler>()
|
||||||
private val mediaList: MutableList<ParcelableMediaUpdate> = ArrayList()
|
private val mediaList: MutableList<ParcelableMediaUpdate> = ArrayList()
|
||||||
override fun headers(header: Header) {
|
override fun headers(header: Header) {
|
||||||
if (processingStack.isEmpty()) {
|
if (processingStack.isEmpty()) {
|
||||||
draft.timestamp = header.getField("Date").convert {
|
draft.timestamp = header.getField("Date")?.convert {
|
||||||
(it as DateTimeField).date.time
|
(it as DateTimeField).date.time
|
||||||
}
|
} ?: 0
|
||||||
draft.account_keys = header.getField("From").convert { field ->
|
draft.account_keys = header.getField("From")?.convert { field ->
|
||||||
when (field) {
|
when (field) {
|
||||||
is MailboxField -> {
|
is MailboxField -> {
|
||||||
return@convert arrayOf(field.mailbox.convert { UserKey(it.localPart, it.domain) })
|
return@convert arrayOf(field.mailbox.convert { UserKey(it.localPart, it.domain) })
|
||||||
|
@ -95,6 +118,8 @@ private class DraftContentHandler(private val draft: Draft) : SimpleContentHandl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
draft.location = header.getField("X-GeoLocation")?.body?.convert(ParcelableLocation::valueOf)
|
||||||
|
draft.action_type = header.getField("X-Action-Type")?.body
|
||||||
} else {
|
} else {
|
||||||
processingStack.peek().headers(header)
|
processingStack.peek().headers(header)
|
||||||
}
|
}
|
||||||
|
@ -108,7 +133,7 @@ private class DraftContentHandler(private val draft: Draft) : SimpleContentHandl
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun startBodyPart() {
|
override fun startBodyPart() {
|
||||||
processingStack.push(BodyPartHandler(draft))
|
processingStack.push(BodyPartHandler(context, draft))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun body(bd: BodyDescriptor?, `is`: InputStream?) {
|
override fun body(bd: BodyDescriptor?, `is`: InputStream?) {
|
||||||
|
@ -131,7 +156,7 @@ private class DraftContentHandler(private val draft: Draft) : SimpleContentHandl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BodyPartHandler(private val draft: Draft) : SimpleContentHandler() {
|
private class BodyPartHandler(private val context: Context, private val draft: Draft) : SimpleContentHandler() {
|
||||||
internal lateinit var header: Header
|
internal lateinit var header: Header
|
||||||
internal var media: ParcelableMediaUpdate? = null
|
internal var media: ParcelableMediaUpdate? = null
|
||||||
|
|
||||||
|
@ -147,11 +172,32 @@ private class BodyPartHandler(private val draft: Draft) : SimpleContentHandler()
|
||||||
val contentDisposition = header.getField("Content-Disposition") as? ContentDispositionField
|
val contentDisposition = header.getField("Content-Disposition") as? ContentDispositionField
|
||||||
if (contentDisposition != null && contentDisposition.isAttachment) {
|
if (contentDisposition != null && contentDisposition.isAttachment) {
|
||||||
when (contentDisposition.filename) {
|
when (contentDisposition.filename) {
|
||||||
|
"twidere.action.extras.json" -> {
|
||||||
|
draft.action_extras = when (draft.action_type) {
|
||||||
|
"0", "1", Action.UPDATE_STATUS, Action.REPLY, Action.QUOTE -> {
|
||||||
|
LoganSquare.parse(st, UpdateStatusActionExtras::class.java)
|
||||||
|
}
|
||||||
|
"2", Action.SEND_DIRECT_MESSAGE -> {
|
||||||
|
LoganSquare.parse(st, SendDirectMessageActionExtras::class.java)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val contentType = header.getField("Content-Type") as? ContentTypeField
|
val contentType = header.getField("Content-Type") as? ContentTypeField
|
||||||
|
val filename = contentDisposition.filename ?: return
|
||||||
|
val mediaFile = File(context.filesDir, filename)
|
||||||
media = ParcelableMediaUpdate().apply {
|
media = ParcelableMediaUpdate().apply {
|
||||||
|
bd.transferEncoding
|
||||||
this.type = contentType?.getParameter("media_type").toInt(ParcelableMedia.Type.UNKNOWN)
|
this.type = contentType?.getParameter("media_type").toInt(ParcelableMedia.Type.UNKNOWN)
|
||||||
this.alt_text = contentType?.getParameter("alt_text")
|
this.alt_text = contentType?.getParameter("alt_text")
|
||||||
|
FileOutputStream(mediaFile).use {
|
||||||
|
IoUtils.copyStream(st, it, null)
|
||||||
|
it.flush()
|
||||||
|
}
|
||||||
|
this.uri = Uri.fromFile(mediaFile).toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,11 @@ import android.content.DialogInterface
|
||||||
import android.content.DialogInterface.OnClickListener
|
import android.content.DialogInterface.OnClickListener
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
|
import android.media.MediaScannerConnection
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.AsyncTask
|
import android.os.AsyncTask
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.os.Environment
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.support.v4.app.DialogFragment
|
import android.support.v4.app.DialogFragment
|
||||||
import android.support.v4.app.FragmentActivity
|
import android.support.v4.app.FragmentActivity
|
||||||
|
@ -43,7 +45,10 @@ import android.widget.AbsListView.MultiChoiceModeListener
|
||||||
import android.widget.AdapterView
|
import android.widget.AdapterView
|
||||||
import android.widget.AdapterView.OnItemClickListener
|
import android.widget.AdapterView.OnItemClickListener
|
||||||
import android.widget.ListView
|
import android.widget.ListView
|
||||||
|
import android.widget.Toast
|
||||||
import kotlinx.android.synthetic.main.fragment_drafts.*
|
import kotlinx.android.synthetic.main.fragment_drafts.*
|
||||||
|
import nl.komponents.kovenant.task
|
||||||
|
import nl.komponents.kovenant.ui.successUi
|
||||||
import org.mariotaku.sqliteqb.library.Columns.Column
|
import org.mariotaku.sqliteqb.library.Columns.Column
|
||||||
import org.mariotaku.sqliteqb.library.Expression
|
import org.mariotaku.sqliteqb.library.Expression
|
||||||
import org.mariotaku.sqliteqb.library.RawItemArray
|
import org.mariotaku.sqliteqb.library.RawItemArray
|
||||||
|
@ -52,10 +57,10 @@ import org.mariotaku.twidere.TwidereConstants.*
|
||||||
import org.mariotaku.twidere.activity.iface.IExtendedActivity
|
import org.mariotaku.twidere.activity.iface.IExtendedActivity
|
||||||
import org.mariotaku.twidere.adapter.DraftsAdapter
|
import org.mariotaku.twidere.adapter.DraftsAdapter
|
||||||
import org.mariotaku.twidere.constant.IntentConstants
|
import org.mariotaku.twidere.constant.IntentConstants
|
||||||
|
import org.mariotaku.twidere.extension.writeMimeMessageTo
|
||||||
import org.mariotaku.twidere.model.Draft
|
import org.mariotaku.twidere.model.Draft
|
||||||
import org.mariotaku.twidere.model.DraftCursorIndices
|
|
||||||
import org.mariotaku.twidere.model.ParcelableMediaUpdate
|
import org.mariotaku.twidere.model.ParcelableMediaUpdate
|
||||||
import org.mariotaku.twidere.model.draft.SendDirectMessageActionExtra
|
import org.mariotaku.twidere.model.draft.SendDirectMessageActionExtras
|
||||||
import org.mariotaku.twidere.model.util.ParcelableStatusUpdateUtils
|
import org.mariotaku.twidere.model.util.ParcelableStatusUpdateUtils
|
||||||
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts
|
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts
|
||||||
import org.mariotaku.twidere.service.BackgroundOperationService
|
import org.mariotaku.twidere.service.BackgroundOperationService
|
||||||
|
@ -63,6 +68,7 @@ import org.mariotaku.twidere.util.AsyncTaskUtils
|
||||||
import org.mariotaku.twidere.util.JsonSerializer
|
import org.mariotaku.twidere.util.JsonSerializer
|
||||||
import org.mariotaku.twidere.util.Utils.getDefaultTextSize
|
import org.mariotaku.twidere.util.Utils.getDefaultTextSize
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.io.FileOutputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class DraftsFragment : BaseSupportFragment(), LoaderCallbacks<Cursor?>, OnItemClickListener, MultiChoiceModeListener {
|
class DraftsFragment : BaseSupportFragment(), LoaderCallbacks<Cursor?>, OnItemClickListener, MultiChoiceModeListener {
|
||||||
|
@ -85,27 +91,52 @@ class DraftsFragment : BaseSupportFragment(), LoaderCallbacks<Cursor?>, OnItemCl
|
||||||
R.id.delete -> {
|
R.id.delete -> {
|
||||||
val f = DeleteDraftsConfirmDialogFragment()
|
val f = DeleteDraftsConfirmDialogFragment()
|
||||||
val args = Bundle()
|
val args = Bundle()
|
||||||
args.putLongArray(IntentConstants.EXTRA_IDS, listView!!.checkedItemIds)
|
args.putLongArray(IntentConstants.EXTRA_IDS, listView.checkedItemIds)
|
||||||
f.arguments = args
|
f.arguments = args
|
||||||
f.show(childFragmentManager, "delete_drafts_confirm")
|
f.show(childFragmentManager, "delete_drafts_confirm")
|
||||||
}
|
}
|
||||||
R.id.send -> {
|
R.id.send -> {
|
||||||
val c = adapter!!.cursor
|
val checked = listView.checkedItemPositions
|
||||||
if (c == null || c.isClosed) return false
|
|
||||||
val checked = listView!!.checkedItemPositions
|
|
||||||
val list = ArrayList<Draft>()
|
val list = ArrayList<Draft>()
|
||||||
val indices = DraftCursorIndices(c)
|
|
||||||
for (i in 0 until checked.size()) {
|
for (i in 0 until checked.size()) {
|
||||||
if (checked.valueAt(i) && c.moveToPosition(checked.keyAt(i))) {
|
val position = checked.keyAt(i)
|
||||||
list.add(indices.newObject(c))
|
if (checked.valueAt(i)) {
|
||||||
|
list.add(adapter!!.getDraft(position))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sendDrafts(list)) {
|
if (sendDrafts(list)) {
|
||||||
val where = Expression.`in`(Column(Drafts._ID),
|
val where = Expression.`in`(Column(Drafts._ID),
|
||||||
RawItemArray(listView!!.checkedItemIds))
|
RawItemArray(listView.checkedItemIds))
|
||||||
contentResolver.delete(Drafts.CONTENT_URI, where.sql, null)
|
contentResolver.delete(Drafts.CONTENT_URI, where.sql, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
R.id.save -> {
|
||||||
|
val checked = listView.checkedItemPositions
|
||||||
|
val drafts = ArrayList<Draft>()
|
||||||
|
for (i in 0 until checked.size()) {
|
||||||
|
val position = checked.keyAt(i)
|
||||||
|
if (checked.valueAt(i)) {
|
||||||
|
drafts.add(adapter!!.getDraft(position))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
task {
|
||||||
|
val pubDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
|
||||||
|
val paths = drafts.map { draft ->
|
||||||
|
val name = "${draft.timestamp}.eml"
|
||||||
|
val destFile = File(pubDir, name)
|
||||||
|
FileOutputStream(destFile).use {
|
||||||
|
draft.writeMimeMessageTo(context, it)
|
||||||
|
it.flush()
|
||||||
|
}
|
||||||
|
return@map destFile.absolutePath
|
||||||
|
}
|
||||||
|
MediaScannerConnection.scanFile(context, paths.toTypedArray(), null, null)
|
||||||
|
}.successUi {
|
||||||
|
Toast.makeText(context, R.string.draft_saved, Toast.LENGTH_SHORT).show()
|
||||||
|
}.fail { ex ->
|
||||||
|
Log.w(LOGTAG, ex)
|
||||||
|
}
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -140,9 +171,7 @@ class DraftsFragment : BaseSupportFragment(), LoaderCallbacks<Cursor?>, OnItemCl
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemClick(view: AdapterView<*>, child: View, position: Int, id: Long) {
|
override fun onItemClick(view: AdapterView<*>, child: View, position: Int, id: Long) {
|
||||||
val c = adapter!!.cursor
|
val item = adapter!!.getDraft(position)
|
||||||
if (c == null || c.isClosed || !c.moveToPosition(position)) return
|
|
||||||
val item = DraftCursorIndices.fromCursor(c)
|
|
||||||
if (TextUtils.isEmpty(item.action_type)) {
|
if (TextUtils.isEmpty(item.action_type)) {
|
||||||
editDraft(item)
|
editDraft(item)
|
||||||
return
|
return
|
||||||
|
@ -162,13 +191,13 @@ class DraftsFragment : BaseSupportFragment(), LoaderCallbacks<Cursor?>, OnItemCl
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
adapter = DraftsAdapter(activity)
|
adapter = DraftsAdapter(activity)
|
||||||
adapter!!.setTextSize(preferences.getInt(KEY_TEXT_SIZE, getDefaultTextSize(activity)).toFloat())
|
adapter!!.setTextSize(preferences.getInt(KEY_TEXT_SIZE, getDefaultTextSize(activity)).toFloat())
|
||||||
listView!!.adapter = adapter
|
listView.adapter = adapter
|
||||||
listView!!.emptyView = emptyView
|
listView.emptyView = emptyView
|
||||||
listView!!.onItemClickListener = this
|
listView.onItemClickListener = this
|
||||||
listView!!.choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL
|
listView.choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL
|
||||||
listView!!.setMultiChoiceModeListener(this)
|
listView.setMultiChoiceModeListener(this)
|
||||||
emptyIcon!!.setImageResource(R.drawable.ic_info_draft)
|
emptyIcon.setImageResource(R.drawable.ic_info_draft)
|
||||||
emptyText!!.setText(R.string.drafts_hint_messages)
|
emptyText.setText(R.string.drafts_hint_messages)
|
||||||
loaderManager.initLoader(0, null, this)
|
loaderManager.initLoader(0, null, this)
|
||||||
setListShown(false)
|
setListShown(false)
|
||||||
}
|
}
|
||||||
|
@ -207,8 +236,8 @@ class DraftsFragment : BaseSupportFragment(), LoaderCallbacks<Cursor?>, OnItemCl
|
||||||
}
|
}
|
||||||
Draft.Action.SEND_DIRECT_MESSAGE_COMPAT, Draft.Action.SEND_DIRECT_MESSAGE -> {
|
Draft.Action.SEND_DIRECT_MESSAGE_COMPAT, Draft.Action.SEND_DIRECT_MESSAGE -> {
|
||||||
var recipientId: String? = null
|
var recipientId: String? = null
|
||||||
if (item.action_extras is SendDirectMessageActionExtra) {
|
if (item.action_extras is SendDirectMessageActionExtras) {
|
||||||
recipientId = (item.action_extras as SendDirectMessageActionExtra).recipientId
|
recipientId = (item.action_extras as SendDirectMessageActionExtras).recipientId
|
||||||
}
|
}
|
||||||
if (item.account_keys?.isEmpty() ?: true || recipientId == null) {
|
if (item.account_keys?.isEmpty() ?: true || recipientId == null) {
|
||||||
continue@loop
|
continue@loop
|
||||||
|
@ -224,7 +253,7 @@ class DraftsFragment : BaseSupportFragment(), LoaderCallbacks<Cursor?>, OnItemCl
|
||||||
|
|
||||||
private fun updateTitle(mode: ActionMode?) {
|
private fun updateTitle(mode: ActionMode?) {
|
||||||
if (listView == null || mode == null) return
|
if (listView == null || mode == null) return
|
||||||
val count = listView!!.checkedItemCount
|
val count = listView.checkedItemCount
|
||||||
mode.title = resources.getQuantityString(R.plurals.Nitems_selected, count, count)
|
mode.title = resources.getQuantityString(R.plurals.Nitems_selected, count, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -199,7 +199,7 @@ object ParcelableStatusUtils {
|
||||||
private fun getPlaceFullName(status: Status): String? {
|
private fun getPlaceFullName(status: Status): String? {
|
||||||
val place = status.place
|
val place = status.place
|
||||||
if (place != null) return place.fullName
|
if (place != null) return place.fullName
|
||||||
val location = status.location
|
val location = status.location ?: return null
|
||||||
if (ParcelableLocation.valueOf(location) == null) {
|
if (ParcelableLocation.valueOf(location) == null) {
|
||||||
return location
|
return location
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ object ParcelableStatusUtils {
|
||||||
if (geoLocation != null) {
|
if (geoLocation != null) {
|
||||||
return ParcelableLocationUtils.fromGeoLocation(geoLocation)
|
return ParcelableLocationUtils.fromGeoLocation(geoLocation)
|
||||||
}
|
}
|
||||||
val locationString = status.location
|
val locationString = status.location ?: return null
|
||||||
val location = ParcelableLocation.valueOf(locationString)
|
val location = ParcelableLocation.valueOf(locationString)
|
||||||
if (location != null) {
|
if (location != null) {
|
||||||
return location
|
return location
|
||||||
|
|
|
@ -31,7 +31,6 @@ class AccountAuthenticatorService : Service() {
|
||||||
|
|
||||||
internal class TwidereAccountAuthenticator(val context: Context) : AbstractAccountAuthenticator(context) {
|
internal class TwidereAccountAuthenticator(val context: Context) : AbstractAccountAuthenticator(context) {
|
||||||
|
|
||||||
// TODO: Make SignInActivity comply with AccountAuthenticatorActivity
|
|
||||||
override fun addAccount(response: AccountAuthenticatorResponse, accountType: String,
|
override fun addAccount(response: AccountAuthenticatorResponse, accountType: String,
|
||||||
authTokenType: String?, requiredFeatures: Array<String>?,
|
authTokenType: String?, requiredFeatures: Array<String>?,
|
||||||
options: Bundle?): Bundle {
|
options: Bundle?): Bundle {
|
||||||
|
|
|
@ -62,7 +62,7 @@ import org.mariotaku.twidere.TwidereConstants.*
|
||||||
import org.mariotaku.twidere.annotation.AccountType
|
import org.mariotaku.twidere.annotation.AccountType
|
||||||
import org.mariotaku.twidere.extension.newMicroBlogInstance
|
import org.mariotaku.twidere.extension.newMicroBlogInstance
|
||||||
import org.mariotaku.twidere.model.*
|
import org.mariotaku.twidere.model.*
|
||||||
import org.mariotaku.twidere.model.draft.SendDirectMessageActionExtra
|
import org.mariotaku.twidere.model.draft.SendDirectMessageActionExtras
|
||||||
import org.mariotaku.twidere.model.util.AccountUtils
|
import org.mariotaku.twidere.model.util.AccountUtils
|
||||||
import org.mariotaku.twidere.model.util.ParcelableDirectMessageUtils
|
import org.mariotaku.twidere.model.util.ParcelableDirectMessageUtils
|
||||||
import org.mariotaku.twidere.model.util.ParcelableStatusUpdateUtils
|
import org.mariotaku.twidere.model.util.ParcelableStatusUpdateUtils
|
||||||
|
@ -173,7 +173,7 @@ class BackgroundOperationService : IntentService("background_operation"), Consta
|
||||||
updateStatuses(item.action_type, ParcelableStatusUpdateUtils.fromDraftItem(this, item))
|
updateStatuses(item.action_type, ParcelableStatusUpdateUtils.fromDraftItem(this, item))
|
||||||
}
|
}
|
||||||
Draft.Action.SEND_DIRECT_MESSAGE_COMPAT, Draft.Action.SEND_DIRECT_MESSAGE -> {
|
Draft.Action.SEND_DIRECT_MESSAGE_COMPAT, Draft.Action.SEND_DIRECT_MESSAGE -> {
|
||||||
val recipientId = (item.action_extras as? SendDirectMessageActionExtra)?.recipientId ?: return
|
val recipientId = (item.action_extras as? SendDirectMessageActionExtras)?.recipientId ?: return
|
||||||
if (item.account_keys?.isEmpty() ?: true) {
|
if (item.account_keys?.isEmpty() ?: true) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ import org.mariotaku.twidere.TwidereConstants.*
|
||||||
import org.mariotaku.twidere.annotation.AccountType
|
import org.mariotaku.twidere.annotation.AccountType
|
||||||
import org.mariotaku.twidere.app.TwidereApplication
|
import org.mariotaku.twidere.app.TwidereApplication
|
||||||
import org.mariotaku.twidere.model.*
|
import org.mariotaku.twidere.model.*
|
||||||
import org.mariotaku.twidere.model.draft.UpdateStatusActionExtra
|
import org.mariotaku.twidere.model.draft.UpdateStatusActionExtras
|
||||||
import org.mariotaku.twidere.model.util.ParcelableLocationUtils
|
import org.mariotaku.twidere.model.util.ParcelableLocationUtils
|
||||||
import org.mariotaku.twidere.model.util.ParcelableStatusUtils
|
import org.mariotaku.twidere.model.util.ParcelableStatusUtils
|
||||||
import org.mariotaku.twidere.preference.ServicePickerPreference
|
import org.mariotaku.twidere.preference.ServicePickerPreference
|
||||||
|
@ -519,7 +519,8 @@ class UpdateStatusTask(
|
||||||
draft.text = statusUpdate.text
|
draft.text = statusUpdate.text
|
||||||
draft.location = statusUpdate.location
|
draft.location = statusUpdate.location
|
||||||
draft.media = statusUpdate.media
|
draft.media = statusUpdate.media
|
||||||
draft.action_extras = UpdateStatusActionExtra().apply {
|
draft.timestamp = System.currentTimeMillis()
|
||||||
|
draft.action_extras = UpdateStatusActionExtras().apply {
|
||||||
inReplyToStatus = statusUpdate.in_reply_to_status
|
inReplyToStatus = statusUpdate.in_reply_to_status
|
||||||
isPossiblySensitive = statusUpdate.is_possibly_sensitive
|
isPossiblySensitive = statusUpdate.is_possibly_sensitive
|
||||||
isRepostStatusId = statusUpdate.repost_status_id
|
isRepostStatusId = statusUpdate.repost_status_id
|
||||||
|
|
|
@ -5,12 +5,17 @@
|
||||||
<item
|
<item
|
||||||
android:id="@id/delete"
|
android:id="@id/delete"
|
||||||
android:icon="@drawable/ic_action_delete"
|
android:icon="@drawable/ic_action_delete"
|
||||||
app:showAsAction="ifRoom|withText"
|
android:title="@string/delete"
|
||||||
android:title="@string/delete"/>
|
app:showAsAction="ifRoom|withText"/>
|
||||||
<item
|
<item
|
||||||
android:id="@id/send"
|
android:id="@id/send"
|
||||||
android:icon="@drawable/ic_action_send"
|
android:icon="@drawable/ic_action_send"
|
||||||
app:showAsAction="ifRoom|withText"
|
android:title="@string/send"
|
||||||
android:title="@string/send"/>
|
app:showAsAction="ifRoom|withText"/>
|
||||||
|
<item
|
||||||
|
android:id="@id/save"
|
||||||
|
android:enabled="@bool/debug"
|
||||||
|
android:icon="@drawable/ic_action_save"
|
||||||
|
android:title="@string/save"
|
||||||
|
android:visible="@bool/debug"/>
|
||||||
</menu>
|
</menu>
|
Loading…
Reference in New Issue