1
0
mirror of https://github.com/TwidereProject/Twidere-Android synced 2025-02-17 04:00:48 +01:00

migrating to kotlin

This commit is contained in:
Mariotaku Lee 2016-07-02 11:54:53 +08:00
parent ad612d5a5b
commit 23494b009f
135 changed files with 9416 additions and 10941 deletions

View File

@ -3,6 +3,7 @@ package org.mariotaku.twidere.model;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
@ -20,6 +21,7 @@ public class ParcelableMediaUpdate implements Parcelable {
public int type;
@JsonField(name = "alt_text")
@Nullable
public String alt_text;
public ParcelableMediaUpdate() {

View File

@ -10,7 +10,7 @@ apply plugin: 'io.fabric'
// END Non-FOSS component
buildscript {
ext.kotlin_version = '1.0.2-1'
ext.kotlin_version = '1.0.3'
repositories {
jcenter()

View File

@ -1,38 +1,37 @@
package org.mariotaku.twidere.activity;
package org.mariotaku.twidere.activity
import android.net.Uri;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import android.net.Uri
import org.junit.Assert.assertEquals
import org.junit.Test
/**
* Created by mariotaku on 16/3/3.
*/
public class ImagePageFragmentTest {
class ImagePageFragmentTest {
@Test
public void testReplaceTwitterMediaUri() throws Exception {
@Throws(Exception::class)
fun testReplaceTwitterMediaUri() {
assertEquals("https://pbs.twimg.com/media/DEADBEEF.png:large",
MediaViewerActivity.ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
"https://pbs.twimg.com/media/DEADBEEF.png:large")).toString());
"https://pbs.twimg.com/media/DEADBEEF.png:large")).toString())
assertEquals("https://pbs.twimg.com/media/DEADBEEF.png:orig",
MediaViewerActivity.ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
"https://pbs.twimg.com/media/DEADBEEF.png:orig")).toString());
"https://pbs.twimg.com/media/DEADBEEF.png:orig")).toString())
assertEquals("https://pbs.twimg.com/media/DEADBEEF.png:large",
MediaViewerActivity.ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
"https://pbs.twimg.com/media/DEADBEEF.jpg:large")).toString());
"https://pbs.twimg.com/media/DEADBEEF.jpg:large")).toString())
assertEquals("https://pbs.twimg.com/media/DEADBEEF.png:large",
MediaViewerActivity.ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
"https://pbs.twimg.com/media/DEADBEEF.jpg:orig")).toString());
"https://pbs.twimg.com/media/DEADBEEF.jpg:orig")).toString())
assertEquals("https://pbs.twimg.com/media/DEADBEEF.png",
MediaViewerActivity.ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
"https://pbs.twimg.com/media/DEADBEEF.jpg")).toString());
"https://pbs.twimg.com/media/DEADBEEF.jpg")).toString())
assertEquals("https://pbs.twimg.com/media/DEADBEEF.png:",
MediaViewerActivity.ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
"https://pbs.twimg.com/media/DEADBEEF.jpg:")).toString());
"https://pbs.twimg.com/media/DEADBEEF.jpg:")).toString())
assertEquals("https://example.com/media/DEADBEEF.jpg",
MediaViewerActivity.ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
"https://example.com/media/DEADBEEF.jpg")).toString());
"https://example.com/media/DEADBEEF.jpg")).toString())
}
}

View File

@ -1,26 +0,0 @@
package org.mariotaku.twidere.model;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* Created by mariotaku on 16/3/9.
*/
public class UserKeyTest {
@Test
public void testToString() throws Exception {
assertEquals("abc@twitter.com", new UserKey("abc", "twitter.com").toString());
assertEquals("\\@user@twitter.com", new UserKey("@user", "twitter.com").toString());
assertEquals("\\@u\\\\ser@twitter.com", new UserKey("@u\\ser", "twitter.com").toString());
}
@Test
public void testValueOf() throws Exception {
assertEquals(new UserKey("abc", "twitter.com"), UserKey.valueOf("abc@twitter.com"));
assertEquals(new UserKey("abc@", "twitter.com"), UserKey.valueOf("abc\\@@twitter.com"));
assertEquals(new UserKey("abc@", "twitter.com"), UserKey.valueOf("a\\bc\\@@twitter.com"));
assertEquals(new UserKey("a\\bc@", "twitter.com"), UserKey.valueOf("a\\\\bc\\@@twitter.com"));
}
}

View File

@ -0,0 +1,28 @@
package org.mariotaku.twidere.model
import org.junit.Test
import org.junit.Assert.assertEquals
/**
* Created by mariotaku on 16/3/9.
*/
class UserKeyTest {
@Test
@Throws(Exception::class)
fun testToString() {
assertEquals("abc@twitter.com", UserKey("abc", "twitter.com").toString())
assertEquals("\\@user@twitter.com", UserKey("@user", "twitter.com").toString())
assertEquals("\\@u\\\\ser@twitter.com", UserKey("@u\\ser", "twitter.com").toString())
}
@Test
@Throws(Exception::class)
fun testValueOf() {
assertEquals(UserKey("abc", "twitter.com"), UserKey.valueOf("abc@twitter.com"))
assertEquals(UserKey("abc@", "twitter.com"), UserKey.valueOf("abc\\@@twitter.com"))
assertEquals(UserKey("abc@", "twitter.com"), UserKey.valueOf("a\\bc\\@@twitter.com"))
assertEquals(UserKey("a\\bc@", "twitter.com"), UserKey.valueOf("a\\\\bc\\@@twitter.com"))
}
}

View File

@ -1,24 +1,24 @@
package org.mariotaku.twidere.task;
package org.mariotaku.twidere.task
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import org.junit.Assert.assertEquals
import org.junit.Test
/**
* Created by mariotaku on 16/3/2.
*/
public class SaveFileTaskTest {
class SaveFileTaskTest {
@Test
public void testGetFileNameWithExtension() throws Exception {
@Throws(Exception::class)
fun testGetFileNameWithExtension() {
assertEquals("pbs_twimg_com_media_abcdefghijklmn.jpg",
SaveFileTask.getFileNameWithExtension("pbs_twimg_com_media_abcdefghijklmn_jpg",
"jpg", '_', null));
"jpg", '_', null))
assertEquals("pbs_twimg_com_media_abcdefghijklmn_jpg",
SaveFileTask.getFileNameWithExtension("pbs_twimg_com_media_abcdefghijklmn_jpg",
null, '_', null));
null, '_', null))
assertEquals("pbs_twimg_com_media_abcdefghijklmn_jpgsuffix",
SaveFileTask.getFileNameWithExtension("pbs_twimg_com_media_abcdefghijklmn_jpg",
null, '_', "suffix"));
null, '_', "suffix"))
}
}

View File

@ -1,30 +1,31 @@
package org.mariotaku.twidere.util;
package org.mariotaku.twidere.util
import org.junit.Test;
import org.junit.Test
import static org.junit.Assert.assertEquals;
import org.junit.Assert.assertEquals
/**
* Created by mariotaku on 16/2/10.
*/
public class MicroBlogAPIFactoryTest {
class MicroBlogAPIFactoryTest {
@Test
public void testGetApiUrl() throws Exception {
assertEquals("https://api.twitter.com/", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com", "api", null));
assertEquals("https://api.twitter.com/", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com/", "api", null));
assertEquals("https://api.twitter.com/1.1/", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com", "api", "/1.1/"));
assertEquals("https://api.twitter.com/1.1", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com/", "api", "1.1"));
assertEquals("https://api.twitter.com/1.1", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com", "api", "/1.1"));
assertEquals("https://api.twitter.com/1.1", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com/", "api", "/1.1"));
assertEquals("https://api.twitter.com/1.1/", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com", "api", "1.1/"));
assertEquals("https://api.twitter.com/1.1/", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com/", "api", "1.1/"));
assertEquals("https://api.twitter.com/1.1/", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com", "api", "/1.1/"));
assertEquals("https://api.twitter.com/1.1/", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com/", "api", "/1.1/"));
@Throws(Exception::class)
fun testGetApiUrl() {
assertEquals("https://api.twitter.com/", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com", "api", null))
assertEquals("https://api.twitter.com/", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com/", "api", null))
assertEquals("https://api.twitter.com/1.1/", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com", "api", "/1.1/"))
assertEquals("https://api.twitter.com/1.1", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com/", "api", "1.1"))
assertEquals("https://api.twitter.com/1.1", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com", "api", "/1.1"))
assertEquals("https://api.twitter.com/1.1", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com/", "api", "/1.1"))
assertEquals("https://api.twitter.com/1.1/", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com", "api", "1.1/"))
assertEquals("https://api.twitter.com/1.1/", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com/", "api", "1.1/"))
assertEquals("https://api.twitter.com/1.1/", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com", "api", "/1.1/"))
assertEquals("https://api.twitter.com/1.1/", MicroBlogAPIFactory.getApiUrl("https://[DOMAIN.]twitter.com/", "api", "/1.1/"))
}
@Test
public void testGetApiBaseUrl() {
assertEquals("https://media.twitter.com", MicroBlogAPIFactory.getApiBaseUrl("https://api.twitter.com", "media"));
fun testGetApiBaseUrl() {
assertEquals("https://media.twitter.com", MicroBlogAPIFactory.getApiBaseUrl("https://api.twitter.com", "media"))
}
}

View File

@ -1,37 +0,0 @@
package org.mariotaku.twidere.util;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertArrayEquals;
/**
* Created by mariotaku on 16/1/31.
*/
public class TwidereArrayUtilsTest {
@Test
public void testMergeArray() throws Exception {
String[] array1 = {"1", "2"};
String[] array2 = {"1", "2"};
String[] array3 = null;
//noinspection ConstantConditions
String[] merged = new String[TwidereArrayUtils.arraysLength(array1, array2, array3)];
//noinspection ConstantConditions
TwidereArrayUtils.mergeArray(merged, array1, array2, array3);
String[] expected = {"1", "2", "1", "2"};
assertArrayEquals(expected, merged);
}
@Test
public void testArraysLength() throws Exception {
String[] array1 = {"1", "2"};
String[] array2 = {"1", "2"};
String[] array3 = null;
//noinspection ConstantConditions
assertEquals(4, TwidereArrayUtils.arraysLength(array1, array2, array3));
assertEquals(6, TwidereArrayUtils.arraysLength(array1, array2, array2));
}
}

View File

@ -0,0 +1,39 @@
package org.mariotaku.twidere.util
import org.junit.Test
import junit.framework.Assert.assertEquals
import org.junit.Assert.assertArrayEquals
/**
* Created by mariotaku on 16/1/31.
*/
class TwidereArrayUtilsTest {
@Test
@Throws(Exception::class)
fun testMergeArray() {
val array1 = arrayOf("1", "2")
val array2 = arrayOf("1", "2")
val array3: Array<String>? = null
//noinspection ConstantConditions
val merged = arrayOfNulls<String>(TwidereArrayUtils.arraysLength(array1, array2, array3))
//noinspection ConstantConditions
TwidereArrayUtils.mergeArray(merged, array1, array2, array3)
val expected = arrayOf("1", "2", "1", "2")
assertArrayEquals(expected, merged)
}
@Test
@Throws(Exception::class)
fun testArraysLength() {
val array1 = arrayOf("1", "2")
val array2 = arrayOf("1", "2")
val array3: Array<String>? = null
//noinspection ConstantConditions
assertEquals(4, TwidereArrayUtils.arraysLength(array1, array2, array3))
assertEquals(6, TwidereArrayUtils.arraysLength(array1, array2, array2))
}
}

View File

@ -1,58 +0,0 @@
package org.mariotaku.twidere.util;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Created by mariotaku on 16/1/23.
*/
public class TwidereMathUtilsTest {
public void testClamp() throws Exception {
}
public void testClamp1() throws Exception {
}
public void testNextPowerOf2() throws Exception {
}
public void testPrevPowerOf2() throws Exception {
}
public void testSum() throws Exception {
}
public void testSum1() throws Exception {
}
public void testSum2() throws Exception {
}
@Test
public void testInRange() {
assertTrue(TwidereMathUtils.inRange(5, 0, 10, TwidereMathUtils.RANGE_INCLUSIVE_INCLUSIVE));
assertFalse(TwidereMathUtils.inRange(0, 0, 10, TwidereMathUtils.RANGE_EXCLUSIVE_EXCLUSIVE));
assertFalse(TwidereMathUtils.inRange(0, 5, 10, TwidereMathUtils.RANGE_INCLUSIVE_INCLUSIVE));
assertFalse(TwidereMathUtils.inRange(5, 5, 10, TwidereMathUtils.RANGE_EXCLUSIVE_INCLUSIVE));
assertFalse(TwidereMathUtils.inRange(10, 5, 10, TwidereMathUtils.RANGE_INCLUSIVE_EXCLUSIVE));
}
@Test
public void testInRange1() {
assertTrue(TwidereMathUtils.inRange(5f, 0f, 10f, TwidereMathUtils.RANGE_INCLUSIVE_INCLUSIVE));
assertFalse(TwidereMathUtils.inRange(0f, 0f, 10f, TwidereMathUtils.RANGE_EXCLUSIVE_EXCLUSIVE));
assertFalse(TwidereMathUtils.inRange(0f, 5f, 10f, TwidereMathUtils.RANGE_INCLUSIVE_INCLUSIVE));
assertFalse(TwidereMathUtils.inRange(5f, 5f, 10f, TwidereMathUtils.RANGE_EXCLUSIVE_INCLUSIVE));
assertFalse(TwidereMathUtils.inRange(10f, 5f, 10f, TwidereMathUtils.RANGE_INCLUSIVE_EXCLUSIVE));
}
}

View File

@ -0,0 +1,65 @@
package org.mariotaku.twidere.util
import org.junit.Test
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
/**
* Created by mariotaku on 16/1/23.
*/
class TwidereMathUtilsTest {
@Throws(Exception::class)
fun testClamp() {
}
@Throws(Exception::class)
fun testClamp1() {
}
@Throws(Exception::class)
fun testNextPowerOf2() {
}
@Throws(Exception::class)
fun testPrevPowerOf2() {
}
@Throws(Exception::class)
fun testSum() {
}
@Throws(Exception::class)
fun testSum1() {
}
@Throws(Exception::class)
fun testSum2() {
}
@Test
fun testInRange() {
assertTrue(TwidereMathUtils.inRange(5, 0, 10, TwidereMathUtils.RANGE_INCLUSIVE_INCLUSIVE))
assertFalse(TwidereMathUtils.inRange(0, 0, 10, TwidereMathUtils.RANGE_EXCLUSIVE_EXCLUSIVE))
assertFalse(TwidereMathUtils.inRange(0, 5, 10, TwidereMathUtils.RANGE_INCLUSIVE_INCLUSIVE))
assertFalse(TwidereMathUtils.inRange(5, 5, 10, TwidereMathUtils.RANGE_EXCLUSIVE_INCLUSIVE))
assertFalse(TwidereMathUtils.inRange(10, 5, 10, TwidereMathUtils.RANGE_INCLUSIVE_EXCLUSIVE))
}
@Test
fun testInRange1() {
assertTrue(TwidereMathUtils.inRange(5f, 0f, 10f, TwidereMathUtils.RANGE_INCLUSIVE_INCLUSIVE))
assertFalse(TwidereMathUtils.inRange(0f, 0f, 10f, TwidereMathUtils.RANGE_EXCLUSIVE_EXCLUSIVE))
assertFalse(TwidereMathUtils.inRange(0f, 5f, 10f, TwidereMathUtils.RANGE_INCLUSIVE_INCLUSIVE))
assertFalse(TwidereMathUtils.inRange(5f, 5f, 10f, TwidereMathUtils.RANGE_EXCLUSIVE_INCLUSIVE))
assertFalse(TwidereMathUtils.inRange(10f, 5f, 10f, TwidereMathUtils.RANGE_INCLUSIVE_EXCLUSIVE))
}
}

View File

@ -1,24 +0,0 @@
package org.mariotaku.twidere.util;
import org.apache.commons.lang3.reflect.TypeUtils;
import org.junit.Test;
import org.mariotaku.microblog.library.twitter.model.CursorTimestampResponse;
import org.mariotaku.microblog.library.twitter.model.ResponseList;
import org.mariotaku.microblog.library.twitter.model.Status;
import java.util.List;
import static org.junit.Assert.assertEquals;
/**
* Created by mariotaku on 16/2/15.
*/
public class TwidereTypeUtilsTest {
@Test
public void testGetSimpleName() throws Exception {
assertEquals("CursorTimestampResponse", TwidereTypeUtils.toSimpleName(CursorTimestampResponse.class));
assertEquals("ResponseList<Status>", TwidereTypeUtils.toSimpleName(TypeUtils.parameterize(ResponseList.class, Status.class)));
assertEquals("List<List<Object>>", TwidereTypeUtils.toSimpleName(TypeUtils.parameterize(List.class, TypeUtils.parameterize(List.class, Object.class))));
}
}

View File

@ -0,0 +1,22 @@
package org.mariotaku.twidere.util
import org.apache.commons.lang3.reflect.TypeUtils
import org.junit.Assert.assertEquals
import org.junit.Test
import org.mariotaku.microblog.library.twitter.model.CursorTimestampResponse
import org.mariotaku.microblog.library.twitter.model.ResponseList
import org.mariotaku.microblog.library.twitter.model.Status
/**
* Created by mariotaku on 16/2/15.
*/
class TwidereTypeUtilsTest {
@Test
@Throws(Exception::class)
fun testGetSimpleName() {
assertEquals("CursorTimestampResponse", TwidereTypeUtils.toSimpleName(CursorTimestampResponse::class.java))
assertEquals("ResponseList<Status>", TwidereTypeUtils.toSimpleName(TypeUtils.parameterize(ResponseList::class.java, Status::class.java)))
assertEquals("List<List<Object>>", TwidereTypeUtils.toSimpleName(TypeUtils.parameterize(List::class.java, TypeUtils.parameterize(List::class.java, Any::class.java))))
}
}

View File

@ -1,33 +1,35 @@
package org.mariotaku.twidere.util;
package org.mariotaku.twidere.util
import org.junit.Test;
import org.junit.Test
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertNull
/**
* Created by mariotaku on 16/2/9.
*/
public class UriUtilsTest {
class UriUtilsTest {
@Test
public void testGetAuthority() throws Exception {
assertEquals("www.google.com", UriUtils.getAuthority("http://www.google.com/"));
assertEquals("twitter.com", UriUtils.getAuthority("https://twitter.com"));
assertNull(UriUtils.getAuthority("www.google.com/"));
@Throws(Exception::class)
fun testGetAuthority() {
assertEquals("www.google.com", UriUtils.getAuthority("http://www.google.com/"))
assertEquals("twitter.com", UriUtils.getAuthority("https://twitter.com"))
assertNull(UriUtils.getAuthority("www.google.com/"))
}
@Test
public void testGetPath() throws Exception {
assertEquals("/", UriUtils.getPath("http://www.example.com/"));
assertEquals("", UriUtils.getPath("http://www.example.com"));
assertEquals("/test/path", UriUtils.getPath("https://example.com/test/path"));
assertEquals("/test/path", UriUtils.getPath("https://example.com/test/path?with=query"));
assertEquals("/test/path/", UriUtils.getPath("https://example.com/test/path/?with=query"));
assertEquals("/test/path", UriUtils.getPath("https://example.com/test/path?with=query#fragment"));
assertEquals("/test/path/", UriUtils.getPath("https://example.com/test/path/?with=query#fragment"));
assertEquals("/test/path", UriUtils.getPath("https://example.com/test/path#fragment"));
assertEquals("/test/path/", UriUtils.getPath("https://example.com/test/path/#fragment"));
@Throws(Exception::class)
fun testGetPath() {
assertEquals("/", UriUtils.getPath("http://www.example.com/"))
assertEquals("", UriUtils.getPath("http://www.example.com"))
assertEquals("/test/path", UriUtils.getPath("https://example.com/test/path"))
assertEquals("/test/path", UriUtils.getPath("https://example.com/test/path?with=query"))
assertEquals("/test/path/", UriUtils.getPath("https://example.com/test/path/?with=query"))
assertEquals("/test/path", UriUtils.getPath("https://example.com/test/path?with=query#fragment"))
assertEquals("/test/path/", UriUtils.getPath("https://example.com/test/path/?with=query#fragment"))
assertEquals("/test/path", UriUtils.getPath("https://example.com/test/path#fragment"))
assertEquals("/test/path/", UriUtils.getPath("https://example.com/test/path/#fragment"))
}
}

View File

@ -1,44 +0,0 @@
package org.mariotaku.twidere.util.media.preview.provider;
import org.junit.Test;
import org.mariotaku.twidere.model.ParcelableMedia;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
/**
* Created by mariotaku on 16/2/20.
*/
public class InstagramProviderTest {
final InstagramProvider provider = new InstagramProvider();
@Test
public void testFrom() throws Exception {
ParcelableMedia media = provider.from("https://www.instagram.com/p/abcd1234");
assertNotNull(media);
assertEquals("https://instagram.com/p/abcd1234/media/?size=l", media.media_url);
media = provider.from("https://www.instagram.com/p/abcd1234/");
assertNotNull(media);
assertEquals("https://instagram.com/p/abcd1234/media/?size=l", media.media_url);
media = provider.from("https://www.instagram.com/p/abcd1234?key=value");
assertNotNull(media);
assertEquals("https://instagram.com/p/abcd1234/media/?size=l", media.media_url);
media = provider.from("https://www.instagram.com/p/abcd1234/?key=value");
assertNotNull(media);
assertEquals("https://instagram.com/p/abcd1234/media/?size=l", media.media_url);
media = provider.from("https://www.instagram.com/p/abcd1234/?key=value#fragment");
assertNotNull(media);
assertEquals("https://instagram.com/p/abcd1234/media/?size=l", media.media_url);
media = provider.from("https://www.instagram.com/p/abcd1234#fragment");
assertNotNull(media);
assertEquals("https://instagram.com/p/abcd1234/media/?size=l", media.media_url);
media = provider.from("https://www.instagram.com/p/abcd1234/#fragment");
assertNotNull(media);
assertEquals("https://instagram.com/p/abcd1234/media/?size=l", media.media_url);
media = provider.from("https://www.instagram.com/user");
assertNull(media);
}
}

View File

@ -0,0 +1,36 @@
package org.mariotaku.twidere.util.media.preview.provider
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Test
import org.mariotaku.twidere.model.ParcelableMedia
/**
* Created by mariotaku on 16/2/20.
*/
class InstagramProviderTest {
internal val provider = InstagramProvider()
@Test
@Throws(Exception::class)
fun testFrom() {
var media: ParcelableMedia ? = provider.from("https://www.instagram.com/p/abcd1234")
assertEquals("https://instagram.com/p/abcd1234/media/?size=l", media!!.media_url)
media = provider.from("https://www.instagram.com/p/abcd1234/")
assertEquals("https://instagram.com/p/abcd1234/media/?size=l", media!!.media_url)
media = provider.from("https://www.instagram.com/p/abcd1234?key=value")
assertEquals("https://instagram.com/p/abcd1234/media/?size=l", media!!.media_url)
media = provider.from("https://www.instagram.com/p/abcd1234/?key=value")
assertEquals("https://instagram.com/p/abcd1234/media/?size=l", media!!.media_url)
media = provider.from("https://www.instagram.com/p/abcd1234/?key=value#fragment")
assertEquals("https://instagram.com/p/abcd1234/media/?size=l", media!!.media_url)
media = provider.from("https://www.instagram.com/p/abcd1234#fragment")
assertEquals("https://instagram.com/p/abcd1234/media/?size=l", media!!.media_url)
media = provider.from("https://www.instagram.com/p/abcd1234/#fragment")
assertEquals("https://instagram.com/p/abcd1234/media/?size=l", media!!.media_url)
media = provider.from("https://www.instagram.com/user")
assertNull(media)
}
}

View File

@ -1,32 +0,0 @@
package org.mariotaku.twidere.activity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
public class AssistLauncherActivity extends Activity implements Constants {
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final SharedPreferencesWrapper prefs = SharedPreferencesWrapper.getInstance(this, SHARED_PREFERENCES_NAME,
MODE_PRIVATE);
final String composeNowAction = prefs.getString(KEY_COMPOSE_NOW_ACTION, VALUE_COMPOSE_NOW_ACTION_COMPOSE), action;
if (VALUE_COMPOSE_NOW_ACTION_TAKE_PHOTO.equals(composeNowAction)) {
action = INTENT_ACTION_COMPOSE_TAKE_PHOTO;
} else if (VALUE_COMPOSE_NOW_ACTION_PICK_IMAGE.equals(composeNowAction)) {
action = INTENT_ACTION_COMPOSE_PICK_IMAGE;
} else {
action = INTENT_ACTION_COMPOSE;
}
final Intent intent = new Intent(action);
intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
intent.setClass(this, ComposeActivity.class);
startActivity(intent);
finish();
}
}

View File

@ -1,437 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.activity;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatDelegate;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceFragmentCompat;
import android.support.v7.preference.PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback;
import android.support.v7.view.menu.ActionMenuItemView;
import android.support.v7.widget.Toolbar;
import android.support.v7.widget.TwidereActionMenuView;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import com.afollestad.appthemeengine.ATE;
import com.afollestad.appthemeengine.ATEActivity;
import com.afollestad.appthemeengine.Config;
import com.afollestad.appthemeengine.customizers.ATEStatusBarCustomizer;
import com.afollestad.appthemeengine.customizers.ATEToolbarCustomizer;
import com.squareup.otto.Bus;
import org.mariotaku.twidere.BuildConfig;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.activity.iface.IAppCompatActivity;
import org.mariotaku.twidere.activity.iface.IControlBarActivity;
import org.mariotaku.twidere.activity.iface.IExtendedActivity;
import org.mariotaku.twidere.activity.iface.IThemedActivity;
import org.mariotaku.twidere.fragment.iface.IBaseFragment.SystemWindowsInsetsCallback;
import org.mariotaku.twidere.preference.iface.IDialogPreference;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.IntentUtils;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.NotificationManagerWrapper;
import org.mariotaku.twidere.util.PermissionsManager;
import org.mariotaku.twidere.util.ReadStateManager;
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
import org.mariotaku.twidere.util.StrictModeUtils;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.UserColorNameManager;
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper;
import org.mariotaku.twidere.view.iface.IExtendedView.OnFitSystemWindowsListener;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import javax.inject.Inject;
@SuppressLint("Registered")
public class BaseActivity extends ATEActivity implements Constants, IExtendedActivity,
IThemedActivity, IAppCompatActivity, IControlBarActivity, OnFitSystemWindowsListener,
SystemWindowsInsetsCallback, KeyboardShortcutCallback, OnPreferenceDisplayDialogCallback,
ATEToolbarCustomizer, ATEStatusBarCustomizer {
private static final String[] sClassPrefixList = {
"android.widget.",
"android.view.",
"android.webkit."
};
// Utility classes
@Inject
protected KeyboardShortcutsHandler mKeyboardShortcutsHandler;
@Inject
protected AsyncTwitterWrapper mTwitterWrapper;
@Inject
protected ReadStateManager mReadStateManager;
@Inject
protected Bus mBus;
@Inject
protected SharedPreferencesWrapper mPreferences;
@Inject
protected NotificationManagerWrapper mNotificationManager;
@Inject
protected MediaLoaderWrapper mMediaLoader;
@Inject
protected UserColorNameManager mUserColorNameManager;
@Inject
protected PermissionsManager mPermissionsManager;
private ActionHelper mActionHelper = new ActionHelper(this);
// Registered listeners
private ArrayList<ControlBarOffsetListener> mControlBarOffsetListeners = new ArrayList<>();
// Data fields
private Rect mSystemWindowsInsets;
private int mKeyMetaState;
// Data fields
private int mCurrentThemeBackgroundAlpha;
private String mCurrentThemeBackgroundOption;
@Override
public boolean getSystemWindowsInsets(Rect insets) {
if (mSystemWindowsInsets == null) return false;
insets.set(mSystemWindowsInsets);
return true;
}
@Override
public void onFitSystemWindows(Rect insets) {
if (mSystemWindowsInsets == null)
mSystemWindowsInsets = new Rect(insets);
else {
mSystemWindowsInsets.set(insets);
}
notifyControlBarOffsetChanged();
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
final int keyCode = event.getKeyCode();
if (KeyEvent.isModifierKey(keyCode)) {
final int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
mKeyMetaState |= KeyboardShortcutsHandler.getMetaStateForKeyCode(keyCode);
} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
mKeyMetaState &= ~KeyboardShortcutsHandler.getMetaStateForKeyCode(keyCode);
}
}
return super.dispatchKeyEvent(event);
}
@Override
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
if (handleKeyboardShortcutSingle(mKeyboardShortcutsHandler, keyCode, event, mKeyMetaState))
return true;
return isKeyboardShortcutHandled(mKeyboardShortcutsHandler, keyCode, event, mKeyMetaState) || super.onKeyUp(keyCode, event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (handleKeyboardShortcutRepeat(mKeyboardShortcutsHandler, keyCode, event.getRepeatCount(), event, mKeyMetaState))
return true;
return isKeyboardShortcutHandled(mKeyboardShortcutsHandler, keyCode, event, mKeyMetaState) || super.onKeyDown(keyCode, event);
}
@Override
public boolean handleKeyboardShortcutSingle(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event, int metaState) {
return false;
}
@Override
public boolean isKeyboardShortcutHandled(@NonNull KeyboardShortcutsHandler handler, int keyCode, @NonNull KeyEvent event, int metaState) {
return false;
}
@Override
public boolean handleKeyboardShortcutRepeat(@NonNull KeyboardShortcutsHandler handler, int keyCode, int repeatCount, @NonNull KeyEvent event, int metaState) {
return false;
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
if (BuildConfig.DEBUG) {
StrictModeUtils.detectAllVmPolicy();
StrictModeUtils.detectAllThreadPolicy();
}
super.onCreate(savedInstanceState);
GeneralComponentHelper.build(this).inject(this);
}
@Override
protected void onResume() {
super.onResume();
final NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
if (adapter != null && adapter.isEnabled()) {
final IntentFilter handlerFilter = IntentUtils.getWebLinkIntentFilter(this);
if (handlerFilter != null) {
final Intent linkIntent = new Intent(this, WebLinkHandlerActivity.class);
final PendingIntent intent = PendingIntent.getActivity(this, 0, linkIntent, 0);
final IntentFilter intentFilter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
for (int i = 0, j = handlerFilter.countDataSchemes(); i < j; i++) {
intentFilter.addDataScheme(handlerFilter.getDataScheme(i));
}
for (int i = 0, j = handlerFilter.countDataAuthorities(); i < j; i++) {
final IntentFilter.AuthorityEntry authorityEntry = handlerFilter.getDataAuthority(i);
final int port = authorityEntry.getPort();
intentFilter.addDataAuthority(authorityEntry.getHost(), port < 0 ? null : Integer.toString(port));
}
try {
adapter.enableForegroundDispatch(this, intent, new IntentFilter[]{intentFilter}, null);
} catch (Exception e) {
// Ignore if blocked by modified roms
}
}
}
}
@Override
protected void onPause() {
final NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
if (adapter != null && adapter.isEnabled()) {
try {
adapter.disableForegroundDispatch(this);
} catch (Exception e) {
// Ignore if blocked by modified roms
}
}
mActionHelper.dispatchOnPause();
super.onPause();
}
@Override
public void setControlBarOffset(float offset) {
}
@Override
public void setControlBarVisibleAnimate(boolean visible) {
}
@Override
public void setControlBarVisibleAnimate(boolean visible, ControlBarShowHideHelper.ControlBarAnimationListener listener) {
}
@Override
public float getControlBarOffset() {
return 0;
}
@Override
public int getControlBarHeight() {
return 0;
}
@Override
public void notifyControlBarOffsetChanged() {
final float offset = getControlBarOffset();
for (final ControlBarOffsetListener l : mControlBarOffsetListeners) {
l.onControlBarOffsetChanged(this, offset);
}
}
@Override
public void registerControlBarOffsetListener(ControlBarOffsetListener listener) {
mControlBarOffsetListeners.add(listener);
}
@Override
public void unregisterControlBarOffsetListener(ControlBarOffsetListener listener) {
mControlBarOffsetListeners.remove(listener);
}
public int getKeyMetaState() {
return mKeyMetaState;
}
@Override
protected void onResumeFragments() {
super.onResumeFragments();
mActionHelper.dispatchOnResumeFragments();
}
@Override
public void executeAfterFragmentResumed(Action action) {
mActionHelper.executeAfterFragmentResumed(action);
}
@Override
public int getCurrentThemeBackgroundAlpha() {
return mCurrentThemeBackgroundAlpha;
}
@Override
public String getCurrentThemeBackgroundOption() {
return mCurrentThemeBackgroundOption;
}
@Override
public int getThemeBackgroundAlpha() {
return ThemeUtils.getUserThemeBackgroundAlpha(this);
}
@Override
public String getThemeBackgroundOption() {
return ThemeUtils.getThemeBackgroundOption(this);
}
@Nullable
@Override
public String getATEKey() {
return ThemeUtils.getATEKey(this);
}
@Override
protected void onApplyThemeResource(@NonNull Resources.Theme theme, int resId, boolean first) {
mCurrentThemeBackgroundAlpha = getThemeBackgroundAlpha();
mCurrentThemeBackgroundOption = getThemeBackgroundOption();
super.onApplyThemeResource(theme, resId, first);
final Window window = getWindow();
if (window != null && shouldApplyWindowBackground()) {
ThemeUtils.applyWindowBackground(this, window, getThemeBackgroundOption(),
getThemeBackgroundAlpha());
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
ThemeUtils.fixNightMode(getResources(), newConfig);
super.onConfigurationChanged(newConfig);
}
protected boolean shouldApplyWindowBackground() {
return true;
}
@Override
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
// Fix for https://github.com/afollestad/app-theme-engine/issues/109
if (context != this) {
final AppCompatDelegate delegate = getDelegate();
View view = delegate.createView(parent, name, context, attrs);
if (view == null) {
view = newInstance(name, context, attrs);
}
if (view == null) {
view = newInstance(name, context, attrs);
}
if (view != null) {
return view;
}
}
if (parent instanceof TwidereActionMenuView) {
final Class<?> cls = findClass(name);
if (cls != null && ActionMenuItemView.class.isAssignableFrom(cls)) {
return ((TwidereActionMenuView) parent).createActionMenuView(context, attrs);
}
}
return super.onCreateView(parent, name, context, attrs);
}
private Class<?> findClass(String name) {
Class<?> cls = null;
try {
cls = Class.forName(name);
} catch (ClassNotFoundException e) {
// Ignore
}
if (cls != null) return cls;
for (String prefix : sClassPrefixList) {
try {
cls = Class.forName(prefix + name);
} catch (ClassNotFoundException e) {
// Ignore
}
if (cls != null) return cls;
}
return null;
}
private View newInstance(String name, Context context, AttributeSet attrs) {
try {
final Class<?> cls = findClass(name);
if (cls == null) throw new ClassNotFoundException(name);
final Constructor<?> constructor = cls.getConstructor(Context.class, AttributeSet.class);
return (View) constructor.newInstance(context, attrs);
} catch (InstantiationException e) {
return null;
} catch (IllegalAccessException e) {
return null;
} catch (InvocationTargetException e) {
return null;
} catch (NoSuchMethodException e) {
return null;
} catch (ClassNotFoundException e) {
return null;
}
}
@Override
public boolean onPreferenceDisplayDialog(PreferenceFragmentCompat fragment, Preference preference) {
if (preference instanceof IDialogPreference) {
((IDialogPreference) preference).displayDialog(fragment);
return true;
}
return false;
}
@Override
public int getStatusBarColor() {
return ATE.USE_DEFAULT;
}
@Override
public int getToolbarColor(@Nullable Toolbar toolbar) {
return ATE.USE_DEFAULT;
}
@Override
public int getLightStatusBarMode() {
//noinspection WrongConstant
return ThemeUtils.getLightStatusBarMode(Config.statusBarColor(this, getATEKey()));
}
@Override
public int getLightToolbarMode(@Nullable Toolbar toolbar) {
//noinspection WrongConstant
return ThemeUtils.getLightToolbarMode(Config.toolbarColor(this, getATEKey(), toolbar));
}
}

View File

@ -241,18 +241,18 @@ public class CustomTabEditorActivity extends BaseActivity implements OnClickList
icon.setVisibility(displayProfileImage ? View.VISIBLE : View.GONE);
if (value instanceof ParcelableUser) {
final ParcelableUser user = (ParcelableUser) value;
text1.setText(mUserColorNameManager.getUserNickname(user.key, user.name));
text1.setText(userColorNameManager.getUserNickname(user.key, user.name));
text2.setText(String.format("@%s", user.screen_name));
if (displayProfileImage) {
mMediaLoader.displayProfileImage(icon, user);
mediaLoader.displayProfileImage(icon, user);
}
} else if (value instanceof ParcelableUserList) {
final ParcelableUserList userList = (ParcelableUserList) value;
final String createdBy = mUserColorNameManager.getDisplayName(userList, displayName);
final String createdBy = userColorNameManager.getDisplayName(userList, displayName);
text1.setText(userList.name);
text2.setText(getString(R.string.created_by, createdBy));
if (displayProfileImage) {
mMediaLoader.displayProfileImage(icon, userList.user_profile_image_url);
mediaLoader.displayProfileImage(icon, userList.user_profile_image_url);
}
} else if (value instanceof CharSequence) {
text2.setVisibility(View.GONE);

View File

@ -1,155 +0,0 @@
package org.mariotaku.twidere.activity;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.util.Log;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.fragment.DataExportImportTypeSelectorDialogFragment;
import org.mariotaku.twidere.fragment.ProgressDialogFragment;
import org.mariotaku.twidere.util.DataImportExportUtils;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class DataExportActivity extends BaseActivity implements
DataExportImportTypeSelectorDialogFragment.Callback {
private ExportSettingsTask mTask;
private Runnable mResumeFragmentsRunnable;
@Override
public void onCancelled(DialogFragment df) {
if (!isFinishing()) {
finish();
}
}
@Override
public void onDismissed(final DialogFragment df) {
if (df instanceof DataExportImportTypeSelectorDialogFragment) {
finish();
}
}
@Override
protected void onResumeFragments() {
super.onResumeFragments();
if (mResumeFragmentsRunnable != null) {
mResumeFragmentsRunnable.run();
}
}
@Override
protected void onActivityResult(int requestCode, final int resultCode, final Intent data) {
switch (requestCode) {
case REQUEST_PICK_DIRECTORY: {
mResumeFragmentsRunnable = new Runnable() {
@Override
public void run() {
if (resultCode == RESULT_OK) {
final String path = data.getData().getPath();
final DialogFragment df = new DataExportImportTypeSelectorDialogFragment();
final Bundle args = new Bundle();
args.putString(EXTRA_PATH, path);
args.putString(EXTRA_TITLE, getString(R.string.export_settings_type_dialog_title));
df.setArguments(args);
df.show(getSupportFragmentManager(), "select_export_type");
} else {
if (!isFinishing()) {
finish();
}
}
}
};
return;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public void onPositiveButtonClicked(final String path, final int flags) {
if (path == null || flags == 0) {
finish();
return;
}
if (mTask == null || mTask.getStatus() != AsyncTask.Status.RUNNING) {
mTask = new ExportSettingsTask(this, path, flags);
mTask.execute();
}
}
@Override
protected void onStart() {
super.onStart();
setVisible(true);
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
final Intent intent = new Intent(this, FileSelectorActivity.class);
intent.setAction(INTENT_ACTION_PICK_DIRECTORY);
startActivityForResult(intent, REQUEST_PICK_DIRECTORY);
}
}
static class ExportSettingsTask extends AsyncTask<Object, Object, Boolean> {
private static final String FRAGMENT_TAG = "import_settings_dialog";
private final DataExportActivity mActivity;
private final String mPath;
private final int mFlags;
ExportSettingsTask(final DataExportActivity activity, final String path, final int flags) {
mActivity = activity;
mPath = path;
mFlags = flags;
}
@Override
protected Boolean doInBackground(final Object... params) {
if (mPath == null) return false;
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.US);
final String fileName = String.format("Twidere_Settings_%s.zip", sdf.format(new Date()));
final File file = new File(mPath, fileName);
file.delete();
try {
DataImportExportUtils.exportData(mActivity, file, mFlags);
return true;
} catch (final IOException e) {
Log.w(LOGTAG, e);
return false;
}
}
@Override
protected void onPostExecute(final Boolean result) {
final FragmentManager fm = mActivity.getSupportFragmentManager();
final DialogFragment f = (DialogFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (f != null) {
f.dismiss();
}
if (result != null && result) {
mActivity.setResult(RESULT_OK);
} else {
mActivity.setResult(RESULT_CANCELED);
}
mActivity.finish();
}
@Override
protected void onPreExecute() {
ProgressDialogFragment.show(mActivity, FRAGMENT_TAG).setCancelable(false);
}
}
}

View File

@ -1,202 +0,0 @@
package org.mariotaku.twidere.activity;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.util.Log;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.fragment.DataExportImportTypeSelectorDialogFragment;
import org.mariotaku.twidere.fragment.ProgressDialogFragment;
import org.mariotaku.twidere.util.DataImportExportUtils;
import java.io.File;
import java.io.IOException;
public class DataImportActivity extends BaseActivity implements
DataExportImportTypeSelectorDialogFragment.Callback {
private ImportSettingsTask mImportSettingsTask;
private OpenImportTypeTask mOpenImportTypeTask;
private Runnable mResumeFragmentsRunnable;
@Override
public void onCancelled(final DialogFragment df) {
if (!isFinishing()) {
finish();
}
}
@Override
public void onDismissed(final DialogFragment df) {
if (df instanceof DataExportImportTypeSelectorDialogFragment) {
finish();
}
}
@Override
protected void onActivityResult(int requestCode, final int resultCode, final Intent data) {
switch (requestCode) {
case REQUEST_PICK_FILE: {
mResumeFragmentsRunnable = new Runnable() {
@Override
public void run() {
if (resultCode == RESULT_OK) {
final String path = data.getData().getPath();
if (mOpenImportTypeTask == null || mOpenImportTypeTask.getStatus() != AsyncTask.Status.RUNNING) {
mOpenImportTypeTask = new OpenImportTypeTask(DataImportActivity.this, path);
mOpenImportTypeTask.execute();
}
} else {
if (!isFinishing()) {
finish();
}
}
}
};
return;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
protected void onResumeFragments() {
super.onResumeFragments();
if (mResumeFragmentsRunnable != null) {
mResumeFragmentsRunnable.run();
}
}
@Override
public void onPositiveButtonClicked(final String path, final int flags) {
if (path == null || flags == 0) {
finish();
return;
}
if (mImportSettingsTask == null || mImportSettingsTask.getStatus() != AsyncTask.Status.RUNNING) {
mImportSettingsTask = new ImportSettingsTask(this, path, flags);
mImportSettingsTask.execute();
}
}
@Override
protected void onStart() {
super.onStart();
setVisible(true);
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
final Intent intent = new Intent(this, FileSelectorActivity.class);
intent.setAction(INTENT_ACTION_PICK_FILE);
startActivityForResult(intent, REQUEST_PICK_FILE);
}
}
static class ImportSettingsTask extends AsyncTask<Object, Object, Boolean> {
private static final String FRAGMENT_TAG = "import_settings_dialog";
private final DataImportActivity mActivity;
private final String mPath;
private final int mFlags;
ImportSettingsTask(final DataImportActivity activity, final String path, final int flags) {
mActivity = activity;
mPath = path;
mFlags = flags;
}
@Override
protected Boolean doInBackground(final Object... params) {
if (mPath == null) return false;
final File file = new File(mPath);
if (!file.isFile()) return false;
try {
DataImportExportUtils.importData(mActivity, file, mFlags);
return true;
} catch (final IOException e) {
Log.w(LOGTAG, e);
return false;
}
}
@Override
protected void onPostExecute(final Boolean result) {
final FragmentManager fm = mActivity.getSupportFragmentManager();
final Fragment f = fm.findFragmentByTag(FRAGMENT_TAG);
if (f instanceof DialogFragment) {
((DialogFragment) f).dismiss();
}
if (result != null && result) {
mActivity.setResult(RESULT_OK);
} else {
mActivity.setResult(RESULT_CANCELED);
}
mActivity.finish();
}
@Override
protected void onPreExecute() {
ProgressDialogFragment.show(mActivity, FRAGMENT_TAG).setCancelable(false);
}
}
static class OpenImportTypeTask extends AsyncTask<Object, Object, Integer> {
private static final String FRAGMENT_TAG = "read_settings_data_dialog";
private final DataImportActivity mActivity;
private final String mPath;
OpenImportTypeTask(final DataImportActivity activity, final String path) {
mActivity = activity;
mPath = path;
}
@Override
protected Integer doInBackground(final Object... params) {
if (mPath == null) return 0;
final File file = new File(mPath);
if (!file.isFile()) return 0;
try {
return DataImportExportUtils.getImportedSettingsFlags(file);
} catch (final IOException e) {
return 0;
}
}
@Override
protected void onPostExecute(final Integer flags) {
final FragmentManager fm = mActivity.getSupportFragmentManager();
final Fragment f = fm.findFragmentByTag(FRAGMENT_TAG);
if (f instanceof DialogFragment) {
((DialogFragment) f).dismiss();
}
final DialogFragment df = new DataExportImportTypeSelectorDialogFragment();
final Bundle args = new Bundle();
args.putString(EXTRA_PATH, mPath);
args.putString(EXTRA_TITLE, mActivity.getString(R.string.import_settings_type_dialog_title));
if (flags != null) {
args.putInt(EXTRA_FLAGS, flags);
} else {
args.putInt(EXTRA_FLAGS, 0);
}
df.setArguments(args);
df.show(mActivity.getSupportFragmentManager(), "select_import_type");
}
@Override
protected void onPreExecute() {
ProgressDialogFragment.show(mActivity, FRAGMENT_TAG).setCancelable(false);
}
}
}

View File

@ -68,12 +68,12 @@ public class KeyboardShortcutPreferenceCompatActivity extends BaseActivity imple
switch (v.getId()) {
case R.id.button_positive: {
if (mKeySpec == null) return;
mKeyboardShortcutsHandler.register(mKeySpec, getKeyAction());
keyboardShortcutsHandler.register(mKeySpec, getKeyAction());
finish();
break;
}
case R.id.button_neutral: {
mKeyboardShortcutsHandler.unregister(getKeyAction());
keyboardShortcutsHandler.unregister(getKeyAction());
finish();
break;
}
@ -106,10 +106,10 @@ public class KeyboardShortcutPreferenceCompatActivity extends BaseActivity imple
}
mKeySpec = spec;
mKeysLabel.setText(spec.toKeyString());
final String oldAction = mKeyboardShortcutsHandler.findAction(spec);
final String oldAction = keyboardShortcutsHandler.findAction(spec);
final KeyboardShortcutSpec copyOfSpec = spec.copy();
copyOfSpec.setContextTag(null);
final String oldGeneralAction = mKeyboardShortcutsHandler.findAction(copyOfSpec);
final String oldGeneralAction = keyboardShortcutsHandler.findAction(copyOfSpec);
if (!TextUtils.isEmpty(oldAction) && !keyAction.equals(oldAction)) {
// Conflicts with keys in same context tag
mConflictLabel.setVisibility(View.VISIBLE);

View File

@ -1,57 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.activity;
import android.app.Activity;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import org.mariotaku.twidere.BuildConfig;
import org.mariotaku.twidere.util.StrictModeUtils;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
public class MainActivity extends Activity {
@Override
protected void onCreate(final Bundle savedInstanceState) {
if (BuildConfig.DEBUG) {
StrictModeUtils.detectAllVmPolicy();
StrictModeUtils.detectAllThreadPolicy();
}
super.onCreate(savedInstanceState);
if (Utils.checkDeviceCompatible()) {
final Intent intent = new Intent(this, HomeActivity.class);
startActivity(intent);
} else {
final Intent intent = new Intent(this, IncompatibleAlertActivity.class);
startActivity(intent);
}
finish();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
ThemeUtils.fixNightMode(getResources(), newConfig);
super.onConfigurationChanged(newConfig);
}
}

View File

@ -171,13 +171,13 @@ public final class MediaViewerActivity extends BaseActivity implements IExtended
CacheDownloadMediaViewerFragment f = (CacheDownloadMediaViewerFragment) object;
final boolean running = f.getLoaderManager().hasRunningLoaders();
final boolean downloaded = f.hasDownloadedData();
MenuUtils.setMenuItemAvailability(menu, R.id.refresh, !running && !downloaded);
MenuUtils.setMenuItemAvailability(menu, R.id.share, !running && downloaded);
MenuUtils.setMenuItemAvailability(menu, R.id.save, !running && downloaded);
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.refresh, !running && !downloaded);
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.share, !running && downloaded);
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.save, !running && downloaded);
} else {
MenuUtils.setMenuItemAvailability(menu, R.id.refresh, false);
MenuUtils.setMenuItemAvailability(menu, R.id.share, true);
MenuUtils.setMenuItemAvailability(menu, R.id.save, false);
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.refresh, false);
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.share, true);
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.save, false);
}
return true;
}

View File

@ -169,14 +169,14 @@ public class QuickSearchBarActivity extends BaseActivity implements OnClickListe
case SuggestionsAdapter.VIEW_TYPE_USER_SUGGESTION_ITEM: {
IntentUtils.openUserProfile(this, getSelectedAccountKey(),
UserKey.valueOf(item.extra_id), item.summary, null,
mPreferences.getBoolean(KEY_NEW_DOCUMENT_API),
preferences.getBoolean(KEY_NEW_DOCUMENT_API),
Referral.DIRECT);
finish();
break;
}
case SuggestionsAdapter.VIEW_TYPE_USER_SCREEN_NAME: {
IntentUtils.openUserProfile(this, getSelectedAccountKey(), null, item.title, null,
mPreferences.getBoolean(KEY_NEW_DOCUMENT_API), Referral.DIRECT);
preferences.getBoolean(KEY_NEW_DOCUMENT_API), Referral.DIRECT);
finish();
break;
}
@ -346,8 +346,8 @@ public class QuickSearchBarActivity extends BaseActivity implements OnClickListe
super(activity, null, 0);
mRemovedPositions = new SortableIntList();
mActivity = activity;
mMediaLoader = activity.mMediaLoader;
mUserColorNameManager = activity.mUserColorNameManager;
mMediaLoader = activity.mediaLoader;
mUserColorNameManager = activity.userColorNameManager;
mInflater = LayoutInflater.from(activity);
}

View File

@ -54,7 +54,7 @@ public class RequestPermissionsActivity extends BaseActivity implements OnClickL
public void onClick(final View view) {
switch (view.getId()) {
case R.id.accept: {
mPermissionsManager.accept(mCallingPackage, mPermissions);
permissionsManager.accept(mCallingPackage, mPermissions);
setResult(RESULT_OK);
finish();
break;
@ -91,7 +91,7 @@ public class RequestPermissionsActivity extends BaseActivity implements OnClickL
finish();
return;
}
if (mPermissionsManager.isDenied(caller)) {
if (permissionsManager.isDenied(caller)) {
setResult(RESULT_CANCELED);
finish();
return;

View File

@ -1,696 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.activity;
import android.Manifest;
import android.app.Activity;
import android.app.Dialog;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AlertDialog;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceManager;
import android.support.v7.preference.PreferenceScreen;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import com.afollestad.appthemeengine.Config;
import com.afollestad.appthemeengine.util.ATEUtil;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.SupportTabsAdapter;
import org.mariotaku.twidere.annotation.CustomTabType;
import org.mariotaku.twidere.fragment.BaseDialogFragment;
import org.mariotaku.twidere.fragment.BasePreferenceFragment;
import org.mariotaku.twidere.fragment.BaseSupportFragment;
import org.mariotaku.twidere.fragment.DirectMessagesFragment;
import org.mariotaku.twidere.fragment.HomeTimelineFragment;
import org.mariotaku.twidere.fragment.InteractionsTimelineFragment;
import org.mariotaku.twidere.fragment.MessagesEntriesFragment;
import org.mariotaku.twidere.fragment.ProgressDialogFragment;
import org.mariotaku.twidere.model.CustomTabConfiguration;
import org.mariotaku.twidere.model.SupportTabSpec;
import org.mariotaku.twidere.preference.WizardPageHeaderPreference;
import org.mariotaku.twidere.preference.WizardPageNavPreference;
import org.mariotaku.twidere.provider.TwidereDataStore.Tabs;
import org.mariotaku.twidere.util.AsyncTaskUtils;
import org.mariotaku.twidere.util.CustomTabUtils;
import org.mariotaku.twidere.util.InternalParseUtils;
import org.mariotaku.twidere.util.ParseUtils;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.TwidereMathUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.LinePageIndicator;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class SettingsWizardActivity extends BaseActivity {
public static final String WIZARD_PREFERENCE_KEY_NEXT_PAGE = "next_page";
public static final String WIZARD_PREFERENCE_KEY_USE_DEFAULTS = "use_defaults";
public static final String WIZARD_PREFERENCE_KEY_EDIT_CUSTOM_TABS = "edit_custom_tabs";
public static final String WIZARD_PREFERENCE_KEY_IMPORT_SETTINGS = "import_settings";
private static final int REQUEST_IMPORT_SETTINGS = 201;
private ViewPager mViewPager;
private LinePageIndicator mIndicator;
private SupportTabsAdapter mAdapter;
private AbsInitialSettingsTask mTask;
public void applyInitialSettings() {
if (mTask != null && mTask.getStatus() == AsyncTask.Status.RUNNING) return;
mTask = new InitialSettingsTask(this);
AsyncTaskUtils.executeTask(mTask);
}
public void applyInitialTabSettings() {
if (mTask != null && mTask.getStatus() == AsyncTask.Status.RUNNING) return;
mTask = new InitialTabSettingsTask(this);
AsyncTaskUtils.executeTask(mTask);
}
public void exitWizard() {
final SharedPreferences prefs = getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE);
prefs.edit().putBoolean(KEY_SETTINGS_WIZARD_COMPLETED, true).apply();
final Intent intent = new Intent(this, HomeActivity.class);
intent.putExtra(EXTRA_OPEN_ACCOUNTS_DRAWER, true);
startActivity(intent);
finish();
}
public void gotoFinishPage() {
if (mViewPager == null || mAdapter == null) return;
final int last = mAdapter.getCount() - 1;
mViewPager.setCurrentItem(Math.max(last, 0));
}
public void gotoLastPage() {
if (mViewPager == null || mAdapter == null) return;
gotoPage(getPageCount() - 2);
}
public void gotoNextPage() {
if (mViewPager == null || mAdapter == null) return;
final int current = mViewPager.getCurrentItem();
mViewPager.setCurrentItem(TwidereMathUtils.clamp(current + 1, mAdapter.getCount() - 1, 0));
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
@Override
public void onContentChanged() {
super.onContentChanged();
mViewPager = (ViewPager) findViewById(R.id.pager);
mIndicator = (LinePageIndicator) findViewById(R.id.indicator);
}
@Override
public int getStatusBarColor() {
if (VALUE_THEME_NAME_DARK.equals(getATEKey())) return Color.BLACK;
return ATEUtil.darkenColor(ThemeUtils.getColorBackground(this));
}
@Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
switch (requestCode) {
case REQUEST_IMPORT_SETTINGS: {
if (resultCode == RESULT_OK) {
gotoLastPage();
} else {
gotoNextPage();
}
break;
}
default: {
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public String getThemeBackgroundOption() {
return ThemeUtils.getThemeBackgroundOption(this);
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings_wizard);
mAdapter = new SupportTabsAdapter(this, getSupportFragmentManager(), null);
mViewPager.setAdapter(mAdapter);
mViewPager.setEnabled(false);
mIndicator.setViewPager(mViewPager);
mIndicator.setSelectedColor(Config.accentColor(this, getATEKey()));
initPages();
final int initialPage = getIntent().getIntExtra(EXTRA_PAGE, -1);
if (initialPage != -1) {
mViewPager.setCurrentItem(initialPage, false);
}
}
private void initPages() {
mAdapter.addTab(WizardPageWelcomeFragment.class, null, getString(R.string.wizard_page_welcome_title), null, 0, null);
mAdapter.addTab(WizardPageThemeFragment.class, null, getString(R.string.theme), null, 0, null);
mAdapter.addTab(WizardPageTabsFragment.class, null, getString(R.string.tabs), null, 0, null);
mAdapter.addTab(WizardPageCardsFragment.class, null, getString(R.string.cards), null, 0, null);
mAdapter.addTab(WizardPageUsageStatisticsFragment.class, null, getString(R.string.usage_statistics), null, 0, null);
mAdapter.addTab(WizardPageHintsFragment.class, null, getString(R.string.hints), null, 0, null);
mAdapter.addTab(WizardPageFinishedFragment.class, null, getString(R.string.wizard_page_finished_title), null, 0, null);
}
private void openImportSettingsDialog() {
final Intent intent = new Intent(this, DataImportActivity.class);
startActivityForResult(intent, REQUEST_IMPORT_SETTINGS);
}
public static abstract class BaseWizardPageFragment extends BasePreferenceFragment implements
Preference.OnPreferenceClickListener {
public void gotoFinishPage() {
final Activity a = getActivity();
if (a instanceof SettingsWizardActivity) {
((SettingsWizardActivity) a).gotoFinishPage();
}
}
public void gotoLastPage() {
final Activity a = getActivity();
if (a instanceof SettingsWizardActivity) {
((SettingsWizardActivity) a).gotoLastPage();
}
}
public void gotoNextPage() {
final Activity a = getActivity();
if (a instanceof SettingsWizardActivity) {
((SettingsWizardActivity) a).gotoNextPage();
}
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
final PreferenceManager preferenceManager = getPreferenceManager();
preferenceManager.setSharedPreferencesName(SHARED_PREFERENCES_NAME);
addPreferencesFromResource(getPreferenceResource());
final Context context = getActivity();
final Preference wizardHeader = new WizardPageHeaderPreference(context);
wizardHeader.setTitle(getHeaderTitle());
wizardHeader.setSummary(getHeaderSummary());
wizardHeader.setOrder(0);
final PreferenceScreen screen = getPreferenceScreen();
screen.addPreference(wizardHeader);
final int nextPageTitle = getNextPageTitle();
if (nextPageTitle != 0) {
final Preference nextPage = new WizardPageNavPreference(context);
nextPage.setOrder(999);
nextPage.setKey(WIZARD_PREFERENCE_KEY_NEXT_PAGE);
nextPage.setTitle(nextPageTitle);
nextPage.setOnPreferenceClickListener(this);
screen.addPreference(nextPage);
}
final Preference.OnPreferenceChangeListener listener = new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final Bundle extras = preference.getExtras();
if (extras != null && extras.getBoolean(EXTRA_RESTART_ACTIVITY)) {
((SettingsWizardActivity) getActivity()).restartWithCurrentPage();
return true;
}
return true;
}
};
for (int i = 0, j = screen.getPreferenceCount(); i < j; i++) {
screen.getPreference(i).setOnPreferenceChangeListener(listener);
}
}
@Override
public boolean onPreferenceClick(final Preference preference) {
if (WIZARD_PREFERENCE_KEY_NEXT_PAGE.equals(preference.getKey())) {
gotoNextPage();
}
return true;
}
protected abstract int getHeaderSummary();
protected abstract int getHeaderTitle();
protected int getNextPageTitle() {
return R.string.next_step;
}
protected abstract int getPreferenceResource();
}
private void restartWithCurrentPage() {
final Intent intent = getIntent();
intent.putExtra(EXTRA_PAGE, mViewPager.getCurrentItem());
setIntent(intent);
recreate();
}
public static class WizardPageCardsFragment extends BaseWizardPageFragment {
@Override
protected int getHeaderSummary() {
return R.string.wizard_page_cards_text;
}
@Override
protected int getHeaderTitle() {
return R.string.cards;
}
@Override
protected int getPreferenceResource() {
return R.xml.preferences_cards;
}
}
public static class WizardPageFinishedFragment extends BaseSupportFragment implements OnClickListener {
@Override
public void onClick(final View v) {
final Activity a = getActivity();
if (a instanceof SettingsWizardActivity) {
((SettingsWizardActivity) a).exitWizard();
}
}
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
final Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_wizard_page_finished, container, false);
view.findViewById(R.id.exit_wizard).setOnClickListener(this);
return view;
}
}
public static class WizardPageUsageStatisticsFragment extends BaseWizardPageFragment {
@Override
protected int getHeaderSummary() {
return R.string.wizard_page_usage_statistics_text;
}
@Override
protected int getHeaderTitle() {
return R.string.usage_statistics;
}
@Override
protected int getNextPageTitle() {
return R.string.next_step;
}
@Override
protected int getPreferenceResource() {
return R.xml.settings_wizard_page_usage_statistics;
}
}
public static class WizardPageHintsFragment extends BaseWizardPageFragment {
@Override
protected int getHeaderSummary() {
return R.string.wizard_page_hints_text;
}
@Override
protected int getHeaderTitle() {
return R.string.hints;
}
@Override
protected int getNextPageTitle() {
return R.string.finish;
}
@Override
protected int getPreferenceResource() {
return R.xml.settings_wizard_page_hints;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
super.gotoNextPage();
}
@Override
public void gotoNextPage() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE};
requestPermissions(permissions, REQUEST_REQUEST_PERMISSIONS);
} else {
// Try getting location, some custom rom will popup requirement dialog
Utils.getCachedLocation(getActivity());
super.gotoNextPage();
}
}
}
public static class WizardPageTabsFragment extends BaseWizardPageFragment {
private static final int REQUEST_CUSTOM_TABS = 1;
public void applyInitialTabSettings() {
final Activity a = getActivity();
if (a instanceof SettingsWizardActivity) {
((SettingsWizardActivity) a).applyInitialTabSettings();
}
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
findPreference(WIZARD_PREFERENCE_KEY_EDIT_CUSTOM_TABS).setOnPreferenceClickListener(this);
findPreference(WIZARD_PREFERENCE_KEY_USE_DEFAULTS).setOnPreferenceClickListener(this);
}
@Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
switch (requestCode) {
case REQUEST_CUSTOM_TABS:
if (resultCode != RESULT_OK) {
new TabsUnchangedDialogFragment().show(getFragmentManager(), "tabs_unchanged");
} else {
gotoNextPage();
}
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public boolean onPreferenceClick(final Preference preference) {
final String key = preference.getKey();
if (WIZARD_PREFERENCE_KEY_EDIT_CUSTOM_TABS.equals(key)) {
final Intent intent = new Intent(getActivity(), SettingsActivity.class);
intent.putExtra(SettingsActivity.EXTRA_INITIAL_TAG, "tabs");
startActivityForResult(intent, REQUEST_CUSTOM_TABS);
} else if (WIZARD_PREFERENCE_KEY_USE_DEFAULTS.equals(key)) {
applyInitialTabSettings();
}
return true;
}
@Override
protected int getHeaderSummary() {
return R.string.wizard_page_tabs_text;
}
@Override
protected int getHeaderTitle() {
return R.string.tabs;
}
@Override
protected int getNextPageTitle() {
return 0;
}
@Override
protected int getPreferenceResource() {
return R.xml.settings_wizard_page_tab;
}
public static class TabsUnchangedDialogFragment extends BaseDialogFragment implements
DialogInterface.OnClickListener {
@Override
public void onCancel(final DialogInterface dialog) {
gotoNextPage();
}
@Override
public void onClick(final DialogInterface dialog, final int which) {
gotoNextPage();
}
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(R.string.wizard_page_tabs_unchanged_message);
builder.setPositiveButton(android.R.string.ok, this);
return builder.create();
}
private void gotoNextPage() {
final Activity a = getActivity();
if (a instanceof SettingsWizardActivity) {
((SettingsWizardActivity) a).gotoNextPage();
}
}
}
}
public static class WizardPageThemeFragment extends BaseWizardPageFragment implements Preference.OnPreferenceClickListener {
@Override
protected int getHeaderSummary() {
return R.string.wizard_page_theme_text;
}
@Override
protected int getHeaderTitle() {
return R.string.theme;
}
@Override
protected int getPreferenceResource() {
return R.xml.preferences_theme;
}
}
public static class WizardPageWelcomeFragment extends BaseWizardPageFragment implements Preference.OnPreferenceClickListener {
public void applyInitialSettings() {
final Activity a = getActivity();
if (a instanceof SettingsWizardActivity) {
((SettingsWizardActivity) a).applyInitialSettings();
}
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
findPreference(WIZARD_PREFERENCE_KEY_NEXT_PAGE).setOnPreferenceClickListener(this);
findPreference(WIZARD_PREFERENCE_KEY_USE_DEFAULTS).setOnPreferenceClickListener(this);
findPreference(WIZARD_PREFERENCE_KEY_IMPORT_SETTINGS).setOnPreferenceClickListener(this);
}
@Override
public boolean onPreferenceClick(final Preference preference) {
final String key = preference.getKey();
if (WIZARD_PREFERENCE_KEY_NEXT_PAGE.equals(key)) {
gotoNextPage();
} else if (WIZARD_PREFERENCE_KEY_USE_DEFAULTS.equals(key)) {
applyInitialSettings();
} else if (WIZARD_PREFERENCE_KEY_IMPORT_SETTINGS.equals(key)) {
openImportSettingsDialog();
}
return true;
}
@Override
protected int getHeaderSummary() {
return R.string.wizard_page_welcome_text;
}
@Override
protected int getHeaderTitle() {
return R.string.wizard_page_welcome_title;
}
@Override
protected int getNextPageTitle() {
return 0;
}
@Override
protected int getPreferenceResource() {
return R.xml.settings_wizard_page_welcome;
}
private void openImportSettingsDialog() {
final Activity a = getActivity();
if (a instanceof SettingsWizardActivity) {
((SettingsWizardActivity) a).openImportSettingsDialog();
}
}
}
static abstract class AbsInitialSettingsTask extends AsyncTask<Object, Object, Boolean> {
private static final String FRAGMENT_TAG = "initial_settings_dialog";
private static final String[] DEFAULT_TAB_TYPES = {CustomTabType.HOME_TIMELINE,
CustomTabType.NOTIFICATIONS_TIMELINE, CustomTabType.TRENDS_SUGGESTIONS,
CustomTabType.DIRECT_MESSAGES};
private final SettingsWizardActivity mActivity;
AbsInitialSettingsTask(final SettingsWizardActivity activity) {
mActivity = activity;
}
@Override
protected Boolean doInBackground(final Object... params) {
final ContentResolver resolver = mActivity.getContentResolver();
final List<SupportTabSpec> tabs = CustomTabUtils.getHomeTabs(mActivity);
if (wasConfigured(tabs)) return true;
Collections.sort(tabs);
int i = 0;
final List<ContentValues> values_list = new ArrayList<>();
for (final String type : DEFAULT_TAB_TYPES) {
final ContentValues values = new ContentValues();
final CustomTabConfiguration conf = CustomTabUtils.getTabConfiguration(type);
values.put(Tabs.TYPE, type);
values.put(Tabs.ICON, CustomTabUtils.findTabIconKey(conf.getDefaultIcon()));
values.put(Tabs.POSITION, i++);
values_list.add(values);
}
for (final SupportTabSpec spec : tabs) {
final String type = CustomTabUtils.findTabType(spec.cls);
if (type != null) {
final ContentValues values = new ContentValues();
values.put(Tabs.TYPE, type);
values.put(Tabs.ARGUMENTS, InternalParseUtils.bundleToJSON(spec.args));
values.put(Tabs.NAME, ParseUtils.parseString(spec.name));
if (spec.icon instanceof Integer) {
values.put(Tabs.ICON, CustomTabUtils.findTabIconKey((Integer) spec.icon));
} else if (spec.icon instanceof File) {
values.put(Tabs.ICON, ((File) spec.icon).getPath());
}
values.put(Tabs.POSITION, i++);
}
}
resolver.delete(Tabs.CONTENT_URI, null, null);
resolver.bulkInsert(Tabs.CONTENT_URI, values_list.toArray(new ContentValues[values_list.size()]));
return true;
}
protected SettingsWizardActivity getActivity() {
return mActivity;
}
protected abstract void nextStep();
@Override
protected void onPostExecute(final Boolean result) {
final FragmentManager fm = mActivity.getSupportFragmentManager();
final DialogFragment f = (DialogFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (f != null) {
f.dismiss();
}
nextStep();
}
@Override
protected void onPreExecute() {
ProgressDialogFragment.show(mActivity, FRAGMENT_TAG).setCancelable(false);
}
private boolean wasConfigured(final List<SupportTabSpec> tabs) {
for (final SupportTabSpec spec : tabs) {
if (spec.cls == HomeTimelineFragment.class
|| spec.cls == InteractionsTimelineFragment.class
|| spec.cls == DirectMessagesFragment.class
|| spec.cls == MessagesEntriesFragment.class) return true;
}
return false;
}
}
static class InitialSettingsTask extends AbsInitialSettingsTask {
InitialSettingsTask(final SettingsWizardActivity activity) {
super(activity);
}
@Override
protected void nextStep() {
final SettingsWizardActivity activity = getActivity();
activity.gotoPage(activity.getPageCount() - 3);
}
}
private void gotoPage(int page) {
mViewPager.setCurrentItem(TwidereMathUtils.clamp(page, 0, getPageCount() - 1));
}
private int getPageCount() {
return mAdapter.getCount();
}
static class InitialTabSettingsTask extends AbsInitialSettingsTask {
InitialTabSettingsTask(final SettingsWizardActivity activity) {
super(activity);
}
@Override
protected void nextStep() {
getActivity().gotoNextPage();
}
}
}

View File

@ -346,10 +346,10 @@ public class SignInActivity extends BaseActivity implements OnClickListener, Tex
ViewCompat.setBackgroundTintList(mSignInButton, color);
final String consumerKey = mPreferences.getString(KEY_CONSUMER_KEY, null);
final String consumerSecret = mPreferences.getString(KEY_CONSUMER_SECRET, null);
final String consumerKey = preferences.getString(KEY_CONSUMER_KEY, null);
final String consumerSecret = preferences.getString(KEY_CONSUMER_SECRET, null);
if (BuildConfig.SHOW_CUSTOM_TOKEN_DIALOG && savedInstanceState == null &&
!mPreferences.getBoolean(KEY_CONSUMER_KEY_SECRET_SET, false) &&
!preferences.getBoolean(KEY_CONSUMER_KEY_SECRET_SET, false) &&
!Utils.isCustomConsumerKeySecret(consumerKey, consumerSecret)) {
final SetConsumerKeySecretDialogFragment df = new SetConsumerKeySecretDialogFragment();
df.setCancelable(false);
@ -396,14 +396,14 @@ public class SignInActivity extends BaseActivity implements OnClickListener, Tex
private void setDefaultAPI() {
final long apiLastChange = mPreferences.getLong(KEY_API_LAST_CHANGE, mAPIChangeTimestamp);
final long apiLastChange = preferences.getLong(KEY_API_LAST_CHANGE, mAPIChangeTimestamp);
final boolean defaultApiChanged = apiLastChange != mAPIChangeTimestamp;
final String apiUrlFormat = Utils.getNonEmptyString(mPreferences, KEY_API_URL_FORMAT, DEFAULT_TWITTER_API_URL_FORMAT);
final int authType = mPreferences.getInt(KEY_AUTH_TYPE, AuthType.OAUTH);
final boolean sameOAuthSigningUrl = mPreferences.getBoolean(KEY_SAME_OAUTH_SIGNING_URL, false);
final boolean noVersionSuffix = mPreferences.getBoolean(KEY_NO_VERSION_SUFFIX, false);
final String consumerKey = Utils.getNonEmptyString(mPreferences, KEY_CONSUMER_KEY, TWITTER_CONSUMER_KEY);
final String consumerSecret = Utils.getNonEmptyString(mPreferences, KEY_CONSUMER_SECRET, TWITTER_CONSUMER_SECRET);
final String apiUrlFormat = Utils.getNonEmptyString(preferences, KEY_API_URL_FORMAT, DEFAULT_TWITTER_API_URL_FORMAT);
final int authType = preferences.getInt(KEY_AUTH_TYPE, AuthType.OAUTH);
final boolean sameOAuthSigningUrl = preferences.getBoolean(KEY_SAME_OAUTH_SIGNING_URL, false);
final boolean noVersionSuffix = preferences.getBoolean(KEY_NO_VERSION_SUFFIX, false);
final String consumerKey = Utils.getNonEmptyString(preferences, KEY_CONSUMER_KEY, TWITTER_CONSUMER_KEY);
final String consumerSecret = Utils.getNonEmptyString(preferences, KEY_CONSUMER_SECRET, TWITTER_CONSUMER_SECRET);
if (TextUtils.isEmpty(mAPIUrlFormat) || defaultApiChanged) {
mAPIUrlFormat = apiUrlFormat;
}

View File

@ -1,55 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.fragment.SettingsDetailsFragment;
public class UsageStatisticsActivity extends BaseActivity {
@Override
protected void onDestroy() {
if (!mPreferences.contains(KEY_USAGE_STATISTICS)) {
final SharedPreferences.Editor editor = mPreferences.edit();
editor.putBoolean(KEY_USAGE_STATISTICS, mPreferences.getBoolean(KEY_USAGE_STATISTICS));
editor.apply();
}
super.onDestroy();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Bundle fragmentArgs = new Bundle();
fragmentArgs.putInt(EXTRA_RESID, R.xml.preferences_usage_statistics);
final FragmentManager fm = getSupportFragmentManager();
final FragmentTransaction ft = fm.beginTransaction();
ft.replace(android.R.id.content, Fragment.instantiate(this,
SettingsDetailsFragment.class.getName(), fragmentArgs));
ft.commit();
}
}

View File

@ -196,12 +196,12 @@ public class UserListSelectorActivity extends BaseActivity implements OnClickLis
@Override
protected void onStart() {
super.onStart();
mBus.register(this);
bus.register(this);
}
@Override
protected void onStop() {
mBus.unregister(this);
bus.unregister(this);
super.onStop();
}

View File

@ -17,16 +17,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.activity.iface;
package org.mariotaku.twidere.activity.iface
public interface IThemedActivity {
interface IThemedActivity {
int getCurrentThemeBackgroundAlpha();
val currentThemeBackgroundAlpha: Int
String getCurrentThemeBackgroundOption();
val currentThemeBackgroundOption: String
int getThemeBackgroundAlpha();
val themeBackgroundAlpha: Int
String getThemeBackgroundOption();
val themeBackgroundOption: String
}

View File

@ -22,6 +22,7 @@ package org.mariotaku.twidere.adapter;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.support.annotation.NonNull;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.adapter.iface.IBaseAdapter;
@ -67,7 +68,7 @@ public class BaseArrayAdapter<T> extends ArrayAdapter<T> implements Constants, I
super(context, layoutRes, collection);
//noinspection unchecked
GeneralComponentHelper.build(context).inject((BaseArrayAdapter<Object>) this);
final TwidereApplication app = TwidereApplication.getInstance(context);
final TwidereApplication app = TwidereApplication.Companion.getInstance(context);
mLinkify = new TwidereLinkify(new OnLinkClickHandler(context, mMultiSelectManager, mPreferences));
mNicknamePrefs = context.getSharedPreferences(USER_NICKNAME_PREFERENCES_NAME, Context.MODE_PRIVATE);
mColorPrefs = context.getSharedPreferences(USER_COLOR_PREFERENCES_NAME, Context.MODE_PRIVATE);
@ -75,6 +76,7 @@ public class BaseArrayAdapter<T> extends ArrayAdapter<T> implements Constants, I
mColorPrefs.registerOnSharedPreferenceChangeListener(this);
}
@NonNull
@Override
public MediaLoaderWrapper getImageLoader() {
return mImageLoader;
@ -128,7 +130,7 @@ public class BaseArrayAdapter<T> extends ArrayAdapter<T> implements Constants, I
}
@Override
public final void setLinkHighlightOption(final String option) {
public final void setLinkHighlightOption(@NonNull final String option) {
final int optionInt = Utils.getLinkHighlightingStyleInt(option);
mLinkify.setHighlightOption(optionInt);
if (optionInt == mLinkHighlightOption) return;

View File

@ -42,8 +42,8 @@ public class SourceAutoCompleteAdapter extends SimpleCursorAdapter {
public SourceAutoCompleteAdapter(final Context context) {
super(context, android.R.layout.simple_list_item_1, null, FROM, TO, 0);
final TwidereApplication app = TwidereApplication.getInstance(context);
mDatabase = app.getSQLiteDatabase();
final TwidereApplication app = TwidereApplication.Companion.getInstance(context);
mDatabase = app.getSqLiteDatabase();
}
@Override

View File

@ -1,421 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.app;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.PackageManager;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.multidex.MultiDex;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatDelegate;
import android.support.v7.widget.ActionBarContextView;
import android.widget.ImageView;
import android.widget.TextView;
import com.afollestad.appthemeengine.ATE;
import com.afollestad.appthemeengine.Config;
import com.pnikosis.materialishprogress.ProgressWheel;
import com.rengwuxian.materialedittext.MaterialEditText;
import org.apache.commons.lang3.ArrayUtils;
import org.mariotaku.twidere.BuildConfig;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.AssistLauncherActivity;
import org.mariotaku.twidere.activity.MainActivity;
import org.mariotaku.twidere.activity.MainHondaJOJOActivity;
import org.mariotaku.twidere.service.RefreshService;
import org.mariotaku.twidere.util.BugReporter;
import org.mariotaku.twidere.util.DebugModeUtils;
import org.mariotaku.twidere.util.ExternalThemeManager;
import org.mariotaku.twidere.util.HttpClientFactory;
import org.mariotaku.twidere.util.StrictModeUtils;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.TwidereBugReporter;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.content.TwidereSQLiteOpenHelper;
import org.mariotaku.twidere.util.dagger.DependencyHolder;
import org.mariotaku.twidere.util.net.TwidereDns;
import org.mariotaku.twidere.util.theme.ActionBarContextViewViewProcessor;
import org.mariotaku.twidere.util.theme.FloatingActionButtonViewProcessor;
import org.mariotaku.twidere.util.theme.FontFamilyTagProcessor;
import org.mariotaku.twidere.util.theme.IconActionButtonTagProcessor;
import org.mariotaku.twidere.util.theme.ImageViewViewProcessor;
import org.mariotaku.twidere.util.theme.MaterialEditTextViewProcessor;
import org.mariotaku.twidere.util.theme.OptimalLinkColorTagProcessor;
import org.mariotaku.twidere.util.theme.ProfileImageViewViewProcessor;
import org.mariotaku.twidere.util.theme.ProgressWheelViewProcessor;
import org.mariotaku.twidere.util.theme.SwipeRefreshLayoutViewProcessor;
import org.mariotaku.twidere.util.theme.TabPagerIndicatorViewProcessor;
import org.mariotaku.twidere.util.theme.TextViewViewProcessor;
import org.mariotaku.twidere.util.theme.TimelineContentTextViewViewProcessor;
import org.mariotaku.twidere.view.ProfileImageView;
import org.mariotaku.twidere.view.TabPagerIndicator;
import org.mariotaku.twidere.view.ThemedMultiValueSwitch;
import org.mariotaku.twidere.view.TimelineContentTextView;
public class TwidereApplication extends Application implements Constants,
OnSharedPreferenceChangeListener {
private static final String KEY_UCD_DATA_PROFILING = "ucd_data_profiling";
private static final String KEY_SPICE_DATA_PROFILING = "spice_data_profiling";
private static final String KEY_KEYBOARD_SHORTCUT_INITIALIZED = "keyboard_shortcut_initialized";
private static TwidereApplication sInstance;
private Handler mHandler;
private SharedPreferences mPreferences;
private SQLiteOpenHelper mSQLiteOpenHelper;
private SQLiteDatabase mDatabase;
private ProfileImageViewViewProcessor mProfileImageViewViewProcessor;
private FontFamilyTagProcessor mFontFamilyTagProcessor;
@NonNull
public static TwidereApplication getInstance(@NonNull final Context context) {
return (TwidereApplication) context.getApplicationContext();
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
public Handler getHandler() {
return mHandler;
}
public void initKeyboardShortcuts() {
final SharedPreferences preferences = getSharedPreferences();
if (!preferences.getBoolean(KEY_KEYBOARD_SHORTCUT_INITIALIZED, false)) {
// getApplicationModule().getKeyboardShortcutsHandler().reset();
preferences.edit().putBoolean(KEY_KEYBOARD_SHORTCUT_INITIALIZED, true).apply();
}
}
public SQLiteDatabase getSQLiteDatabase() {
if (mDatabase != null) return mDatabase;
StrictModeUtils.checkDiskIO();
return mDatabase = getSQLiteOpenHelper().getWritableDatabase();
}
public SQLiteOpenHelper getSQLiteOpenHelper() {
if (mSQLiteOpenHelper != null) return mSQLiteOpenHelper;
return mSQLiteOpenHelper = new TwidereSQLiteOpenHelper(this, DATABASES_NAME, DATABASES_VERSION);
}
@Override
public void onCreate() {
sInstance = this;
if (BuildConfig.DEBUG) {
StrictModeUtils.detectAllVmPolicy();
}
final SharedPreferences preferences = getSharedPreferences();
resetTheme(preferences);
super.onCreate();
mProfileImageViewViewProcessor = new ProfileImageViewViewProcessor();
mFontFamilyTagProcessor = new FontFamilyTagProcessor();
ATE.registerViewProcessor(TabPagerIndicator.class, new TabPagerIndicatorViewProcessor());
ATE.registerViewProcessor(FloatingActionButton.class, new FloatingActionButtonViewProcessor());
ATE.registerViewProcessor(ActionBarContextView.class, new ActionBarContextViewViewProcessor());
ATE.registerViewProcessor(SwipeRefreshLayout.class, new SwipeRefreshLayoutViewProcessor());
ATE.registerViewProcessor(TimelineContentTextView.class, new TimelineContentTextViewViewProcessor());
ATE.registerViewProcessor(TextView.class, new TextViewViewProcessor());
ATE.registerViewProcessor(ImageView.class, new ImageViewViewProcessor());
ATE.registerViewProcessor(MaterialEditText.class, new MaterialEditTextViewProcessor());
ATE.registerViewProcessor(ProgressWheel.class, new ProgressWheelViewProcessor());
ATE.registerViewProcessor(ProfileImageView.class, mProfileImageViewViewProcessor);
ATE.registerTagProcessor(OptimalLinkColorTagProcessor.TAG, new OptimalLinkColorTagProcessor());
ATE.registerTagProcessor(FontFamilyTagProcessor.TAG, mFontFamilyTagProcessor);
ATE.registerTagProcessor(IconActionButtonTagProcessor.PREFIX_COLOR,
new IconActionButtonTagProcessor(IconActionButtonTagProcessor.PREFIX_COLOR));
ATE.registerTagProcessor(IconActionButtonTagProcessor.PREFIX_COLOR_ACTIVATED,
new IconActionButtonTagProcessor(IconActionButtonTagProcessor.PREFIX_COLOR_ACTIVATED));
ATE.registerTagProcessor(IconActionButtonTagProcessor.PREFIX_COLOR_DISABLED,
new IconActionButtonTagProcessor(IconActionButtonTagProcessor.PREFIX_COLOR_DISABLED));
ATE.registerTagProcessor(ThemedMultiValueSwitch.PREFIX_TINT, new ThemedMultiValueSwitch.TintTagProcessor());
mProfileImageViewViewProcessor.setStyle(Utils.getProfileImageStyle(preferences));
mFontFamilyTagProcessor.setFontFamily(ThemeUtils.getThemeFontFamily(preferences));
final int themeColor = preferences.getInt(KEY_THEME_COLOR, ContextCompat.getColor(this,
R.color.branding_color));
if (!ATE.config(this, VALUE_THEME_NAME_LIGHT).isConfigured()) {
//noinspection WrongConstant
ATE.config(this, VALUE_THEME_NAME_LIGHT)
.primaryColor(themeColor)
.accentColor(ThemeUtils.getOptimalAccentColor(themeColor, Color.BLACK))
.coloredActionBar(true)
.coloredStatusBar(true)
.commit();
}
if (!ATE.config(this, VALUE_THEME_NAME_DARK).isConfigured()) {
ATE.config(this, VALUE_THEME_NAME_DARK)
.accentColor(ThemeUtils.getOptimalAccentColor(themeColor, Color.WHITE))
.coloredActionBar(false)
.coloredStatusBar(true)
.statusBarColor(Color.BLACK)
.commit();
}
if (!ATE.config(this, null).isConfigured()) {
ATE.config(this, null)
.accentColor(ThemeUtils.getOptimalAccentColor(themeColor, Color.WHITE))
.coloredActionBar(false)
.coloredStatusBar(false)
.commit();
}
initializeAsyncTask();
initDebugMode();
initBugReport();
mHandler = new Handler();
final PackageManager pm = getPackageManager();
final ComponentName main = new ComponentName(this, MainActivity.class);
final ComponentName main2 = new ComponentName(this, MainHondaJOJOActivity.class);
final boolean mainDisabled = pm.getComponentEnabledSetting(main) != PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
final boolean main2Disabled = pm.getComponentEnabledSetting(main2) != PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
final boolean noEntry = mainDisabled && main2Disabled;
if (noEntry) {
pm.setComponentEnabledSetting(main, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
} else if (!mainDisabled) {
pm.setComponentEnabledSetting(main2, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
if (!Utils.isComposeNowSupported(this)) {
final ComponentName assist = new ComponentName(this, AssistLauncherActivity.class);
pm.setComponentEnabledSetting(assist, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
migrateUsageStatisticsPreferences();
Utils.startRefreshServiceIfNeeded(this);
DependencyHolder holder = DependencyHolder.get(this);
registerActivityLifecycleCallbacks(holder.getActivityTracker());
final IntentFilter packageFilter = new IntentFilter();
packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
packageFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
final String[] packages = getPackageManager().getPackagesForUid(uid);
DependencyHolder holder = DependencyHolder.get(context);
final ExternalThemeManager manager = holder.getExternalThemeManager();
if (ArrayUtils.contains(packages, manager.getEmojiPackageName())) {
manager.reloadEmojiPreferences();
}
}
}, packageFilter);
}
private void initDebugMode() {
DebugModeUtils.initForApplication(this);
}
private void initBugReport() {
final SharedPreferences preferences = getSharedPreferences();
if (!preferences.getBoolean(KEY_BUG_REPORTS, BuildConfig.DEBUG)) return;
BugReporter.setImplementation(new TwidereBugReporter());
BugReporter.init(this);
}
private void migrateUsageStatisticsPreferences() {
final SharedPreferences preferences = getSharedPreferences();
final boolean hasUsageStatistics = preferences.contains(KEY_USAGE_STATISTICS);
if (hasUsageStatistics) return;
if (preferences.contains(KEY_UCD_DATA_PROFILING) || preferences.contains(KEY_SPICE_DATA_PROFILING)) {
final boolean prevUsageEnabled = preferences.getBoolean(KEY_UCD_DATA_PROFILING, false)
|| preferences.getBoolean(KEY_SPICE_DATA_PROFILING, false);
final Editor editor = preferences.edit();
editor.putBoolean(KEY_USAGE_STATISTICS, prevUsageEnabled);
editor.remove(KEY_UCD_DATA_PROFILING);
editor.remove(KEY_SPICE_DATA_PROFILING);
editor.apply();
}
}
private SharedPreferences getSharedPreferences() {
if (mPreferences != null) return mPreferences;
mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE);
mPreferences.registerOnSharedPreferenceChangeListener(this);
return mPreferences;
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
}
@Override
public void onLowMemory() {
final DependencyHolder holder = DependencyHolder.get(this);
super.onLowMemory();
}
@Override
public void onSharedPreferenceChanged(final SharedPreferences preferences, final String key) {
switch (key) {
case KEY_REFRESH_INTERVAL: {
stopService(new Intent(this, RefreshService.class));
Utils.startRefreshServiceIfNeeded(this);
break;
}
case KEY_ENABLE_PROXY:
case KEY_PROXY_HOST:
case KEY_PROXY_PORT:
case KEY_PROXY_TYPE:
case KEY_PROXY_USERNAME:
case KEY_PROXY_PASSWORD:
case KEY_CONNECTION_TIMEOUT:
case KEY_RETRY_ON_NETWORK_ISSUE: {
HttpClientFactory.reloadConnectivitySettings(this);
break;
}
case KEY_DNS_SERVER:
case KEY_TCP_DNS_QUERY:
case KEY_BUILTIN_DNS_RESOLVER: {
reloadDnsSettings();
break;
}
case KEY_CONSUMER_KEY:
case KEY_CONSUMER_SECRET:
case KEY_API_URL_FORMAT:
case KEY_AUTH_TYPE:
case KEY_SAME_OAUTH_SIGNING_URL:
case KEY_THUMBOR_ENABLED:
case KEY_THUMBOR_ADDRESS:
case KEY_THUMBOR_SECURITY_KEY: {
final Editor editor = preferences.edit();
editor.putLong(KEY_API_LAST_CHANGE, System.currentTimeMillis());
editor.apply();
break;
}
case KEY_EMOJI_SUPPORT: {
DependencyHolder.get(this).getExternalThemeManager().reloadEmojiPreferences();
break;
}
case KEY_THEME: {
resetTheme(preferences);
Config.markChanged(this, VALUE_THEME_NAME_LIGHT, VALUE_THEME_NAME_DARK);
break;
}
case KEY_THEME_BACKGROUND: {
Config.markChanged(this, VALUE_THEME_NAME_LIGHT, VALUE_THEME_NAME_DARK);
break;
}
case KEY_PROFILE_IMAGE_STYLE: {
Config.markChanged(this, VALUE_THEME_NAME_LIGHT, VALUE_THEME_NAME_DARK);
mProfileImageViewViewProcessor.setStyle(Utils.getProfileImageStyle(preferences.getString(key, null)));
break;
}
case KEY_THEME_FONT_FAMILY: {
Config.markChanged(this, VALUE_THEME_NAME_LIGHT, VALUE_THEME_NAME_DARK);
mFontFamilyTagProcessor.setFontFamily(ThemeUtils.getThemeFontFamily(preferences));
break;
}
case KEY_THEME_COLOR: {
final int themeColor = preferences.getInt(key, ContextCompat.getColor(this,
R.color.branding_color));
//noinspection WrongConstant
ATE.config(this, VALUE_THEME_NAME_LIGHT)
.primaryColor(themeColor)
.accentColor(ThemeUtils.getOptimalAccentColor(themeColor, Color.BLACK))
.coloredActionBar(true)
.coloredStatusBar(true)
.commit();
ATE.config(this, VALUE_THEME_NAME_DARK)
.accentColor(ThemeUtils.getOptimalAccentColor(themeColor, Color.WHITE))
.coloredActionBar(false)
.coloredStatusBar(true)
.statusBarColor(Color.BLACK)
.commit();
ATE.config(this, null)
.accentColor(ThemeUtils.getOptimalAccentColor(themeColor, Color.BLACK))
.coloredActionBar(false)
.coloredStatusBar(false)
.commit();
break;
}
}
}
private void resetTheme(SharedPreferences preferences) {
switch (ThemeUtils.getLocalNightMode(preferences)) {
case AppCompatDelegate.MODE_NIGHT_AUTO: {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO);
break;
}
case AppCompatDelegate.MODE_NIGHT_YES: {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
break;
}
default: {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
break;
}
}
}
private void reloadDnsSettings() {
DependencyHolder holder = DependencyHolder.get(this);
final TwidereDns dns = holder.getDns();
dns.reloadDnsSettings();
}
private void initializeAsyncTask() {
// AsyncTask class needs to be loaded in UI thread.
// So we load it here to comply the rule.
try {
Class.forName(AsyncTask.class.getName());
} catch (final ClassNotFoundException ignore) {
}
}
@Nullable
public static TwidereApplication getInstance() {
return sInstance;
}
}

View File

@ -0,0 +1,319 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.app
import android.app.Application
import android.content.*
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.content.pm.PackageManager
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.graphics.Color
import android.os.AsyncTask
import android.os.Handler
import android.support.design.widget.FloatingActionButton
import android.support.multidex.MultiDex
import android.support.v4.content.ContextCompat
import android.support.v4.widget.SwipeRefreshLayout
import android.support.v7.app.AppCompatDelegate
import android.support.v7.widget.ActionBarContextView
import android.widget.ImageView
import android.widget.TextView
import com.afollestad.appthemeengine.ATE
import com.afollestad.appthemeengine.Config
import com.pnikosis.materialishprogress.ProgressWheel
import com.rengwuxian.materialedittext.MaterialEditText
import org.apache.commons.lang3.ArrayUtils
import org.mariotaku.twidere.BuildConfig
import org.mariotaku.twidere.Constants
import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.*
import org.mariotaku.twidere.activity.AssistLauncherActivity
import org.mariotaku.twidere.activity.MainActivity
import org.mariotaku.twidere.activity.MainHondaJOJOActivity
import org.mariotaku.twidere.service.RefreshService
import org.mariotaku.twidere.util.*
import org.mariotaku.twidere.util.content.TwidereSQLiteOpenHelper
import org.mariotaku.twidere.util.dagger.DependencyHolder
import org.mariotaku.twidere.util.theme.*
import org.mariotaku.twidere.view.ProfileImageView
import org.mariotaku.twidere.view.TabPagerIndicator
import org.mariotaku.twidere.view.ThemedMultiValueSwitch
import org.mariotaku.twidere.view.TimelineContentTextView
class TwidereApplication : Application(), Constants, OnSharedPreferenceChangeListener {
var handler: Handler? = null
private set
private var mPreferences: SharedPreferences? = null
private var mSQLiteOpenHelper: SQLiteOpenHelper? = null
private var profileImageViewViewProcessor: ProfileImageViewViewProcessor? = null
private var fontFamilyTagProcessor: FontFamilyTagProcessor? = null
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
MultiDex.install(this)
}
fun initKeyboardShortcuts() {
val preferences = sharedPreferences
if (!preferences.getBoolean(KEY_KEYBOARD_SHORTCUT_INITIALIZED, false)) {
// getApplicationModule().getKeyboardShortcutsHandler().reset();
preferences.edit().putBoolean(KEY_KEYBOARD_SHORTCUT_INITIALIZED, true).apply()
}
}
val sqLiteDatabase: SQLiteDatabase by lazy {
StrictModeUtils.checkDiskIO()
sqLiteOpenHelper.writableDatabase
}
val sqLiteOpenHelper: SQLiteOpenHelper by lazy {
TwidereSQLiteOpenHelper(this, Constants.DATABASES_NAME, Constants.DATABASES_VERSION)
}
override fun onCreate() {
instance = this
if (BuildConfig.DEBUG) {
StrictModeUtils.detectAllVmPolicy()
}
val preferences = sharedPreferences
resetTheme(preferences)
super.onCreate()
profileImageViewViewProcessor = ProfileImageViewViewProcessor()
fontFamilyTagProcessor = FontFamilyTagProcessor()
ATE.registerViewProcessor(TabPagerIndicator::class.java, TabPagerIndicatorViewProcessor())
ATE.registerViewProcessor(FloatingActionButton::class.java, FloatingActionButtonViewProcessor())
ATE.registerViewProcessor(ActionBarContextView::class.java, ActionBarContextViewViewProcessor())
ATE.registerViewProcessor(SwipeRefreshLayout::class.java, SwipeRefreshLayoutViewProcessor())
ATE.registerViewProcessor(TimelineContentTextView::class.java, TimelineContentTextViewViewProcessor())
ATE.registerViewProcessor(TextView::class.java, TextViewViewProcessor())
ATE.registerViewProcessor(ImageView::class.java, ImageViewViewProcessor())
ATE.registerViewProcessor(MaterialEditText::class.java, MaterialEditTextViewProcessor())
ATE.registerViewProcessor(ProgressWheel::class.java, ProgressWheelViewProcessor())
ATE.registerViewProcessor(ProfileImageView::class.java, profileImageViewViewProcessor!!)
ATE.registerTagProcessor(OptimalLinkColorTagProcessor.TAG, OptimalLinkColorTagProcessor())
ATE.registerTagProcessor(FontFamilyTagProcessor.TAG, fontFamilyTagProcessor!!)
ATE.registerTagProcessor(IconActionButtonTagProcessor.PREFIX_COLOR,
IconActionButtonTagProcessor(IconActionButtonTagProcessor.PREFIX_COLOR))
ATE.registerTagProcessor(IconActionButtonTagProcessor.PREFIX_COLOR_ACTIVATED,
IconActionButtonTagProcessor(IconActionButtonTagProcessor.PREFIX_COLOR_ACTIVATED))
ATE.registerTagProcessor(IconActionButtonTagProcessor.PREFIX_COLOR_DISABLED,
IconActionButtonTagProcessor(IconActionButtonTagProcessor.PREFIX_COLOR_DISABLED))
ATE.registerTagProcessor(ThemedMultiValueSwitch.PREFIX_TINT, ThemedMultiValueSwitch.TintTagProcessor())
profileImageViewViewProcessor!!.setStyle(Utils.getProfileImageStyle(preferences))
fontFamilyTagProcessor!!.setFontFamily(ThemeUtils.getThemeFontFamily(preferences))
val themeColor = preferences.getInt(KEY_THEME_COLOR, ContextCompat.getColor(this,
R.color.branding_color))
if (!ATE.config(this, VALUE_THEME_NAME_LIGHT).isConfigured) {
//noinspection WrongConstant
ATE.config(this, VALUE_THEME_NAME_LIGHT).primaryColor(themeColor).accentColor(ThemeUtils.getOptimalAccentColor(themeColor, Color.BLACK)).coloredActionBar(true).coloredStatusBar(true).commit()
}
if (!ATE.config(this, VALUE_THEME_NAME_DARK).isConfigured) {
ATE.config(this, VALUE_THEME_NAME_DARK).accentColor(ThemeUtils.getOptimalAccentColor(themeColor, Color.WHITE)).coloredActionBar(false).coloredStatusBar(true).statusBarColor(Color.BLACK).commit()
}
if (!ATE.config(this, null).isConfigured) {
ATE.config(this, null).accentColor(ThemeUtils.getOptimalAccentColor(themeColor, Color.WHITE)).coloredActionBar(false).coloredStatusBar(false).commit()
}
initializeAsyncTask()
initDebugMode()
initBugReport()
handler = Handler()
val pm = packageManager
val main = ComponentName(this, MainActivity::class.java)
val main2 = ComponentName(this, MainHondaJOJOActivity::class.java)
val mainDisabled = pm.getComponentEnabledSetting(main) != PackageManager.COMPONENT_ENABLED_STATE_ENABLED
val main2Disabled = pm.getComponentEnabledSetting(main2) != PackageManager.COMPONENT_ENABLED_STATE_ENABLED
val noEntry = mainDisabled && main2Disabled
if (noEntry) {
pm.setComponentEnabledSetting(main, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP)
} else if (!mainDisabled) {
pm.setComponentEnabledSetting(main2, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP)
}
if (!Utils.isComposeNowSupported(this)) {
val assist = ComponentName(this, AssistLauncherActivity::class.java)
pm.setComponentEnabledSetting(assist, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP)
}
migrateUsageStatisticsPreferences()
Utils.startRefreshServiceIfNeeded(this)
val holder = DependencyHolder.get(this)
registerActivityLifecycleCallbacks(holder.activityTracker)
val packageFilter = IntentFilter()
packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED)
packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED)
packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED)
packageFilter.addAction(Intent.ACTION_PACKAGE_REPLACED)
registerReceiver(object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val uid = intent.getIntExtra(Intent.EXTRA_UID, -1)
val packages = packageManager.getPackagesForUid(uid)
val holder = DependencyHolder.get(context)
val manager = holder.externalThemeManager
if (ArrayUtils.contains(packages, manager.emojiPackageName)) {
manager.reloadEmojiPreferences()
}
}
}, packageFilter)
}
private fun initDebugMode() {
DebugModeUtils.initForApplication(this)
}
private fun initBugReport() {
val preferences = sharedPreferences
if (!preferences.getBoolean(KEY_BUG_REPORTS, BuildConfig.DEBUG)) return
BugReporter.setImplementation(TwidereBugReporter())
BugReporter.init(this)
}
private fun migrateUsageStatisticsPreferences() {
val preferences = sharedPreferences
val hasUsageStatistics = preferences.contains(Constants.KEY_USAGE_STATISTICS)
if (hasUsageStatistics) return
if (preferences.contains(KEY_UCD_DATA_PROFILING) || preferences.contains(KEY_SPICE_DATA_PROFILING)) {
val prevUsageEnabled = preferences.getBoolean(KEY_UCD_DATA_PROFILING, false) || preferences.getBoolean(KEY_SPICE_DATA_PROFILING, false)
val editor = preferences.edit()
editor.putBoolean(Constants.KEY_USAGE_STATISTICS, prevUsageEnabled)
editor.remove(KEY_UCD_DATA_PROFILING)
editor.remove(KEY_SPICE_DATA_PROFILING)
editor.apply()
}
}
private val sharedPreferences: SharedPreferences by lazy {
val prefs = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
prefs.registerOnSharedPreferenceChangeListener(this)
prefs
}
override fun onTrimMemory(level: Int) {
super.onTrimMemory(level)
}
override fun onLowMemory() {
val holder = DependencyHolder.get(this)
super.onLowMemory()
}
override fun onSharedPreferenceChanged(preferences: SharedPreferences, key: String) {
when (key) {
KEY_REFRESH_INTERVAL -> {
stopService(Intent(this, RefreshService::class.java))
Utils.startRefreshServiceIfNeeded(this)
}
KEY_ENABLE_PROXY, KEY_PROXY_HOST, KEY_PROXY_PORT, KEY_PROXY_TYPE, KEY_PROXY_USERNAME, KEY_PROXY_PASSWORD, KEY_CONNECTION_TIMEOUT, KEY_RETRY_ON_NETWORK_ISSUE -> {
HttpClientFactory.reloadConnectivitySettings(this)
}
KEY_DNS_SERVER, KEY_TCP_DNS_QUERY, KEY_BUILTIN_DNS_RESOLVER -> {
reloadDnsSettings()
}
KEY_CONSUMER_KEY, KEY_CONSUMER_SECRET, KEY_API_URL_FORMAT, KEY_AUTH_TYPE, KEY_SAME_OAUTH_SIGNING_URL, KEY_THUMBOR_ENABLED, KEY_THUMBOR_ADDRESS, KEY_THUMBOR_SECURITY_KEY -> {
val editor = preferences.edit()
editor.putLong(KEY_API_LAST_CHANGE, System.currentTimeMillis())
editor.apply()
}
KEY_EMOJI_SUPPORT -> {
DependencyHolder.get(this).externalThemeManager.reloadEmojiPreferences()
}
KEY_THEME -> {
resetTheme(preferences)
Config.markChanged(this, VALUE_THEME_NAME_LIGHT, VALUE_THEME_NAME_DARK)
}
KEY_THEME_BACKGROUND -> {
Config.markChanged(this, VALUE_THEME_NAME_LIGHT, VALUE_THEME_NAME_DARK)
}
KEY_PROFILE_IMAGE_STYLE -> {
Config.markChanged(this, VALUE_THEME_NAME_LIGHT, VALUE_THEME_NAME_DARK)
profileImageViewViewProcessor!!.setStyle(Utils.getProfileImageStyle(preferences.getString(key, null)))
}
KEY_THEME_FONT_FAMILY -> {
Config.markChanged(this, VALUE_THEME_NAME_LIGHT, VALUE_THEME_NAME_DARK)
fontFamilyTagProcessor!!.setFontFamily(ThemeUtils.getThemeFontFamily(preferences))
}
KEY_THEME_COLOR -> {
val themeColor = preferences.getInt(key, ContextCompat.getColor(this,
R.color.branding_color))
//noinspection WrongConstant
ATE.config(this, VALUE_THEME_NAME_LIGHT).primaryColor(themeColor).accentColor(ThemeUtils.getOptimalAccentColor(themeColor, Color.BLACK)).coloredActionBar(true).coloredStatusBar(true).commit()
ATE.config(this, VALUE_THEME_NAME_DARK).accentColor(ThemeUtils.getOptimalAccentColor(themeColor, Color.WHITE)).coloredActionBar(false).coloredStatusBar(true).statusBarColor(Color.BLACK).commit()
ATE.config(this, null).accentColor(ThemeUtils.getOptimalAccentColor(themeColor, Color.BLACK)).coloredActionBar(false).coloredStatusBar(false).commit()
}
}
}
private fun resetTheme(preferences: SharedPreferences) {
when (ThemeUtils.getLocalNightMode(preferences)) {
AppCompatDelegate.MODE_NIGHT_AUTO -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO)
}
AppCompatDelegate.MODE_NIGHT_YES -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
}
else -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
}
}
}
private fun reloadDnsSettings() {
val holder = DependencyHolder.get(this)
val dns = holder.dns
dns.reloadDnsSettings()
}
private fun initializeAsyncTask() {
// AsyncTask class needs to be loaded in UI thread.
// So we load it here to comply the rule.
try {
Class.forName(AsyncTask::class.java.name)
} catch (ignore: ClassNotFoundException) {
}
}
companion object {
private val KEY_UCD_DATA_PROFILING = "ucd_data_profiling"
private val KEY_SPICE_DATA_PROFILING = "spice_data_profiling"
private val KEY_KEYBOARD_SHORTCUT_INITIALIZED = "keyboard_shortcut_initialized"
var instance: TwidereApplication? = null
private set
fun getInstance(context: Context): TwidereApplication {
return context.applicationContext as TwidereApplication
}
}
}

View File

@ -6,7 +6,6 @@ import android.graphics.Rect
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentActivity
import android.support.v4.view.ViewPager
import android.support.v4.view.ViewPager.OnPageChangeListener
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
@ -29,7 +28,6 @@ import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface
import org.mariotaku.twidere.fragment.iface.SupportFragmentCallback
import org.mariotaku.twidere.util.KeyboardShortcutsHandler
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback
import org.mariotaku.twidere.view.ExtendedLinearLayout
import org.mariotaku.twidere.view.TabPagerIndicator
/**
@ -38,33 +36,29 @@ import org.mariotaku.twidere.view.TabPagerIndicator
abstract class AbsToolbarTabPagesFragment : BaseSupportFragment(), RefreshScrollTopInterface, SupportFragmentCallback, IBaseFragment.SystemWindowsInsetsCallback, ControlBarOffsetListener, HideUiOnScroll, OnPageChangeListener, IToolBarSupportFragment, KeyboardShortcutCallback {
private var pagerAdapter: SupportTabsAdapter? = null
private var mPagerIndicator: TabPagerIndicator? = null
private var mViewPager: ViewPager? = null
private var mWindowOverlay: View? = null
override val toolbar: Toolbar
get() = toolbarContainer.toolbar
private var mControlBarHeight: Int = 0
private var mToolbarContainer: ExtendedLinearLayout? = null
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val activity = activity
pagerAdapter = SupportTabsAdapter(activity, childFragmentManager, null, 1)
mViewPager!!.adapter = pagerAdapter
mViewPager!!.offscreenPageLimit = 2
mViewPager!!.addOnPageChangeListener(this)
mPagerIndicator!!.setViewPager(mViewPager)
mPagerIndicator!!.setTabDisplayOption(TabPagerIndicator.LABEL)
viewPager.adapter = pagerAdapter
viewPager.offscreenPageLimit = 2
viewPager.addOnPageChangeListener(this)
toolbarTabs.setViewPager(viewPager)
toolbarTabs.setTabDisplayOption(TabPagerIndicator.LABEL)
addTabs(pagerAdapter!!)
mToolbarContainer!!.setOnSizeChangedListener { view, w, h, oldw, oldh ->
val pageLimit = mViewPager!!.offscreenPageLimit
val currentItem = mViewPager!!.currentItem
toolbarContainer.setOnSizeChangedListener { view, w, h, oldw, oldh ->
val pageLimit = viewPager.offscreenPageLimit
val currentItem = viewPager.currentItem
val count = pagerAdapter!!.count
for (i in 0..count - 1) {
if (i > currentItem - pageLimit - 1 || i < currentItem + pageLimit) {
val obj = pagerAdapter!!.instantiateItem(mViewPager, i)
val obj = pagerAdapter!!.instantiateItem(viewPager, i)
if (obj is IBaseFragment) {
obj.requestFitSystemWindows()
}
@ -75,11 +69,6 @@ abstract class AbsToolbarTabPagesFragment : BaseSupportFragment(), RefreshScroll
protected abstract fun addTabs(adapter: SupportTabsAdapter)
override fun onDestroy() {
mViewPager!!.removeOnPageChangeListener(this)
super.onDestroy()
}
override fun onAttach(context: Context?) {
super.onAttach(context)
if (context is IControlBarActivity) {
@ -101,10 +90,6 @@ abstract class AbsToolbarTabPagesFragment : BaseSupportFragment(), RefreshScroll
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mViewPager = view!!.findViewById(R.id.view_pager) as ViewPager
mToolbarContainer = view.findViewById(R.id.toolbarContainer) as ExtendedLinearLayout
mPagerIndicator = view.findViewById(R.id.toolbarTabs) as TabPagerIndicator
mWindowOverlay = view.findViewById(R.id.window_overlay)
val host = host
if (host is AppCompatActivity) {
@ -113,7 +98,7 @@ abstract class AbsToolbarTabPagesFragment : BaseSupportFragment(), RefreshScroll
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
val o = pagerAdapter!!.instantiateItem(mViewPager, mViewPager!!.currentItem)
val o = pagerAdapter!!.instantiateItem(viewPager, viewPager.currentItem)
if (o is Fragment) {
o.onActivityResult(requestCode, resultCode, data)
}
@ -131,9 +116,9 @@ abstract class AbsToolbarTabPagesFragment : BaseSupportFragment(), RefreshScroll
}
override fun getCurrentVisibleFragment(): Fragment? {
val currentItem = mViewPager!!.currentItem
val currentItem = viewPager.currentItem
if (currentItem < 0 || currentItem >= pagerAdapter!!.count) return null
return pagerAdapter!!.instantiateItem(mViewPager, currentItem) as Fragment
return pagerAdapter!!.instantiateItem(viewPager, currentItem) as Fragment
}
override fun triggerRefresh(position: Int): Boolean {
@ -144,8 +129,8 @@ abstract class AbsToolbarTabPagesFragment : BaseSupportFragment(), RefreshScroll
}
override fun getSystemWindowsInsets(insets: Rect): Boolean {
if (mPagerIndicator == null) return false
insets.set(0, mToolbarContainer!!.height, 0, 0)
if (toolbarTabs == null) return false
insets.set(0, toolbarContainer.height, 0, 0)
return true
}
@ -170,14 +155,14 @@ abstract class AbsToolbarTabPagesFragment : BaseSupportFragment(), RefreshScroll
override var controlBarOffset: Float
get() {
if (mToolbarContainer == null) return 0f
return 1 + mToolbarContainer!!.translationY / controlBarHeight
if (toolbarContainer == null) return 0f
return 1 + toolbarContainer.translationY / controlBarHeight
}
set(offset) {
if (mToolbarContainer == null) return
if (toolbarContainer == null) return
val translationY = (offset - 1) * controlBarHeight
mToolbarContainer!!.translationY = translationY
mWindowOverlay!!.translationY = translationY
toolbarContainer.translationY = translationY
windowOverlay!!.translationY = translationY
}
override val controlBarHeight: Int
@ -193,16 +178,16 @@ abstract class AbsToolbarTabPagesFragment : BaseSupportFragment(), RefreshScroll
if (action != null) {
when (action) {
ACTION_NAVIGATION_PREVIOUS_TAB -> {
val previous = mViewPager!!.currentItem - 1
val previous = viewPager.currentItem - 1
if (previous >= 0 && previous < pagerAdapter!!.count) {
mViewPager!!.setCurrentItem(previous, true)
viewPager.setCurrentItem(previous, true)
}
return true
}
ACTION_NAVIGATION_NEXT_TAB -> {
val next = mViewPager!!.currentItem + 1
val next = viewPager.currentItem + 1
if (next >= 0 && next < pagerAdapter!!.count) {
mViewPager!!.setCurrentItem(next, true)
viewPager.setCurrentItem(next, true)
}
return true
}

View File

@ -462,15 +462,15 @@ public class AccountsDashboardFragment extends BaseSupportFragment implements Lo
}
}
final Menu menu = mNavigationView.getMenu();
MenuUtils.setMenuItemAvailability(menu, R.id.interactions, !hasInteractionsTab);
MenuUtils.setMenuItemAvailability(menu, R.id.messages, !hasDmTab);
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.interactions, !hasInteractionsTab);
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.messages, !hasDmTab);
if (mUseStarsForLikes) {
MenuUtils.setMenuItemTitle(menu, R.id.favorites, R.string.favorites);
MenuUtils.setMenuItemIcon(menu, R.id.favorites, R.drawable.ic_action_star);
MenuUtils.Companion.setMenuItemTitle(menu, R.id.favorites, R.string.favorites);
MenuUtils.Companion.setMenuItemIcon(menu, R.id.favorites, R.drawable.ic_action_star);
} else {
MenuUtils.setMenuItemTitle(menu, R.id.favorites, R.string.likes);
MenuUtils.setMenuItemIcon(menu, R.id.favorites, R.drawable.ic_action_heart);
MenuUtils.Companion.setMenuItemTitle(menu, R.id.favorites, R.string.likes);
MenuUtils.Companion.setMenuItemIcon(menu, R.id.favorites, R.drawable.ic_action_heart);
}
boolean hasLists = false, hasGroups = false, hasPublicTimeline = false;
switch (ParcelableAccountUtils.getAccountType(account)) {
@ -487,9 +487,9 @@ public class AccountsDashboardFragment extends BaseSupportFragment implements Lo
break;
}
}
MenuUtils.setMenuItemAvailability(menu, R.id.groups, hasGroups);
MenuUtils.setMenuItemAvailability(menu, R.id.lists, hasLists);
MenuUtils.setMenuItemAvailability(menu, R.id.public_timeline, hasPublicTimeline);
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.groups, hasGroups);
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.lists, hasLists);
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.public_timeline, hasPublicTimeline);
}
private boolean hasAccountInTab(SupportTabSpec tab, UserKey accountId, boolean isActivated) {

View File

@ -59,20 +59,20 @@ public class AddStatusFilterDialogFragment extends BaseDialogFragment {
final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
mFilterItems = getFilterItemsInfo();
final String[] entries = new String[mFilterItems.length];
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final boolean nameFirst = preferences.getBoolean(KEY_NAME_FIRST);
for (int i = 0, j = entries.length; i < j; i++) {
final FilterItemInfo info = mFilterItems[i];
switch (info.type) {
case FilterItemInfo.FILTER_TYPE_USER:
entries[i] = getString(R.string.user_filter_name, getName(mUserColorNameManager,
entries[i] = getString(R.string.user_filter_name, getName(userColorNameManager,
info.value, nameFirst));
break;
case FilterItemInfo.FILTER_TYPE_KEYWORD:
entries[i] = getString(R.string.keyword_filter_name, getName(mUserColorNameManager,
entries[i] = getString(R.string.keyword_filter_name, getName(userColorNameManager,
info.value, nameFirst));
break;
case FilterItemInfo.FILTER_TYPE_SOURCE:
entries[i] = getString(R.string.source_filter_name, getName(mUserColorNameManager,
entries[i] = getString(R.string.source_filter_name, getName(userColorNameManager,
info.value, nameFirst));
break;
}

View File

@ -1,103 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.support.v4.app.DialogFragment;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.DebugModeUtils;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
import org.mariotaku.twidere.util.TwidereValidator;
import org.mariotaku.twidere.util.UserColorNameManager;
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper;
import javax.inject.Inject;
public class BaseDialogFragment extends DialogFragment implements Constants {
@Inject
protected AsyncTwitterWrapper mTwitterWrapper;
@Inject
protected UserColorNameManager mUserColorNameManager;
@Inject
protected SharedPreferencesWrapper mPreferences;
@Inject
protected TwidereValidator mValidator;
@Inject
protected KeyboardShortcutsHandler mKeyboardShortcutsHandler;
public TwidereApplication getApplication() {
final Activity activity = getActivity();
if (activity != null) return (TwidereApplication) activity.getApplication();
return null;
}
public ContentResolver getContentResolver() {
final Activity activity = getActivity();
if (activity != null) return activity.getContentResolver();
return null;
}
public SharedPreferences getSharedPreferences(final String name, final int mode) {
final Activity activity = getActivity();
if (activity != null) return activity.getSharedPreferences(name, mode);
return null;
}
public Object getSystemService(final String name) {
final Activity activity = getActivity();
if (activity != null) return activity.getSystemService(name);
return null;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
GeneralComponentHelper.build(context).inject(this);
}
@Override
public void onDestroy() {
super.onDestroy();
DebugModeUtils.watchReferenceLeak(this);
}
public void registerReceiver(final BroadcastReceiver receiver, final IntentFilter filter) {
final Activity activity = getActivity();
if (activity == null) return;
activity.registerReceiver(receiver, filter);
}
public void unregisterReceiver(final BroadcastReceiver receiver) {
final Activity activity = getActivity();
if (activity == null) return;
activity.unregisterReceiver(receiver);
}
}

View File

@ -0,0 +1,71 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.content.ContentResolver
import android.content.Context
import android.support.v4.app.DialogFragment
import org.mariotaku.twidere.Constants
import org.mariotaku.twidere.app.TwidereApplication
import org.mariotaku.twidere.util.*
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
import javax.inject.Inject
open class BaseDialogFragment : DialogFragment(), Constants {
@Inject
lateinit var twitterWrapper: AsyncTwitterWrapper
@Inject
lateinit var userColorNameManager: UserColorNameManager
@Inject
lateinit var preferences: SharedPreferencesWrapper
@Inject
lateinit var validator: TwidereValidator
@Inject
lateinit var keyboardShortcutsHandler: KeyboardShortcutsHandler
val application: TwidereApplication?
get() {
val activity = activity
if (activity != null) return activity.application as TwidereApplication
return null
}
val contentResolver: ContentResolver
get() = activity.contentResolver
fun getSystemService(name: String): Any? {
val activity = activity
if (activity != null) return activity.getSystemService(name)
return null
}
override fun onAttach(context: Context?) {
super.onAttach(context)
GeneralComponentHelper.build(context!!).inject(this)
}
override fun onDestroy() {
super.onDestroy()
DebugModeUtils.watchReferenceLeak(this)
}
}

View File

@ -118,7 +118,7 @@ abstract class BaseFiltersFragment : AbsContentListViewFragment<SimpleCursorAdap
R.id.delete -> {
val where = Expression.`in`(Column(Filters._ID),
RawItemArray(listView.checkedItemIds))
contentResolver!!.delete(contentUri, where.sql, null)
contentResolver.delete(contentUri, where.sql, null)
}
R.id.inverse_selection -> {
val positions = listView.getCheckedItemPositions()
@ -347,7 +347,7 @@ abstract class BaseFiltersFragment : AbsContentListViewFragment<SimpleCursorAdap
val resolver = contentResolver
val where = Expression.equalsArgs(Filters.Users.USER_KEY).sql
val whereArgs = arrayOf(user.key.toString())
resolver!!.delete(Filters.Users.CONTENT_URI, where, whereArgs)
resolver.delete(Filters.Users.CONTENT_URI, where, whereArgs)
resolver.insert(Filters.Users.CONTENT_URI, values)
}
}
@ -378,7 +378,7 @@ abstract class BaseFiltersFragment : AbsContentListViewFragment<SimpleCursorAdap
class FilterUsersListAdapter internal constructor(context: Context) : SimpleCursorAdapter(context, android.R.layout.simple_list_item_activated_2, null, arrayOfNulls<String>(0), IntArray(0), 0) {
private val mNameFirst: Boolean
private val nameFirst: Boolean
@Inject
lateinit var userColorNameManager: UserColorNameManager
@Inject
@ -389,7 +389,7 @@ abstract class BaseFiltersFragment : AbsContentListViewFragment<SimpleCursorAdap
init {
GeneralComponentHelper.build(context).inject(this)
mNameFirst = preferences.getBoolean(KEY_NAME_FIRST, true)
nameFirst = preferences.getBoolean(KEY_NAME_FIRST, true)
}
override fun bindView(view: View, context: Context?, cursor: Cursor) {
@ -400,7 +400,7 @@ abstract class BaseFiltersFragment : AbsContentListViewFragment<SimpleCursorAdap
val name = cursor.getString(nameIdx)
val screenName = cursor.getString(screenNameIdx)
val displayName = userColorNameManager.getDisplayName(userId, name, screenName,
mNameFirst)
nameFirst)
text1.text = displayName
text2.text = userId.host
}

View File

@ -58,7 +58,7 @@ public class BaseListFragment extends ListFragment implements Constants, OnScrol
}
public final TwidereApplication getApplication() {
return TwidereApplication.getInstance(getActivity());
return TwidereApplication.Companion.getInstance(getActivity());
}
public final ContentResolver getContentResolver() {

View File

@ -73,9 +73,9 @@ open class BaseSupportFragment : Fragment(), IBaseFragment, Constants {
GeneralComponentHelper.build(context!!).inject(this)
}
val contentResolver: ContentResolver?
val contentResolver: ContentResolver
get() {
return activity?.contentResolver
return activity!!.contentResolver!!
}
fun invalidateOptionsMenu() {

View File

@ -1,129 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Dialog;
import android.content.DialogInterface;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.fragment.iface.IDialogFragmentCallback;
import me.uucky.colorpicker.ColorPickerDialog;
public final class ColorPickerDialogFragment extends BaseDialogFragment implements
DialogInterface.OnClickListener {
private ColorPickerDialog.Controller mController;
@Override
public void onCancel(final DialogInterface dialog) {
super.onCancel(dialog);
final FragmentActivity a = getActivity();
if (a instanceof Callback) {
((Callback) a).onCancelled();
}
}
@Override
public void onClick(final DialogInterface dialog, final int which) {
final FragmentActivity a = getActivity();
if (!(a instanceof Callback) || mController == null) return;
switch (which) {
case DialogInterface.BUTTON_POSITIVE: {
final int color = mController.getColor();
((Callback) a).onColorSelected(color);
break;
}
case DialogInterface.BUTTON_NEUTRAL: {
((Callback) a).onColorCleared();
break;
}
}
}
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final int color;
final Bundle args = getArguments();
if (savedInstanceState != null) {
color = savedInstanceState.getInt(EXTRA_COLOR, Color.WHITE);
} else {
color = args.getInt(EXTRA_COLOR, Color.WHITE);
}
final FragmentActivity activity = getActivity();
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setView(me.uucky.colorpicker.R.layout.cp__dialog_color_picker);
builder.setPositiveButton(android.R.string.ok, this);
if (args.getBoolean(EXTRA_CLEAR_BUTTON, false)) {
builder.setNeutralButton(R.string.clear, this);
}
builder.setNegativeButton(android.R.string.cancel, this);
final AlertDialog dialog = builder.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface di) {
final Dialog dialog = (Dialog) di;
mController = new ColorPickerDialog.Controller(dialog.getContext(), dialog.getWindow().getDecorView());
final boolean showAlphaSlider = args.getBoolean(EXTRA_ALPHA_SLIDER, true);
for (int presetColor : PRESET_COLORS) {
mController.addColor(ContextCompat.getColor(getContext(), presetColor));
}
mController.setAlphaEnabled(showAlphaSlider);
mController.setInitialColor(color);
}
});
return dialog;
}
@Override
public void onDismiss(final DialogInterface dialog) {
super.onDismiss(dialog);
final FragmentActivity a = getActivity();
if (a instanceof Callback) {
((Callback) a).onDismissed();
}
}
@Override
public void onSaveInstanceState(final Bundle outState) {
if (mController != null) {
outState.putInt(EXTRA_COLOR, mController.getColor());
}
super.onSaveInstanceState(outState);
}
public interface Callback extends IDialogFragmentCallback {
void onColorCleared();
void onColorSelected(int color);
}
}

View File

@ -0,0 +1,114 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.Dialog
import android.content.DialogInterface
import android.graphics.Color
import android.os.Bundle
import android.support.v4.content.ContextCompat
import android.support.v7.app.AlertDialog
import me.uucky.colorpicker.ColorPickerDialog
import org.mariotaku.twidere.Constants.*
import org.mariotaku.twidere.R
import org.mariotaku.twidere.fragment.iface.IDialogFragmentCallback
class ColorPickerDialogFragment : BaseDialogFragment(), DialogInterface.OnClickListener {
private var mController: ColorPickerDialog.Controller? = null
override fun onCancel(dialog: DialogInterface?) {
super.onCancel(dialog)
val a = activity
if (a is Callback) {
a.onCancelled()
}
}
override fun onClick(dialog: DialogInterface, which: Int) {
val a = activity
if (a !is Callback || mController == null) return
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
val color = mController!!.color
a.onColorSelected(color)
}
DialogInterface.BUTTON_NEUTRAL -> {
a.onColorCleared()
}
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val color: Int
val args = arguments
if (savedInstanceState != null) {
color = savedInstanceState.getInt(EXTRA_COLOR, Color.WHITE)
} else {
color = args.getInt(EXTRA_COLOR, Color.WHITE)
}
val activity = activity
val builder = AlertDialog.Builder(activity)
builder.setView(me.uucky.colorpicker.R.layout.cp__dialog_color_picker)
builder.setPositiveButton(android.R.string.ok, this)
if (args.getBoolean(EXTRA_CLEAR_BUTTON, false)) {
builder.setNeutralButton(R.string.clear, this)
}
builder.setNegativeButton(android.R.string.cancel, this)
val dialog = builder.create()
dialog.setOnShowListener {
it as Dialog
mController = ColorPickerDialog.Controller(it.context, it.window.decorView)
val showAlphaSlider = args.getBoolean(EXTRA_ALPHA_SLIDER, true)
for (presetColor in PRESET_COLORS) {
mController!!.addColor(ContextCompat.getColor(context, presetColor))
}
mController!!.setAlphaEnabled(showAlphaSlider)
mController!!.setInitialColor(color)
}
return dialog
}
override fun onDismiss(dialog: DialogInterface?) {
super.onDismiss(dialog)
val a = activity
if (a is Callback) {
a.onDismissed()
}
}
override fun onSaveInstanceState(outState: Bundle?) {
if (mController != null) {
outState!!.putInt(EXTRA_COLOR, mController!!.color)
}
super.onSaveInstanceState(outState)
}
interface Callback : IDialogFragmentCallback {
fun onColorCleared()
fun onColorSelected(color: Int)
}
}

View File

@ -1,85 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AlertDialog;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
public class CreateUserBlockDialogFragment extends BaseDialogFragment implements DialogInterface.OnClickListener {
public static final String FRAGMENT_TAG = "create_user_block";
@Override
public void onClick(final DialogInterface dialog, final int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
final ParcelableUser user = getUser();
final AsyncTwitterWrapper twitter = mTwitterWrapper;
if (user == null || twitter == null) return;
twitter.createBlockAsync(user.account_key, user.key);
break;
default:
break;
}
}
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final FragmentActivity activity = getActivity();
final Context context = activity;
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
final ParcelableUser user = getUser();
if (user != null) {
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String displayName = mUserColorNameManager.getDisplayName(user, nameFirst);
builder.setTitle(getString(R.string.block_user, displayName));
builder.setMessage(getString(R.string.block_user_confirm_message, displayName));
}
builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, null);
return builder.create();
}
private ParcelableUser getUser() {
final Bundle args = getArguments();
if (!args.containsKey(EXTRA_USER)) return null;
return args.getParcelable(EXTRA_USER);
}
public static CreateUserBlockDialogFragment show(final FragmentManager fm, final ParcelableUser user) {
final Bundle args = new Bundle();
args.putParcelable(EXTRA_USER, user);
final CreateUserBlockDialogFragment f = new CreateUserBlockDialogFragment();
f.setArguments(args);
f.show(fm, FRAGMENT_TAG);
return f;
}
}

View File

@ -0,0 +1,83 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.support.v4.app.FragmentManager
import android.support.v7.app.AlertDialog
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_USER
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_NAME_FIRST
import org.mariotaku.twidere.model.ParcelableUser
class CreateUserBlockDialogFragment : BaseDialogFragment(), DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface, which: Int) {
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
val user = user
val twitter = twitterWrapper
if (user == null) return
twitter.createBlockAsync(user.account_key, user.key)
}
else -> {
}
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val activity = activity
val context = activity
val builder = AlertDialog.Builder(context)
val user = user
if (user != null) {
val nameFirst = preferences.getBoolean(KEY_NAME_FIRST)
val displayName = userColorNameManager.getDisplayName(user, nameFirst)
builder.setTitle(getString(R.string.block_user, displayName))
builder.setMessage(getString(R.string.block_user_confirm_message, displayName))
}
builder.setPositiveButton(android.R.string.ok, this)
builder.setNegativeButton(android.R.string.cancel, null)
return builder.create()
}
private val user: ParcelableUser?
get() {
val args = arguments
if (!args.containsKey(EXTRA_USER)) return null
return args.getParcelable<ParcelableUser>(EXTRA_USER)
}
companion object {
val FRAGMENT_TAG = "create_user_block"
fun show(fm: FragmentManager, user: ParcelableUser): CreateUserBlockDialogFragment {
val args = Bundle()
args.putParcelable(EXTRA_USER, user)
val f = CreateUserBlockDialogFragment()
f.arguments = args
f.show(fm, FRAGMENT_TAG)
return f
}
}
}

View File

@ -1,84 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import android.widget.CheckBox;
import com.rengwuxian.materialedittext.MaterialEditText;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.text.validator.UserListNameValidator;
import org.mariotaku.twidere.util.ParseUtils;
public class CreateUserListDialogFragment extends BaseDialogFragment implements DialogInterface.OnClickListener {
@Override
public void onClick(final DialogInterface dialog, final int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE: {
final AlertDialog alertDialog = (AlertDialog) dialog;
final Bundle args = getArguments();
final UserKey accountKey = args.getParcelable(EXTRA_ACCOUNT_KEY);
final MaterialEditText editName = (MaterialEditText) alertDialog.findViewById(R.id.name);
final MaterialEditText editDescription = (MaterialEditText) alertDialog.findViewById(R.id.description);
final CheckBox editPublic = (CheckBox) alertDialog.findViewById(R.id.is_public);
assert editName != null && editDescription != null && editPublic != null;
final String name = ParseUtils.parseString(editName.getText());
final String description = ParseUtils.parseString(editDescription.getText());
final boolean isPublic = editPublic.isChecked();
if (TextUtils.isEmpty(name)) return;
mTwitterWrapper.createUserListAsync(accountKey, name, isPublic, description);
break;
}
}
}
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setView(R.layout.dialog_user_list_detail_editor);
builder.setTitle(R.string.new_user_list);
builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, this);
final AlertDialog dialog = builder.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
final AlertDialog alertDialog = (AlertDialog) dialog;
MaterialEditText editName = (MaterialEditText) alertDialog.findViewById(R.id.name);
MaterialEditText editDescription = (MaterialEditText) alertDialog.findViewById(R.id.description);
CheckBox publicCheckBox = (CheckBox) alertDialog.findViewById(R.id.is_public);
editName.addValidator(new UserListNameValidator(getString(R.string.invalid_list_name)));
}
});
return dialog;
}
}

View File

@ -0,0 +1,75 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.support.v7.app.AlertDialog
import android.text.TextUtils
import android.widget.CheckBox
import com.rengwuxian.materialedittext.MaterialEditText
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_ACCOUNT_KEY
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.text.validator.UserListNameValidator
import org.mariotaku.twidere.util.ParseUtils
class CreateUserListDialogFragment : BaseDialogFragment(), DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface, which: Int) {
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
val alertDialog = dialog as AlertDialog
val args = arguments
val accountKey = args.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
val editName = alertDialog.findViewById(R.id.name) as MaterialEditText?
val editDescription = alertDialog.findViewById(R.id.description) as MaterialEditText?
val editPublic = alertDialog.findViewById(R.id.is_public) as CheckBox?
assert(editName != null && editDescription != null && editPublic != null)
val name = ParseUtils.parseString(editName!!.text)
val description = ParseUtils.parseString(editDescription!!.text)
val isPublic = editPublic!!.isChecked
if (TextUtils.isEmpty(name)) return
twitterWrapper.createUserListAsync(accountKey, name, isPublic, description)
}
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(context)
builder.setView(R.layout.dialog_user_list_detail_editor)
builder.setTitle(R.string.new_user_list)
builder.setPositiveButton(android.R.string.ok, this)
builder.setNegativeButton(android.R.string.cancel, this)
val dialog = builder.create()
dialog.setOnShowListener { dialog ->
val alertDialog = dialog as AlertDialog
val editName = alertDialog.findViewById(R.id.name) as MaterialEditText?
val editDescription = alertDialog.findViewById(R.id.description) as MaterialEditText?
val publicCheckBox = alertDialog.findViewById(R.id.is_public) as CheckBox?
editName!!.addValidator(UserListNameValidator(getString(R.string.invalid_list_name)))
}
return dialog
}
}

View File

@ -1,85 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AlertDialog;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
public class CreateUserMuteDialogFragment extends BaseDialogFragment implements DialogInterface.OnClickListener {
public static final String FRAGMENT_TAG = "create_user_mute";
@Override
public void onClick(final DialogInterface dialog, final int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
final ParcelableUser user = getUser();
final AsyncTwitterWrapper twitter = mTwitterWrapper;
if (user == null || twitter == null) return;
twitter.createMuteAsync(user.account_key, user.key);
break;
default:
break;
}
}
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final FragmentActivity activity = getActivity();
final Context context = activity;
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
final ParcelableUser user = getUser();
if (user != null) {
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String displayName = mUserColorNameManager.getDisplayName(user, nameFirst);
builder.setTitle(getString(R.string.mute_user, displayName));
builder.setMessage(getString(R.string.mute_user_confirm_message, displayName));
}
builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, null);
return builder.create();
}
private ParcelableUser getUser() {
final Bundle args = getArguments();
if (!args.containsKey(EXTRA_USER)) return null;
return args.getParcelable(EXTRA_USER);
}
public static CreateUserMuteDialogFragment show(final FragmentManager fm, final ParcelableUser user) {
final Bundle args = new Bundle();
args.putParcelable(EXTRA_USER, user);
final CreateUserMuteDialogFragment f = new CreateUserMuteDialogFragment();
f.setArguments(args);
f.show(fm, FRAGMENT_TAG);
return f;
}
}

View File

@ -0,0 +1,82 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.support.v4.app.FragmentManager
import android.support.v7.app.AlertDialog
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_USER
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_NAME_FIRST
import org.mariotaku.twidere.model.ParcelableUser
class CreateUserMuteDialogFragment : BaseDialogFragment(), DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface, which: Int) {
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
val user = user
val twitter = twitterWrapper
if (user == null) return
twitter.createMuteAsync(user.account_key, user.key)
}
else -> {
}
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val context = context
val builder = AlertDialog.Builder(context)
val user = user
if (user != null) {
val nameFirst = preferences.getBoolean(KEY_NAME_FIRST)
val displayName = userColorNameManager.getDisplayName(user, nameFirst)
builder.setTitle(getString(R.string.mute_user, displayName))
builder.setMessage(getString(R.string.mute_user_confirm_message, displayName))
}
builder.setPositiveButton(android.R.string.ok, this)
builder.setNegativeButton(android.R.string.cancel, null)
return builder.create()
}
private val user: ParcelableUser?
get() {
val args = arguments
if (!args.containsKey(EXTRA_USER)) return null
return args.getParcelable<ParcelableUser>(EXTRA_USER)
}
companion object {
val FRAGMENT_TAG = "create_user_mute"
fun show(fm: FragmentManager, user: ParcelableUser): CreateUserMuteDialogFragment {
val args = Bundle()
args.putParcelable(EXTRA_USER, user)
val f = CreateUserMuteDialogFragment()
f.arguments = args
f.show(fm, FRAGMENT_TAG)
return f
}
}
}

View File

@ -1,111 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AlertDialog;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.ParcelableUserList;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
public class DeleteUserListMembersDialogFragment extends BaseDialogFragment implements
DialogInterface.OnClickListener {
public static final String FRAGMENT_TAG = "destroy_user_list_member";
@Override
public void onClick(final DialogInterface dialog, final int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
final ParcelableUser[] users = getUsers();
final ParcelableUserList userList = getUserList();
final AsyncTwitterWrapper twitter = mTwitterWrapper;
if (users == null || userList == null || twitter == null) return;
twitter.deleteUserListMembersAsync(userList.account_key, userList.id, users);
break;
default:
break;
}
}
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final FragmentActivity activity = getActivity();
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
final ParcelableUser[] users = getUsers();
final ParcelableUserList userList = getUserList();
if (users == null || userList == null) throw new NullPointerException();
if (users.length == 1) {
final ParcelableUser user = users[0];
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String displayName = mUserColorNameManager.getDisplayName(user, nameFirst);
builder.setTitle(getString(R.string.delete_user, displayName));
builder.setMessage(getString(R.string.delete_user_from_list_confirm, displayName, userList.name));
} else {
builder.setTitle(R.string.delete_users);
final Resources res = getResources();
final String message = res.getQuantityString(R.plurals.delete_N_users_from_list_confirm, users.length,
users.length, userList.name);
builder.setMessage(message);
}
builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, null);
return builder.create();
}
private ParcelableUserList getUserList() {
final Bundle args = getArguments();
if (!args.containsKey(EXTRA_USER_LIST)) return null;
return args.getParcelable(EXTRA_USER_LIST);
}
private ParcelableUser[] getUsers() {
final Bundle args = getArguments();
if (!args.containsKey(EXTRA_USERS)) return null;
final Parcelable[] array = args.getParcelableArray(EXTRA_USERS);
if (array == null) return null;
final ParcelableUser[] users = new ParcelableUser[array.length];
for (int i = 0, j = users.length; i < j; i++) {
users[i] = (ParcelableUser) array[i];
}
return users;
}
public static DeleteUserListMembersDialogFragment show(final FragmentManager fm, final ParcelableUserList userList,
final ParcelableUser... users) {
final Bundle args = new Bundle();
args.putParcelable(EXTRA_USER_LIST, userList);
args.putParcelableArray(EXTRA_USERS, users);
final DeleteUserListMembersDialogFragment f = new DeleteUserListMembersDialogFragment();
f.setArguments(args);
f.show(fm, FRAGMENT_TAG);
return f;
}
}

View File

@ -0,0 +1,101 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.support.v4.app.FragmentManager
import android.support.v7.app.AlertDialog
import org.mariotaku.ktextension.asTypedArray
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_USERS
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_USER_LIST
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_NAME_FIRST
import org.mariotaku.twidere.model.ParcelableUser
import org.mariotaku.twidere.model.ParcelableUserList
class DeleteUserListMembersDialogFragment : BaseDialogFragment(), DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface, which: Int) {
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
val users = users ?: return
val userList = userList ?: return
twitterWrapper.deleteUserListMembersAsync(userList.account_key, userList.id, *users)
}
else -> {
}
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(context)
val users = users
val userList = userList
if (users == null || userList == null) throw NullPointerException()
if (users.size == 1) {
val user = users[0]
val nameFirst = preferences.getBoolean(KEY_NAME_FIRST)
val displayName = userColorNameManager.getDisplayName(user, nameFirst)
builder.setTitle(getString(R.string.delete_user, displayName))
builder.setMessage(getString(R.string.delete_user_from_list_confirm, displayName, userList.name))
} else {
builder.setTitle(R.string.delete_users)
val res = resources
val message = res.getQuantityString(R.plurals.delete_N_users_from_list_confirm, users.size,
users.size, userList.name)
builder.setMessage(message)
}
builder.setPositiveButton(android.R.string.ok, this)
builder.setNegativeButton(android.R.string.cancel, null)
return builder.create()
}
private val userList: ParcelableUserList?
get() {
val args = arguments
if (!args.containsKey(EXTRA_USER_LIST)) return null
return args.getParcelable<ParcelableUserList>(EXTRA_USER_LIST)
}
private val users: Array<ParcelableUser>?
get() {
val args = arguments
if (!args.containsKey(EXTRA_USERS)) return null
return args.getParcelableArray(EXTRA_USERS)?.asTypedArray(ParcelableUser.CREATOR)
}
companion object {
val FRAGMENT_TAG = "destroy_user_list_member"
fun show(fm: FragmentManager, userList: ParcelableUserList,
vararg users: ParcelableUser): DeleteUserListMembersDialogFragment {
val args = Bundle()
args.putParcelable(EXTRA_USER_LIST, userList)
args.putParcelableArray(EXTRA_USERS, users)
val f = DeleteUserListMembersDialogFragment()
f.arguments = args
f.show(fm, FRAGMENT_TAG)
return f
}
}
}

View File

@ -1,86 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AlertDialog;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
public class DestroyFriendshipDialogFragment extends BaseDialogFragment implements
DialogInterface.OnClickListener {
public static final String FRAGMENT_TAG = "destroy_friendship";
@Override
public void onClick(final DialogInterface dialog, final int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
final ParcelableUser user = getUser();
final AsyncTwitterWrapper twitter = mTwitterWrapper;
if (user == null || twitter == null) return;
twitter.destroyFriendshipAsync(user.account_key, user.key);
break;
default:
break;
}
}
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final FragmentActivity activity = getActivity();
final Context context = activity;
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
final ParcelableUser user = getUser();
if (user != null) {
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String displayName = mUserColorNameManager.getDisplayName(user, nameFirst);
builder.setTitle(getString(R.string.unfollow_user, displayName));
builder.setMessage(getString(R.string.unfollow_user_confirm_message, displayName));
}
builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, null);
return builder.create();
}
private ParcelableUser getUser() {
final Bundle args = getArguments();
if (!args.containsKey(EXTRA_USER)) return null;
return args.getParcelable(EXTRA_USER);
}
public static DestroyFriendshipDialogFragment show(final FragmentManager fm, final ParcelableUser user) {
final Bundle args = new Bundle();
args.putParcelable(EXTRA_USER, user);
final DestroyFriendshipDialogFragment f = new DestroyFriendshipDialogFragment();
f.setArguments(args);
f.show(fm, FRAGMENT_TAG);
return f;
}
}

View File

@ -0,0 +1,76 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.support.v4.app.FragmentManager
import android.support.v7.app.AlertDialog
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.IntentConstants
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_NAME_FIRST
import org.mariotaku.twidere.model.ParcelableUser
class DestroyFriendshipDialogFragment : BaseDialogFragment(), DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface, which: Int) {
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
val user = user ?: return
twitterWrapper.destroyFriendshipAsync(user.account_key, user.key)
}
else -> {
}
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(context)
val nameFirst = preferences.getBoolean(KEY_NAME_FIRST)
val displayName = userColorNameManager.getDisplayName(user, nameFirst)
builder.setTitle(getString(R.string.unfollow_user, displayName))
builder.setMessage(getString(R.string.unfollow_user_confirm_message, displayName))
builder.setPositiveButton(android.R.string.ok, this)
builder.setNegativeButton(android.R.string.cancel, null)
return builder.create()
}
private val user: ParcelableUser?
get() {
val args = arguments
if (!args.containsKey(IntentConstants.EXTRA_USER)) return null
return args.getParcelable<ParcelableUser>(IntentConstants.EXTRA_USER)
}
companion object {
val FRAGMENT_TAG = "destroy_friendship"
fun show(fm: FragmentManager, user: ParcelableUser): DestroyFriendshipDialogFragment {
val args = Bundle()
args.putParcelable(IntentConstants.EXTRA_USER, user)
val f = DestroyFriendshipDialogFragment()
f.arguments = args
f.show(fm, FRAGMENT_TAG)
return f
}
}
}

View File

@ -42,7 +42,7 @@ public class DestroySavedSearchDialogFragment extends BaseDialogFragment impleme
case DialogInterface.BUTTON_POSITIVE:
final UserKey accountKey = getAccountKey();
final long searchId = getSearchId();
final AsyncTwitterWrapper twitter = mTwitterWrapper;
final AsyncTwitterWrapper twitter = twitterWrapper;
if (searchId <= 0 || twitter == null) return;
twitter.destroySavedSearchAsync(accountKey, searchId);
break;

View File

@ -40,7 +40,7 @@ public class DestroyStatusDialogFragment extends BaseDialogFragment implements D
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
final ParcelableStatus status = getStatus();
final AsyncTwitterWrapper twitter = mTwitterWrapper;
final AsyncTwitterWrapper twitter = twitterWrapper;
if (status == null || twitter == null) return;
twitter.destroyStatusAsync(status.account_key, status.id);
break;

View File

@ -40,7 +40,7 @@ public class DestroyUserListDialogFragment extends BaseDialogFragment implements
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
final ParcelableUserList userList = getUserList();
final AsyncTwitterWrapper twitter = mTwitterWrapper;
final AsyncTwitterWrapper twitter = twitterWrapper;
if (userList == null || twitter == null) return;
twitter.destroyUserListAsync(userList.account_key, userList.id);
break;

View File

@ -1,83 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AlertDialog;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableUserList;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
public class DestroyUserListSubscriptionDialogFragment extends BaseDialogFragment implements
DialogInterface.OnClickListener {
public static final String FRAGMENT_TAG = "destroy_user_list";
@Override
public void onClick(final DialogInterface dialog, final int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
final ParcelableUserList userList = getUserList();
final AsyncTwitterWrapper twitter = mTwitterWrapper;
if (userList == null || twitter == null) return;
twitter.destroyUserListSubscriptionAsync(userList.account_key, userList.id);
break;
default:
break;
}
}
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Context context = getActivity();
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
final ParcelableUserList userList = getUserList();
if (userList != null) {
builder.setTitle(getString(R.string.unsubscribe_from_user_list, userList.name));
builder.setMessage(getString(R.string.unsubscribe_from_user_list_confirm_message, userList.name));
}
builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, null);
return builder.create();
}
private ParcelableUserList getUserList() {
final Bundle args = getArguments();
if (!args.containsKey(EXTRA_USER_LIST)) return null;
return args.getParcelable(EXTRA_USER_LIST);
}
public static DestroyUserListSubscriptionDialogFragment show(final FragmentManager fm,
final ParcelableUserList userList) {
final Bundle args = new Bundle();
args.putParcelable(EXTRA_USER_LIST, userList);
final DestroyUserListSubscriptionDialogFragment f = new DestroyUserListSubscriptionDialogFragment();
f.setArguments(args);
f.show(fm, FRAGMENT_TAG);
return f;
}
}

View File

@ -0,0 +1,80 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.support.v4.app.FragmentManager
import android.support.v7.app.AlertDialog
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_USER_LIST
import org.mariotaku.twidere.model.ParcelableUserList
class DestroyUserListSubscriptionDialogFragment : BaseDialogFragment(), DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface, which: Int) {
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
val userList = userList
val twitter = twitterWrapper
if (userList == null) return
twitter.destroyUserListSubscriptionAsync(userList.account_key, userList.id)
}
else -> {
}
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val context = activity
val builder = AlertDialog.Builder(context)
val userList = userList
if (userList != null) {
builder.setTitle(getString(R.string.unsubscribe_from_user_list, userList.name))
builder.setMessage(getString(R.string.unsubscribe_from_user_list_confirm_message, userList.name))
}
builder.setPositiveButton(android.R.string.ok, this)
builder.setNegativeButton(android.R.string.cancel, null)
return builder.create()
}
private val userList: ParcelableUserList?
get() {
val args = arguments
if (!args.containsKey(EXTRA_USER_LIST)) return null
return args.getParcelable<ParcelableUserList>(EXTRA_USER_LIST)
}
companion object {
val FRAGMENT_TAG = "destroy_user_list"
fun show(fm: FragmentManager,
userList: ParcelableUserList): DestroyUserListSubscriptionDialogFragment {
val args = Bundle()
args.putParcelable(EXTRA_USER_LIST, userList)
val f = DestroyUserListSubscriptionDialogFragment()
f.arguments = args
f.show(fm, FRAGMENT_TAG)
return f
}
}
}

View File

@ -1,404 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.NotificationManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import org.apache.commons.lang3.ArrayUtils;
import org.mariotaku.sqliteqb.library.Columns.Column;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.RawItemArray;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.DraftsAdapter;
import org.mariotaku.twidere.model.Draft;
import org.mariotaku.twidere.model.DraftCursorIndices;
import org.mariotaku.twidere.model.ParcelableMediaUpdate;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.draft.SendDirectMessageActionExtra;
import org.mariotaku.twidere.model.util.ParcelableStatusUpdateUtils;
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts;
import org.mariotaku.twidere.service.BackgroundOperationService;
import org.mariotaku.twidere.util.AsyncTaskUtils;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.JsonSerializer;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import static org.mariotaku.twidere.util.Utils.getDefaultTextSize;
public class DraftsFragment extends BaseSupportFragment implements LoaderCallbacks<Cursor>,
OnItemClickListener, MultiChoiceModeListener {
private ContentResolver mResolver;
private DraftsAdapter mAdapter;
private ListView mListView;
private View mEmptyView;
private TextView mEmptyText;
private ImageView mEmptyIcon;
private View mListContainer, mProgressContainer;
private float mTextSize;
@Override
public boolean onCreateActionMode(final ActionMode mode, final Menu menu) {
mode.getMenuInflater().inflate(R.menu.action_multi_select_drafts, menu);
return true;
}
@Override
public boolean onPrepareActionMode(final ActionMode mode, final Menu menu) {
updateTitle(mode);
return true;
}
@Override
public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) {
switch (item.getItemId()) {
case R.id.delete: {
final DeleteDraftsConfirmDialogFragment f = new DeleteDraftsConfirmDialogFragment();
final Bundle args = new Bundle();
args.putLongArray(EXTRA_IDS, mListView.getCheckedItemIds());
f.setArguments(args);
f.show(getChildFragmentManager(), "delete_drafts_confirm");
break;
}
case R.id.send: {
final Cursor c = mAdapter.getCursor();
if (c == null || c.isClosed()) return false;
final SparseBooleanArray checked = mListView.getCheckedItemPositions();
final List<Draft> list = new ArrayList<>();
final DraftCursorIndices indices = new DraftCursorIndices(c);
for (int i = 0, j = checked.size(); i < j; i++) {
if (checked.valueAt(i) && c.moveToPosition(checked.keyAt(i))) {
list.add(indices.newObject(c));
}
}
if (sendDrafts(list)) {
final Expression where = Expression.in(new Column(Drafts._ID),
new RawItemArray(mListView.getCheckedItemIds()));
mResolver.delete(Drafts.CONTENT_URI, where.getSQL(), null);
}
break;
}
default: {
return false;
}
}
mode.finish();
return true;
}
@Override
public void onDestroyActionMode(final ActionMode mode) {
}
@Override
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
final Uri uri = Drafts.CONTENT_URI_UNSENT;
final String[] cols = Drafts.COLUMNS;
final String orderBy = Drafts.TIMESTAMP + " DESC";
return new CursorLoader(getActivity(), uri, cols, null, null, orderBy);
}
@Override
public void onLoadFinished(final Loader<Cursor> loader, final Cursor cursor) {
mAdapter.swapCursor(cursor);
setListShown(true);
}
@Override
public void onLoaderReset(final Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
@Override
public void onItemCheckedStateChanged(final ActionMode mode, final int position, final long id,
final boolean checked) {
updateTitle(mode);
}
@Override
public void onItemClick(final AdapterView<?> view, final View child, final int position, final long id) {
final Cursor c = mAdapter.getCursor();
if (c == null || c.isClosed() || !c.moveToPosition(position)) return;
final Draft item = DraftCursorIndices.fromCursor(c);
if (TextUtils.isEmpty(item.action_type)) {
editDraft(item);
return;
}
switch (item.action_type) {
case "0":
case "1":
case Draft.Action.UPDATE_STATUS:
case Draft.Action.REPLY:
case Draft.Action.QUOTE: {
editDraft(item);
break;
}
}
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_drafts, container, false);
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mResolver = getContentResolver();
mTextSize = preferences.getInt(KEY_TEXT_SIZE, getDefaultTextSize(getActivity()));
mAdapter = new DraftsAdapter(getActivity());
mListView.setAdapter(mAdapter);
mListView.setEmptyView(mEmptyView);
mListView.setOnItemClickListener(this);
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
mListView.setMultiChoiceModeListener(this);
mEmptyIcon.setImageResource(R.drawable.ic_info_draft);
mEmptyText.setText(R.string.drafts_hint_messages);
getLoaderManager().initLoader(0, null, this);
setListShown(false);
}
@Override
public void onStart() {
final AsyncTwitterWrapper twitter = twitterWrapper;
if (twitter != null) {
twitter.clearNotificationAsync(NOTIFICATION_ID_DRAFTS);
}
super.onStart();
}
@Override
public void onResume() {
super.onResume();
final float text_size = preferences.getInt(KEY_TEXT_SIZE, getDefaultTextSize(getActivity()));
mAdapter.setTextSize(text_size);
if (mTextSize != text_size) {
mTextSize = text_size;
mListView.invalidateViews();
}
}
@Override
public void onStop() {
super.onStop();
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mListView = (ListView) view.findViewById(android.R.id.list);
mEmptyView = view.findViewById(android.R.id.empty);
mEmptyText = (TextView) view.findViewById(R.id.empty_text);
mEmptyIcon = (ImageView) view.findViewById(R.id.empty_icon);
mProgressContainer = view.findViewById(R.id.progress_container);
mListContainer = view.findViewById(R.id.list_container);
}
public void setListShown(boolean listShown) {
mListContainer.setVisibility(listShown ? View.VISIBLE : View.GONE);
mProgressContainer.setVisibility(listShown ? View.GONE : View.VISIBLE);
mEmptyView.setVisibility(listShown && mAdapter.isEmpty() ? View.VISIBLE : View.GONE);
}
private void editDraft(final Draft draft) {
final Intent intent = new Intent(INTENT_ACTION_EDIT_DRAFT);
intent.putExtra(EXTRA_DRAFT, draft);
mResolver.delete(Drafts.CONTENT_URI, Expression.equals(Drafts._ID, draft._id).getSQL(), null);
startActivityForResult(intent, REQUEST_COMPOSE);
}
private boolean sendDrafts(final List<Draft> list) {
final AsyncTwitterWrapper twitter = twitterWrapper;
if (twitter == null) return false;
for (final Draft item : list) {
if (TextUtils.isEmpty(item.action_type)) {
item.action_type = Draft.Action.UPDATE_STATUS;
}
switch (item.action_type) {
case Draft.Action.UPDATE_STATUS_COMPAT_1:
case Draft.Action.UPDATE_STATUS_COMPAT_2:
case Draft.Action.UPDATE_STATUS:
case Draft.Action.REPLY:
case Draft.Action.QUOTE: {
BackgroundOperationService.updateStatusesAsync(getContext(), item.action_type,
ParcelableStatusUpdateUtils.fromDraftItem(getActivity(), item));
break;
}
case Draft.Action.SEND_DIRECT_MESSAGE_COMPAT:
case Draft.Action.SEND_DIRECT_MESSAGE: {
String recipientId = null;
if (item.action_extras instanceof SendDirectMessageActionExtra) {
recipientId = ((SendDirectMessageActionExtra) item.action_extras).getRecipientId();
}
if (ArrayUtils.isEmpty(item.account_keys) || recipientId == null) {
continue;
}
final UserKey accountId = item.account_keys[0];
final String imageUri = item.media != null && item.media.length > 0 ? item.media[0].uri : null;
twitter.sendDirectMessageAsync(accountId, recipientId, item.text, imageUri);
break;
}
}
}
return true;
}
private void updateTitle(final ActionMode mode) {
if (mListView == null || mode == null) return;
final int count = mListView.getCheckedItemCount();
mode.setTitle(getResources().getQuantityString(R.plurals.Nitems_selected, count, count));
}
public static class DeleteDraftsConfirmDialogFragment extends BaseDialogFragment implements OnClickListener {
@Override
public void onClick(final DialogInterface dialog, final int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE: {
final Bundle args = getArguments();
if (args == null) return;
AsyncTaskUtils.executeTask(new DeleteDraftsTask(getActivity(), args.getLongArray(EXTRA_IDS)));
break;
}
}
}
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Context context = getActivity();
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(R.string.delete_drafts_confirm);
builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, null);
return builder.create();
}
}
private static class DeleteDraftsTask extends AsyncTask<Object, Object, Integer> {
private static final String FRAGMENT_TAG_DELETING_DRAFTS = "deleting_drafts";
private final FragmentActivity mActivity;
private final long[] mIds;
private final NotificationManager mNotificationManager;
private Handler mHandler;
private DeleteDraftsTask(final FragmentActivity activity, final long[] ids) {
mActivity = activity;
mNotificationManager = (NotificationManager) activity.getSystemService(Context.NOTIFICATION_SERVICE);
mIds = ids;
mHandler = new Handler(activity.getMainLooper());
}
@Override
protected Integer doInBackground(final Object... params) {
final ContentResolver resolver = mActivity.getContentResolver();
final Expression where = Expression.in(new Column(Drafts._ID), new RawItemArray(mIds));
final String[] projection = {Drafts.MEDIA};
final Cursor c = resolver.query(Drafts.CONTENT_URI, projection, where.getSQL(), null, null);
if (c == null) return 0;
final int idxMedia = c.getColumnIndex(Drafts.MEDIA);
c.moveToFirst();
while (!c.isAfterLast()) {
final ParcelableMediaUpdate[] mediaArray = JsonSerializer.parseArray(c.getString(idxMedia),
ParcelableMediaUpdate.class);
if (mediaArray != null) {
for (final ParcelableMediaUpdate media : mediaArray) {
final Uri uri = Uri.parse(media.uri);
if ("file".equals(uri.getScheme())) {
final File file = new File(uri.getPath());
if (!file.delete()) {
Log.w(LOGTAG, String.format("Unable to delete %s", file));
}
}
}
}
c.moveToNext();
}
c.close();
return resolver.delete(Drafts.CONTENT_URI, where.getSQL(), null);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
final ProgressDialogFragment f = ProgressDialogFragment.show(mActivity,
FRAGMENT_TAG_DELETING_DRAFTS);
f.setCancelable(false);
}
@Override
protected void onPostExecute(final Integer result) {
super.onPostExecute(result);
final Fragment f = mActivity.getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG_DELETING_DRAFTS);
if (f instanceof DialogFragment) {
((DialogFragment) f).dismiss();
}
for (long id : mIds) {
final String tag = Uri.withAppendedPath(Drafts.CONTENT_URI, String.valueOf(id)).toString();
mNotificationManager.cancel(tag, NOTIFICATION_ID_DRAFTS);
}
}
}
}

View File

@ -0,0 +1,317 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.AlertDialog
import android.app.Dialog
import android.app.NotificationManager
import android.content.Context
import android.content.DialogInterface
import android.content.DialogInterface.OnClickListener
import android.content.Intent
import android.database.Cursor
import android.net.Uri
import android.os.AsyncTask
import android.os.Bundle
import android.os.Handler
import android.support.v4.app.DialogFragment
import android.support.v4.app.FragmentActivity
import android.support.v4.app.LoaderManager.LoaderCallbacks
import android.support.v4.content.CursorLoader
import android.support.v4.content.Loader
import android.text.TextUtils
import android.util.Log
import android.view.*
import android.widget.AbsListView.MultiChoiceModeListener
import android.widget.AdapterView
import android.widget.AdapterView.OnItemClickListener
import android.widget.ListView
import kotlinx.android.synthetic.main.fragment_drafts.*
import org.apache.commons.lang3.ArrayUtils
import org.mariotaku.sqliteqb.library.Columns.Column
import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.sqliteqb.library.RawItemArray
import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.*
import org.mariotaku.twidere.adapter.DraftsAdapter
import org.mariotaku.twidere.constant.IntentConstants
import org.mariotaku.twidere.model.Draft
import org.mariotaku.twidere.model.DraftCursorIndices
import org.mariotaku.twidere.model.ParcelableMediaUpdate
import org.mariotaku.twidere.model.draft.SendDirectMessageActionExtra
import org.mariotaku.twidere.model.util.ParcelableStatusUpdateUtils
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts
import org.mariotaku.twidere.service.BackgroundOperationService
import org.mariotaku.twidere.util.AsyncTaskUtils
import org.mariotaku.twidere.util.JsonSerializer
import org.mariotaku.twidere.util.Utils.getDefaultTextSize
import java.io.File
import java.util.*
class DraftsFragment : BaseSupportFragment(), LoaderCallbacks<Cursor>, OnItemClickListener, MultiChoiceModeListener {
private var adapter: DraftsAdapter? = null
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
mode.menuInflater.inflate(R.menu.action_multi_select_drafts, menu)
return true
}
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
updateTitle(mode)
return true
}
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
when (item.itemId) {
R.id.delete -> {
val f = DeleteDraftsConfirmDialogFragment()
val args = Bundle()
args.putLongArray(IntentConstants.EXTRA_IDS, listView!!.checkedItemIds)
f.arguments = args
f.show(childFragmentManager, "delete_drafts_confirm")
}
R.id.send -> {
val c = adapter!!.cursor
if (c == null || c.isClosed) return false
val checked = listView!!.checkedItemPositions
val list = ArrayList<Draft>()
val indices = DraftCursorIndices(c)
var i = 0
val j = checked.size()
while (i < j) {
if (checked.valueAt(i) && c.moveToPosition(checked.keyAt(i))) {
list.add(indices.newObject(c))
}
i++
}
if (sendDrafts(list)) {
val where = Expression.`in`(Column(Drafts._ID),
RawItemArray(listView!!.checkedItemIds))
contentResolver.delete(Drafts.CONTENT_URI, where.sql, null)
}
}
else -> {
return false
}
}
mode.finish()
return true
}
override fun onDestroyActionMode(mode: ActionMode) {
}
override fun onCreateLoader(id: Int, args: Bundle): Loader<Cursor> {
val uri = Drafts.CONTENT_URI_UNSENT
val cols = Drafts.COLUMNS
val orderBy = Drafts.TIMESTAMP + " DESC"
return CursorLoader(activity, uri, cols, null, null, orderBy)
}
override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) {
adapter!!.swapCursor(cursor)
setListShown(true)
}
override fun onLoaderReset(loader: Loader<Cursor>) {
adapter!!.swapCursor(null)
}
override fun onItemCheckedStateChanged(mode: ActionMode, position: Int, id: Long,
checked: Boolean) {
updateTitle(mode)
}
override fun onItemClick(view: AdapterView<*>, child: View, position: Int, id: Long) {
val c = adapter!!.cursor
if (c == null || c.isClosed || !c.moveToPosition(position)) return
val item = DraftCursorIndices.fromCursor(c)
if (TextUtils.isEmpty(item.action_type)) {
editDraft(item)
return
}
when (item.action_type) {
"0", "1", Draft.Action.UPDATE_STATUS, Draft.Action.REPLY, Draft.Action.QUOTE -> {
editDraft(item)
}
}
}
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater!!.inflate(R.layout.fragment_drafts, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
adapter = DraftsAdapter(activity)
adapter!!.setTextSize(preferences.getInt(KEY_TEXT_SIZE, getDefaultTextSize(activity)).toFloat())
listView!!.adapter = adapter
listView!!.emptyView = emptyView
listView!!.onItemClickListener = this
listView!!.choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL
listView!!.setMultiChoiceModeListener(this)
emptyIcon!!.setImageResource(R.drawable.ic_info_draft)
emptyText!!.setText(R.string.drafts_hint_messages)
loaderManager.initLoader(0, null, this)
setListShown(false)
}
override fun onStart() {
twitterWrapper.clearNotificationAsync(NOTIFICATION_ID_DRAFTS)
super.onStart()
}
override fun onStop() {
super.onStop()
}
fun setListShown(listShown: Boolean) {
listContainer!!.visibility = if (listShown) View.VISIBLE else View.GONE
progressContainer!!.visibility = if (listShown) View.GONE else View.VISIBLE
emptyView!!.visibility = if (listShown && adapter!!.isEmpty) View.VISIBLE else View.GONE
}
private fun editDraft(draft: Draft) {
val intent = Intent(INTENT_ACTION_EDIT_DRAFT)
intent.putExtra(EXTRA_DRAFT, draft)
contentResolver.delete(Drafts.CONTENT_URI, Expression.equals(Drafts._ID, draft._id).sql, null)
startActivityForResult(intent, REQUEST_COMPOSE)
}
private fun sendDrafts(list: List<Draft>): Boolean {
loop@ for (item in list) {
if (TextUtils.isEmpty(item.action_type)) {
item.action_type = Draft.Action.UPDATE_STATUS
}
when (item.action_type) {
Draft.Action.UPDATE_STATUS_COMPAT_1, Draft.Action.UPDATE_STATUS_COMPAT_2, Draft.Action.UPDATE_STATUS, Draft.Action.REPLY, Draft.Action.QUOTE -> {
BackgroundOperationService.updateStatusesAsync(context, item.action_type,
ParcelableStatusUpdateUtils.fromDraftItem(activity, item))
}
Draft.Action.SEND_DIRECT_MESSAGE_COMPAT, Draft.Action.SEND_DIRECT_MESSAGE -> {
var recipientId: String? = null
if (item.action_extras is SendDirectMessageActionExtra) {
recipientId = (item.action_extras as SendDirectMessageActionExtra).recipientId
}
if (ArrayUtils.isEmpty(item.account_keys) || recipientId == null) {
continue@loop
}
val accountId = item.account_keys!![0]
val imageUri = if (item.media != null && item.media.size > 0) item.media[0].uri else null
twitterWrapper.sendDirectMessageAsync(accountId, recipientId, item.text, imageUri)
}
}
}
return true
}
private fun updateTitle(mode: ActionMode?) {
if (listView == null || mode == null) return
val count = listView!!.checkedItemCount
mode.title = resources.getQuantityString(R.plurals.Nitems_selected, count, count)
}
class DeleteDraftsConfirmDialogFragment : BaseDialogFragment(), OnClickListener {
override fun onClick(dialog: DialogInterface, which: Int) {
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
val args = arguments ?: return
AsyncTaskUtils.executeTask(DeleteDraftsTask(activity, args.getLongArray(IntentConstants.EXTRA_IDS)))
}
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val context = activity
val builder = AlertDialog.Builder(context)
builder.setMessage(R.string.delete_drafts_confirm)
builder.setPositiveButton(android.R.string.ok, this)
builder.setNegativeButton(android.R.string.cancel, null)
return builder.create()
}
}
private class DeleteDraftsTask(
private val activity: FragmentActivity,
private val ids: LongArray
) : AsyncTask<Any, Any, Int>() {
private val notificationManager: NotificationManager
private val handler: Handler
init {
notificationManager = activity.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
handler = Handler(activity.mainLooper)
}
override fun doInBackground(vararg params: Any): Int? {
val resolver = activity.contentResolver
val where = Expression.`in`(Column(Drafts._ID), RawItemArray(ids))
val projection = arrayOf(Drafts.MEDIA)
val c = resolver.query(Drafts.CONTENT_URI, projection, where.sql, null, null) ?: return 0
val idxMedia = c.getColumnIndex(Drafts.MEDIA)
c.moveToFirst()
while (!c.isAfterLast) {
val mediaArray = JsonSerializer.parseArray(c.getString(idxMedia), ParcelableMediaUpdate::class.java)
if (mediaArray != null) {
for (media in mediaArray) {
val uri = Uri.parse(media.uri)
if ("file" == uri.scheme) {
val file = File(uri.path)
if (!file.delete()) {
Log.w(LOGTAG, String.format("Unable to delete %s", file))
}
}
}
}
c.moveToNext()
}
c.close()
return resolver.delete(Drafts.CONTENT_URI, where.sql, null)
}
override fun onPreExecute() {
super.onPreExecute()
val f = ProgressDialogFragment.show(activity, FRAGMENT_TAG_DELETING_DRAFTS)
f.isCancelable = false
}
override fun onPostExecute(result: Int?) {
super.onPostExecute(result)
val f = activity.supportFragmentManager.findFragmentByTag(FRAGMENT_TAG_DELETING_DRAFTS)
if (f is DialogFragment) {
f.dismiss()
}
for (id in ids) {
val tag = Uri.withAppendedPath(Drafts.CONTENT_URI, id.toString()).toString()
notificationManager.cancel(tag, NOTIFICATION_ID_DRAFTS)
}
}
companion object {
private val FRAGMENT_TAG_DELETING_DRAFTS = "deleting_drafts"
}
}
}

View File

@ -104,9 +104,9 @@ public class ExtensionsListFragment extends BaseListFragment implements LoaderCa
if (extensionInfo.pname != null && extensionInfo.settings != null) {
final Intent intent = new Intent(INTENT_ACTION_EXTENSION_SETTINGS);
intent.setClassName(extensionInfo.pname, extensionInfo.settings);
MenuUtils.setMenuItemAvailability(menu, R.id.settings, mPackageManager.queryIntentActivities(intent, 0).size() == 1);
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.settings, mPackageManager.queryIntentActivities(intent, 0).size() == 1);
} else {
MenuUtils.setMenuItemAvailability(menu, R.id.settings, false);
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.settings, false);
}
}

View File

@ -214,7 +214,7 @@ public class HostMappingsListFragment extends BaseListFragment implements MultiC
final String host = ParseUtils.parseString(mEditHost.getText());
final String address = mCheckExclude.isChecked() ? host : ParseUtils.parseString(mEditAddress.getText());
if (isEmpty(host) || isEmpty(address)) return;
final SharedPreferences prefs = getSharedPreferences(HOST_MAPPING_PREFERENCES_NAME,
final SharedPreferences prefs = getContext().getSharedPreferences(HOST_MAPPING_PREFERENCES_NAME,
Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = prefs.edit();
editor.putString(host, address);

View File

@ -133,7 +133,7 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment implements
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE: {
mKeyboardShortcutsHandler.reset();
keyboardShortcutsHandler.reset();
break;
}
}

View File

@ -1,61 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
/**
* Created by mariotaku on 14-6-24.
*/
public class MessageDialogFragment extends BaseDialogFragment {
private static final String EXTRA_MESSAGE = "message";
public static MessageDialogFragment show(FragmentActivity activity, String message, String tag) {
MessageDialogFragment df = new MessageDialogFragment();
Bundle args = new Bundle();
args.putString(EXTRA_MESSAGE, message);
df.setArguments(args);
df.show(activity.getSupportFragmentManager(), tag);
return df;
}
public static MessageDialogFragment create(String message) {
MessageDialogFragment df = new MessageDialogFragment();
Bundle args = new Bundle();
args.putString(EXTRA_MESSAGE, message);
df.setArguments(args);
return df;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
FragmentActivity activity = getActivity();
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
final Bundle args = getArguments();
builder.setMessage(args.getString(EXTRA_MESSAGE));
builder.setPositiveButton(android.R.string.ok, null);
return builder.create();
}
}

View File

@ -0,0 +1,61 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.AlertDialog
import android.app.Dialog
import android.os.Bundle
import android.support.v4.app.FragmentActivity
/**
* Created by mariotaku on 14-6-24.
*/
class MessageDialogFragment : BaseDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val activity = activity
val builder = AlertDialog.Builder(activity)
val args = arguments
builder.setMessage(args.getString(EXTRA_MESSAGE))
builder.setPositiveButton(android.R.string.ok, null)
return builder.create()
}
companion object {
private val EXTRA_MESSAGE = "message"
fun show(activity: FragmentActivity, message: String, tag: String): MessageDialogFragment {
val df = MessageDialogFragment()
val args = Bundle()
args.putString(EXTRA_MESSAGE, message)
df.arguments = args
df.show(activity.supportFragmentManager, tag)
return df
}
fun create(message: String): MessageDialogFragment {
val df = MessageDialogFragment()
val args = Bundle()
args.putString(EXTRA_MESSAGE, message)
df.arguments = args
return df
}
}
}

View File

@ -0,0 +1,886 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.Activity
import android.app.AlertDialog
import android.app.Dialog
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.SharedPreferences
import android.database.Cursor
import android.os.AsyncTask
import android.os.Build
import android.os.Bundle
import android.support.v4.app.LoaderManager.LoaderCallbacks
import android.support.v4.content.CursorLoader
import android.support.v4.content.Loader
import android.support.v4.view.ViewCompat
import android.support.v7.app.ActionBar
import android.support.v7.widget.FixedLinearLayoutManager
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.PopupMenu
import android.support.v7.widget.RecyclerView
import android.text.Editable
import android.text.TextUtils
import android.text.TextWatcher
import android.util.Property
import android.view.*
import android.view.View.OnClickListener
import android.widget.AdapterView
import android.widget.AdapterView.OnItemSelectedListener
import android.widget.Toast
import com.squareup.otto.Subscribe
import kotlinx.android.synthetic.main.fragment_messages_conversation.*
import kotlinx.android.synthetic.main.layout_actionbar_message_user_picker.*
import me.uucky.colorpicker.internal.EffectViewHelper
import org.mariotaku.sqliteqb.library.Columns.Column
import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.sqliteqb.library.OrderBy
import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.*
import org.mariotaku.twidere.activity.BaseActivity
import org.mariotaku.twidere.activity.ThemedImagePickerActivity
import org.mariotaku.twidere.adapter.AccountsSpinnerAdapter
import org.mariotaku.twidere.adapter.MessageConversationAdapter
import org.mariotaku.twidere.adapter.SimpleParcelableUsersAdapter
import org.mariotaku.twidere.annotation.CustomTabType
import org.mariotaku.twidere.constant.KeyboardShortcutConstants.ACTION_NAVIGATION_BACK
import org.mariotaku.twidere.constant.KeyboardShortcutConstants.CONTEXT_TAG_NAVIGATION
import org.mariotaku.twidere.constant.SharedPreferenceConstants
import org.mariotaku.twidere.loader.UserSearchLoader
import org.mariotaku.twidere.model.*
import org.mariotaku.twidere.model.message.TaskStateChangedEvent
import org.mariotaku.twidere.model.util.ParcelableCredentialsUtils
import org.mariotaku.twidere.provider.TwidereDataStore
import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.Conversation
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.ConversationEntries
import org.mariotaku.twidere.util.*
import org.mariotaku.twidere.util.EditTextEnterHandler.EnterListener
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.TakeAllKeyboardShortcut
import org.mariotaku.twidere.util.Utils.buildDirectMessageConversationUri
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
import org.mariotaku.twidere.view.ExtendedRecyclerView
import java.util.*
import javax.inject.Inject
class MessagesConversationFragment : BaseSupportFragment(), LoaderCallbacks<Cursor>, OnClickListener, OnItemSelectedListener, PopupMenu.OnMenuItemClickListener, KeyboardShortcutCallback, TakeAllKeyboardShortcut {
// Callbacks and listeners
private val searchLoadersCallback = object : LoaderCallbacks<List<ParcelableUser>> {
override fun onCreateLoader(id: Int, args: Bundle): Loader<List<ParcelableUser>> {
usersSearchList!!.visibility = View.GONE
usersSearchEmpty!!.visibility = View.GONE
usersSearchProgress!!.visibility = View.VISIBLE
val accountKey = args.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
val query = args.getString(EXTRA_QUERY)
val fromCache = args.getBoolean(EXTRA_FROM_CACHE)
val fromUser = args.getBoolean(EXTRA_FROM_USER, false)
return CacheUserSearchLoader(this@MessagesConversationFragment, accountKey, query,
fromCache, fromUser)
}
override fun onLoadFinished(loader: Loader<List<ParcelableUser>>, data: List<ParcelableUser>?) {
usersSearchList!!.visibility = View.VISIBLE
usersSearchProgress!!.visibility = View.GONE
usersSearchEmpty!!.visibility = if (data == null || data.isEmpty()) View.GONE else View.VISIBLE
mUsersSearchAdapter!!.setData(data, true)
updateEmptyText()
}
override fun onLoaderReset(loader: Loader<List<ParcelableUser>>) {
}
}
private var scrollListener: PanelShowHideListener? = null
private var messageDrafts: SharedPreferences? = null
private var mEffectHelper: EffectViewHelper? = null
// Adapters
private var mAdapter: MessageConversationAdapter? = null
private var mUsersSearchAdapter: SimpleParcelableUsersAdapter? = null
// Data fields
private var searchUsersLoaderInitialized: Boolean = false
private var navigateBackPressed: Boolean = false
private val selectedDirectMessage: ParcelableDirectMessage? = null
private var loaderInitialized: Boolean = false
private var imageUri: String? = null
private var account: ParcelableCredentials? = null
private var recipient: ParcelableUser? = null
private var textChanged: Boolean = false
private var queryTextChanged: Boolean = false
private val backTimeoutRunnable = Runnable { navigateBackPressed = false }
@Subscribe
fun notifyTaskStateChanged(event: TaskStateChangedEvent) {
updateRefreshState()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
REQUEST_PICK_IMAGE -> {
if (resultCode == Activity.RESULT_OK && data!!.dataString != null) {
imageUri = data.dataString
updateAddImageButton()
}
}
}
super.onActivityResult(requestCode, resultCode, data)
}
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater!!.inflate(R.layout.fragment_messages_conversation, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val activity = activity as BaseActivity
messageDrafts = activity.getSharedPreferences(MESSAGE_DRAFTS_PREFERENCES_NAME, Context.MODE_PRIVATE)
val view = view!!
val viewContext = view.context
setHasOptionsMenu(true)
val actionBar = activity.supportActionBar ?: throw NullPointerException()
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
ActionBar.DISPLAY_SHOW_TITLE or ActionBar.DISPLAY_SHOW_CUSTOM)
actionBar.setCustomView(R.layout.layout_actionbar_message_user_picker)
val accounts = DataStoreUtils.getCredentialsList(activity, false)
val accountsSpinnerAdapter = AccountsSpinnerAdapter(
actionBar.themedContext, R.layout.spinner_item_account_icon)
accountsSpinnerAdapter.setDropDownViewResource(R.layout.list_item_user)
accountsSpinnerAdapter.addAll(accounts)
accountSpinner.adapter = accountsSpinnerAdapter
accountSpinner.onItemSelectedListener = this
queryButton.setOnClickListener(this)
mAdapter = MessageConversationAdapter(activity)
val layoutManager = FixedLinearLayoutManager(viewContext)
layoutManager.orientation = LinearLayoutManager.VERTICAL
layoutManager.stackFromEnd = true
recyclerView.layoutManager = layoutManager
recyclerView.adapter = mAdapter
val useOutline = Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP
val effectHelper: EffectViewHelper
if (useOutline) {
val elevation = resources.getDimension(R.dimen.element_spacing_normal)
val property = PanelElevationProperty(elevation)
effectHelper = EffectViewHelper(inputPanel, property, 100)
} else {
effectHelper = EffectViewHelper(inputPanelShadowCompat, View.ALPHA, 100)
}
scrollListener = PanelShowHideListener(effectHelper)
inputPanelShadowCompat!!.visibility = if (useOutline) View.GONE else View.VISIBLE
ViewCompat.setAlpha(inputPanelShadowCompat, 0f)
mUsersSearchAdapter = SimpleParcelableUsersAdapter(activity)
usersSearchList!!.adapter = mUsersSearchAdapter
usersSearchList!!.emptyView = usersSearchEmpty
usersSearchList!!.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
val account = accountSpinner.selectedItem as ParcelableCredentials
showConversation(account, mUsersSearchAdapter!!.getItem(position))
updateRecipientInfo()
}
setupEditQuery()
setupEditText()
send!!.setOnClickListener(this)
addImage!!.setOnClickListener(this)
send!!.isEnabled = false
if (savedInstanceState != null) {
val account = savedInstanceState.getParcelable<ParcelableCredentials>(EXTRA_ACCOUNT)
val recipient = savedInstanceState.getParcelable<ParcelableUser>(EXTRA_USER)
showConversation(account, recipient)
editText.setText(savedInstanceState.getString(EXTRA_TEXT))
imageUri = savedInstanceState.getString(EXTRA_IMAGE_URI)
} else {
val args = arguments
val account: ParcelableCredentials?
val recipient: ParcelableUser?
if (args != null) {
if (args.containsKey(EXTRA_ACCOUNT)) {
account = args.getParcelable<ParcelableCredentials>(EXTRA_ACCOUNT)
recipient = args.getParcelable<ParcelableUser>(EXTRA_USER)
} else if (args.containsKey(EXTRA_ACCOUNT_KEY) && args.containsKey(EXTRA_RECIPIENT_ID)) {
val accountKey = args.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
if (accountKey == null) {
getActivity().finish()
return
}
val accountPos = accountsSpinnerAdapter.findPositionByKey(accountKey)
if (accountPos >= 0) {
accountSpinner.setSelection(accountPos)
}
val userId = args.getString(EXTRA_RECIPIENT_ID)
if (accountPos >= 0) {
account = accountsSpinnerAdapter.getItem(accountPos)
} else {
account = ParcelableCredentialsUtils.getCredentials(activity, accountKey)
}
if (userId != null) {
recipient = Utils.getUserForConversation(activity, accountKey, userId)
} else {
recipient = null
}
} else {
account = null
recipient = null
}
showConversation(account, recipient)
if (account != null && recipient != null) {
val key = getDraftsTextKey(account.account_key, recipient.key)
editText.setText(messageDrafts!!.getString(key, null))
}
}
}
editText.setSelection(editText.length())
val isValid = account != null && recipient != null
conversationContainer!!.visibility = if (isValid) View.VISIBLE else View.GONE
recipientSelectorContainer!!.visibility = if (isValid) View.GONE else View.VISIBLE
usersSearchList!!.visibility = View.GONE
usersSearchProgress!!.visibility = View.GONE
registerForContextMenu(recyclerView)
queryTextChanged = false
textChanged = false
}
override fun onStart() {
super.onStart()
bus.register(this)
updateEmptyText()
recyclerView.addOnScrollListener(scrollListener)
scrollListener!!.reset()
}
override fun onResume() {
super.onResume()
updateAddImageButton()
}
override fun onSaveInstanceState(outState: Bundle?) {
super.onSaveInstanceState(outState)
if (editText != null) {
outState!!.putCharSequence(EXTRA_TEXT, editText.text)
}
outState!!.putParcelable(EXTRA_ACCOUNT, account)
outState.putParcelable(EXTRA_USER, recipient)
outState.putString(EXTRA_IMAGE_URI, imageUri)
}
override fun onStop() {
recyclerView.removeOnScrollListener(scrollListener)
bus.unregister(this)
val account = account
val recipient = recipient
if (account != null && recipient != null) {
val key = getDraftsTextKey(account.account_key, recipient.key)
val editor = messageDrafts!!.edit()
val text = ParseUtils.parseString(editText.text)
if (TextUtils.isEmpty(text)) {
editor.remove(key)
} else {
editor.putString(key, text)
}
editor.apply()
}
super.onStop()
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
inflater!!.inflate(R.menu.menu_direct_messages_conversation, menu)
}
override fun onPrepareOptionsMenu(menu: Menu?) {
super.onPrepareOptionsMenu(menu)
MenuUtils.setMenuItemAvailability(menu, R.id.delete_all, recipient != null && Utils.isOfficialCredentials(activity, account!!))
updateRecipientInfo()
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item!!.itemId) {
R.id.delete_all -> {
val account = account
if (account == null || recipient == null) return true
val args = Bundle()
args.putParcelable(EXTRA_ACCOUNT, account)
args.putParcelable(EXTRA_USER, recipient)
val df = DeleteConversationConfirmDialogFragment()
df.arguments = args
df.show(fragmentManager, "delete_conversation_confirm")
return true
}
}
return super.onOptionsItemSelected(item)
}
override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> {
val accountId = args?.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
val recipientId = args?.getString(EXTRA_RECIPIENT_ID)
val cols = DirectMessages.COLUMNS
val isValid = accountId != null && recipientId != null
conversationContainer!!.visibility = if (isValid) View.VISIBLE else View.GONE
recipientSelectorContainer!!.visibility = if (isValid) View.GONE else View.VISIBLE
if (!isValid) {
return CursorLoader(activity, TwidereDataStore.CONTENT_URI_NULL, cols, null, null, null)
}
val uri = buildDirectMessageConversationUri(accountId, recipientId, null)
return CursorLoader(activity, uri, cols, null, null, Conversation.DEFAULT_SORT_ORDER)
}
override fun onClick(view: View) {
when (view.id) {
R.id.send -> {
sendDirectMessage()
}
R.id.addImage -> {
val intent = ThemedImagePickerActivity.withThemed(activity).build()
startActivityForResult(intent, REQUEST_PICK_IMAGE)
}
R.id.queryButton -> {
val account = accountSpinner.selectedItem as ParcelableCredentials
searchUsers(account.account_key, ParseUtils.parseString(editUserQuery!!.text), false)
}
}
}
override fun onItemSelected(parent: AdapterView<*>, view: View, pos: Int, id: Long) {
val account = accountSpinner.selectedItem as ParcelableCredentials?
if (account != null) {
this.account = account
updateRecipientInfo()
updateAccount()
}
}
override fun onNothingSelected(view: AdapterView<*>) {
}
override fun onLoaderReset(loader: Loader<Cursor>) {
mAdapter!!.setCursor(null)
}
override fun onMenuItemClick(item: MenuItem): Boolean {
val message = selectedDirectMessage
if (message != null) {
when (item.itemId) {
R.id.delete -> {
twitterWrapper.destroyDirectMessageAsync(message.account_key, message.id)
}
R.id.copy -> {
if (ClipboardUtils.setText(activity, message.text_plain)) {
Utils.showOkMessage(activity, R.string.text_copied, false)
}
}
else -> return false
}
}
return true
}
override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor) {
mAdapter!!.setCursor(cursor)
}
override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo?) {
if (menuInfo == null) return
val inflater = MenuInflater(context)
val contextMenuInfo = menuInfo as ExtendedRecyclerView.ContextMenuInfo?
val message = mAdapter!!.getDirectMessage(contextMenuInfo!!.position)
menu.setHeaderTitle(message.text_unescaped)
inflater.inflate(R.menu.action_direct_message, menu)
}
override fun onContextItemSelected(item: MenuItem?): Boolean {
if (!userVisibleHint) return false
val menuInfo = item!!.menuInfo
val contextMenuInfo = menuInfo as ExtendedRecyclerView.ContextMenuInfo
val message = mAdapter!!.getDirectMessage(contextMenuInfo.position) ?: return false
when (item.itemId) {
R.id.copy -> {
ClipboardUtils.setText(context, message.text_plain)
return true
}
R.id.delete -> {
val args = Bundle()
args.putParcelable(EXTRA_ACCOUNT, account)
args.putParcelable(EXTRA_MESSAGE, message)
val df = DeleteMessageConfirmDialogFragment()
df.arguments = args
df.show(fragmentManager, "delete_message_confirm")
return true
}
}
return false
}
override fun handleKeyboardShortcutSingle(handler: KeyboardShortcutsHandler, keyCode: Int, event: KeyEvent, metaState: Int): Boolean {
val action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event, metaState)
if (ACTION_NAVIGATION_BACK == action) {
val showingConversation = isShowingConversation
val editText = if (showingConversation) editText else editUserQuery
val textChanged = if (showingConversation) textChanged else queryTextChanged
if (editText.length() == 0 && !textChanged) {
val activity = activity
if (!navigateBackPressed) {
Toast.makeText(activity, R.string.press_again_to_close, Toast.LENGTH_SHORT).show()
editText.removeCallbacks(backTimeoutRunnable)
editText.postDelayed(backTimeoutRunnable, 2000)
navigateBackPressed = true
} else {
activity.onBackPressed()
}
} else {
queryTextChanged = false
this.textChanged = false
}
return true
}
return false
}
override fun isKeyboardShortcutHandled(handler: KeyboardShortcutsHandler, keyCode: Int, event: KeyEvent, metaState: Int): Boolean {
val action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event, metaState)
return ACTION_NAVIGATION_BACK == action
}
override fun handleKeyboardShortcutRepeat(handler: KeyboardShortcutsHandler, keyCode: Int, repeatCount: Int, event: KeyEvent, metaState: Int): Boolean {
return false
}
fun showConversation(account: ParcelableCredentials?, recipient: ParcelableUser?) {
this.account = account
this.recipient = recipient
if (account == null || recipient == null) return
val lm = loaderManager
val args = Bundle()
args.putParcelable(EXTRA_ACCOUNT_KEY, account.account_key)
args.putString(EXTRA_RECIPIENT_ID, recipient.key.id)
if (loaderInitialized) {
lm.restartLoader(0, args, this)
} else {
loaderInitialized = true
lm.initLoader(0, args, this)
}
AsyncTaskUtils.executeTask(SetReadStateTask(activity, account, recipient))
updateActionBar()
updateRecipientInfo()
updateAccount()
editText.requestFocus()
}
private fun updateAccount() {
if (account == null) return
if (Utils.isOfficialCredentials(context, account!!)) {
addImage!!.visibility = View.VISIBLE
} else {
addImage!!.visibility = View.GONE
}
}
val isShowingConversation: Boolean
get() = conversationContainer!!.visibility == View.VISIBLE
private fun getDraftsTextKey(accountKey: UserKey, userId: UserKey): String {
return String.format(Locale.ROOT, "text_%s_to_%s", accountKey, userId)
}
private fun searchUsers(accountKey: UserKey, query: String, fromCache: Boolean) {
val args = Bundle()
args.putParcelable(EXTRA_ACCOUNT_KEY, accountKey)
args.putString(EXTRA_QUERY, query)
args.putBoolean(EXTRA_FROM_CACHE, fromCache)
val lm = loaderManager
if (searchUsersLoaderInitialized) {
lm.restartLoader(LOADER_ID_SEARCH_USERS, args, searchLoadersCallback)
} else {
searchUsersLoaderInitialized = true
lm.initLoader(LOADER_ID_SEARCH_USERS, args, searchLoadersCallback)
}
}
// @Override
// public void onRefreshFromEnd() {
// new TwidereAsyncTask<Object, Object, long[][]>() {
//
// @Override
// protected long[][] doInBackground(final Object... params) {
// final long[][] result = new long[2][];
// result[0] = getActivatedAccountIds(getActivity());
// result[1] = getNewestMessageIdsFromDatabase(getActivity(), DirectMessages.Inbox.CONTENT_URI);
// return result;
// }
//
// @Override
// protected void onPostExecute(final long[][] result) {
// final AsyncTwitterWrapper twitter = getTwitterWrapper();
// if (twitter == null) return;
// twitter.getReceivedDirectMessagesAsync(result[0], null, result[1]);
// twitter.getSentDirectMessagesAsync(result[0], null, null);
// }
//
// }.executeTask();
// }
//
// @Override
// public void onRefresh() {
// loadMoreMessages();
// }
private fun sendDirectMessage() {
val account = account ?: return
val recipient = recipient ?: return
val message = editText.text.toString()
if (TextUtils.isEmpty(message)) {
editText.error = getString(R.string.error_message_no_content)
} else {
twitterWrapper.sendDirectMessageAsync(account.account_key, recipient.key.id,
message, imageUri)
editText.text = null
imageUri = null
updateAddImageButton()
}
}
private fun setupEditQuery() {
val queryEnterHandler = EditTextEnterHandler.attach(editUserQuery!!, object : EnterListener {
override fun shouldCallListener(): Boolean {
val activity = activity
if (activity !is BaseActivity) return false
return activity.keyMetaState == 0
}
override fun onHitEnter(): Boolean {
val activity = activity
if (activity !is BaseActivity) return false
if (activity.keyMetaState != 0) return false
val account = accountSpinner.selectedItem as ParcelableCredentials ?: return false
editText.setAccountKey(account.account_key)
searchUsers(account.account_key, ParseUtils.parseString(editUserQuery!!.text), false)
return true
}
}, true)
queryEnterHandler.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable) {
val account = accountSpinner.selectedItem as ParcelableCredentials ?: return
editText.setAccountKey(account.account_key)
searchUsers(account.account_key, ParseUtils.parseString(s), true)
}
})
editUserQuery!!.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable) {
// Utils.removeLineBreaks(s);
queryTextChanged = s.length == 0
}
})
}
private fun setupEditText() {
EditTextEnterHandler.attach(editText, object : EnterListener {
override fun shouldCallListener(): Boolean {
return true
}
override fun onHitEnter(): Boolean {
sendDirectMessage()
return true
}
}, preferences.getBoolean(SharedPreferenceConstants.KEY_QUICK_SEND, false))
editText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable) {
textChanged = s.length == 0
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
if (send == null || s == null) return
send!!.isEnabled = validator.isValidDirectMessage(s.toString())
}
})
}
private fun updateActionBar() {
val activity = activity as BaseActivity
val actionBar = activity.supportActionBar ?: return
actionBar.setDisplayOptions(if (recipient != null) ActionBar.DISPLAY_SHOW_TITLE else ActionBar.DISPLAY_SHOW_CUSTOM,
ActionBar.DISPLAY_SHOW_TITLE or ActionBar.DISPLAY_SHOW_CUSTOM)
}
private fun updateAddImageButton() {
addImage!!.isActivated = imageUri != null
}
// @Override
// public boolean scrollToStart() {
// if (mAdapter == null || mAdapter.isEmpty()) return false;
// setSelection(mAdapter.getCount() - 1);
// return true;
// }
private fun updateEmptyText() {
val noQuery = editUserQuery!!.length() <= 0
if (noQuery) {
usersSearchEmptyText!!.setText(R.string.type_name_to_search)
} else {
usersSearchEmptyText!!.setText(R.string.no_user_found)
}
}
private fun updateRecipientInfo() {
val activity = activity ?: return
if (recipient != null) {
activity.title = userColorNameManager.getDisplayName(recipient,
preferences.getBoolean(KEY_NAME_FIRST))
} else {
activity.setTitle(R.string.direct_messages)
}
}
// @Override
// protected void onReachedTop() {
// if (!mLoadMoreAutomatically) return;
// loadMoreMessages();
// }
private fun updateRefreshState() {
// final AsyncTwitterWrapper twitter = getTwitterWrapper();
// if (twitter == null || !getUserVisibleHint()) return;
// final boolean refreshing = twitter.isReceivedDirectMessagesRefreshing()
// || twitter.isSentDirectMessagesRefreshing();
// setRefreshing(refreshing);
}
// private void loadMoreMessages() {
// if (isRefreshing()) return;
// new TwidereAsyncTask<Object, Object, long[][]>() {
//
// @Override
// protected long[][] doInBackground(final Object... params) {
// final long[][] result = new long[3][];
// result[0] = getActivatedAccountIds(getActivity());
// result[1] = getOldestMessageIdsFromDatabase(getActivity(), DirectMessages.Inbox.CONTENT_URI);
// result[2] = getOldestMessageIdsFromDatabase(getActivity(), DirectMessages.Outbox.CONTENT_URI);
// return result;
// }
//
// @Override
// protected void onPostExecute(final long[][] result) {
// final AsyncTwitterWrapper twitter = getTwitterWrapper();
// if (twitter == null) return;
// twitter.getReceivedDirectMessagesAsync(result[0], result[1], null);
// twitter.getSentDirectMessagesAsync(result[0], result[2], null);
// }
//
// }.executeTask();
// }
class CacheUserSearchLoader(
fragment: MessagesConversationFragment,
accountKey: UserKey,
query: String,
private val fromCache: Boolean,
fromUser: Boolean
) : UserSearchLoader(fragment.context, accountKey, query, 0, null, fromUser) {
private val userColorNameManager: UserColorNameManager
init {
userColorNameManager = fragment.userColorNameManager
}
override fun loadInBackground(): List<ParcelableUser> {
val query = query
if (TextUtils.isEmpty(query)) return emptyList()
if (fromCache) {
val cachedList = ArrayList<ParcelableUser>()
val queryEscaped = query.replace("_", "^_")
val nicknameKeys = Utils.getMatchedNicknameKeys(query, userColorNameManager)
val selection = Expression.or(Expression.likeRaw(Column(CachedUsers.SCREEN_NAME), "?||'%'", "^"),
Expression.likeRaw(Column(CachedUsers.NAME), "?||'%'", "^"),
Expression.inArgs(Column(CachedUsers.USER_KEY), nicknameKeys.size))
val selectionArgs = arrayOf(queryEscaped, queryEscaped, *nicknameKeys)
val order = arrayOf(CachedUsers.LAST_SEEN, CachedUsers.SCREEN_NAME, CachedUsers.NAME)
val ascending = booleanArrayOf(false, true, true)
val orderBy = OrderBy(order, ascending)
val c = context.contentResolver.query(CachedUsers.CONTENT_URI,
CachedUsers.BASIC_COLUMNS, selection?.sql,
selectionArgs, orderBy.sql)!!
val i = ParcelableUserCursorIndices(c)
c.moveToFirst()
while (!c.isAfterLast) {
cachedList.add(i.newObject(c))
c.moveToNext()
}
c.close()
return cachedList
}
return super.loadInBackground()
}
}
class DeleteConversationConfirmDialogFragment : BaseDialogFragment(), DialogInterface.OnClickListener {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(activity)
builder.setMessage(R.string.delete_conversation_confirm_message)
builder.setPositiveButton(android.R.string.ok, this)
builder.setNegativeButton(android.R.string.cancel, null)
return builder.create()
}
override fun onClick(dialog: DialogInterface, which: Int) {
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
val args = arguments
val account = args.getParcelable<ParcelableCredentials>(EXTRA_ACCOUNT)
val user = args.getParcelable<ParcelableUser>(EXTRA_USER)
val twitter = twitterWrapper
if (account == null || user == null) return
twitter.destroyMessageConversationAsync(account.account_key, user.key.id)
}
}
}
}
class DeleteMessageConfirmDialogFragment : BaseDialogFragment(), DialogInterface.OnClickListener {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(activity)
builder.setMessage(R.string.delete_message_confirm_message)
builder.setPositiveButton(android.R.string.ok, this)
builder.setNegativeButton(android.R.string.cancel, null)
return builder.create()
}
override fun onClick(dialog: DialogInterface, which: Int) {
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
val args = arguments
val account = args.getParcelable<ParcelableCredentials>(EXTRA_ACCOUNT)
val message = args.getParcelable<ParcelableDirectMessage>(EXTRA_MESSAGE)
val twitter = twitterWrapper
if (account == null || message == null) return
twitter.destroyDirectMessageAsync(account.account_key, message.id)
}
}
}
}
class SetReadStateTask(private val context: Context, private val account: ParcelableCredentials, private val recipient: ParcelableUser) : AsyncTask<Any, Any, Cursor>() {
@Inject
lateinit var readStateManager: ReadStateManager
init {
GeneralComponentHelper.build(context).inject(this)
}
override fun doInBackground(vararg params: Any): Cursor {
val resolver = context.contentResolver
val projection = arrayOf(ConversationEntries.MESSAGE_ID)
val selection = Expression.and(
Expression.equalsArgs(ConversationEntries.ACCOUNT_KEY),
Expression.equalsArgs(ConversationEntries.CONVERSATION_ID)).sql
val selectionArgs = arrayOf(account.account_key.toString(), recipient.key.toString())
val orderBy = OrderBy(ConversationEntries.MESSAGE_ID, false).sql
return resolver.query(ConversationEntries.CONTENT_URI, projection, selection,
selectionArgs, orderBy)
}
override fun onPostExecute(cursor: Cursor) {
if (cursor.moveToFirst()) {
val messageIdIdx = cursor.getColumnIndex(ConversationEntries.MESSAGE_ID)
val key = "${account.account_key}-${recipient.key}"
readStateManager.setPosition(CustomTabType.DIRECT_MESSAGES, key, cursor.getLong(messageIdIdx), false)
}
cursor.close()
}
}
internal class PanelShowHideListener(private val effectHelper: EffectViewHelper) : RecyclerView.OnScrollListener() {
private var showElevation: Boolean = false
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
val showElevation = layoutManager.findLastCompletelyVisibleItemPosition() < layoutManager.itemCount - 1
if (showElevation != showElevation) {
effectHelper.setState(showElevation)
}
this.showElevation = showElevation
}
fun reset() {
effectHelper.resetState(showElevation)
}
}
internal class PanelElevationProperty(private val elevation: Float) : Property<View, Float>(java.lang.Float.TYPE, null) {
override fun set(`object`: View, value: Float?) {
ViewCompat.setTranslationZ(`object`, elevation * value!!)
}
override fun get(`object`: View): Float? {
return ViewCompat.getTranslationZ(`object`) / elevation
}
}
companion object {
// Constants
private val LOADER_ID_SEARCH_USERS = 1
private val EXTRA_FROM_CACHE = "from_cache"
}
}

View File

@ -1,63 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AlertDialog;
import org.mariotaku.twidere.R;
public class PhishingLinkWarningDialogFragment extends BaseDialogFragment implements OnClickListener {
@Override
public void onClick(final DialogInterface dialog, final int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE: {
final Bundle args = getArguments();
if (args == null) return;
final Uri uri = args.getParcelable(EXTRA_URI);
if (uri == null) return;
final Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(uri);
startActivity(intent);
break;
}
}
}
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(android.R.string.dialog_alert_title);
builder.setView(R.layout.dialog_phishing_link_warning);
builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, null);
return builder.create();
}
}

View File

@ -0,0 +1,56 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.Dialog
import android.content.DialogInterface
import android.content.DialogInterface.OnClickListener
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.support.v7.app.AlertDialog
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_URI
class PhishingLinkWarningDialogFragment : BaseDialogFragment(), OnClickListener {
override fun onClick(dialog: DialogInterface, which: Int) {
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
val args = arguments ?: return
val uri = args.getParcelable<Uri>(EXTRA_URI) ?: return
val intent = Intent(Intent.ACTION_VIEW)
intent.data = uri
startActivity(intent)
}
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(context)
builder.setTitle(android.R.string.dialog_alert_title)
builder.setView(R.layout.dialog_phishing_link_warning)
builder.setPositiveButton(android.R.string.ok, this)
builder.setNegativeButton(android.R.string.cancel, null)
return builder.create()
}
}

View File

@ -1,47 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import org.mariotaku.twidere.R;
public class ProgressDialogFragment extends BaseDialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final ProgressDialog dialog = new ProgressDialog(getActivity());
dialog.setMessage(getString(R.string.please_wait));
return dialog;
}
public static ProgressDialogFragment show(final FragmentActivity activity, final String tag) {
if (activity == null) return null;
final ProgressDialogFragment f = new ProgressDialogFragment();
f.show(activity.getSupportFragmentManager(), tag);
return f;
}
}

View File

@ -0,0 +1,46 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.Dialog
import android.app.ProgressDialog
import android.os.Bundle
import android.support.v4.app.FragmentActivity
import org.mariotaku.twidere.R
class ProgressDialogFragment : BaseDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = ProgressDialog(activity)
dialog.setMessage(getString(R.string.please_wait))
return dialog
}
companion object {
fun show(activity: FragmentActivity, tag: String): ProgressDialogFragment {
val f = ProgressDialogFragment()
f.show(activity.supportFragmentManager, tag)
return f
}
}
}

View File

@ -1,85 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AlertDialog;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
public class ReportSpamDialogFragment extends BaseDialogFragment implements DialogInterface.OnClickListener {
public static final String FRAGMENT_TAG = "create_user_block";
@Override
public void onClick(final DialogInterface dialog, final int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
final ParcelableUser user = getUser();
final AsyncTwitterWrapper twitter = mTwitterWrapper;
if (user == null || twitter == null) return;
twitter.reportSpamAsync(user.account_key, user.key);
break;
default:
break;
}
}
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final FragmentActivity activity = getActivity();
final Context context = activity;
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
final ParcelableUser user = getUser();
if (user != null) {
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String displayName = mUserColorNameManager.getDisplayName(user, nameFirst);
builder.setTitle(getString(R.string.report_user, displayName));
builder.setMessage(getString(R.string.report_user_confirm_message, displayName));
}
builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, null);
return builder.create();
}
private ParcelableUser getUser() {
final Bundle args = getArguments();
if (!args.containsKey(EXTRA_USER)) return null;
return args.getParcelable(EXTRA_USER);
}
public static ReportSpamDialogFragment show(final FragmentManager fm, final ParcelableUser user) {
final Bundle args = new Bundle();
args.putParcelable(EXTRA_USER, user);
final ReportSpamDialogFragment f = new ReportSpamDialogFragment();
f.setArguments(args);
f.show(fm, FRAGMENT_TAG);
return f;
}
}

View File

@ -0,0 +1,79 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.support.v4.app.FragmentManager
import android.support.v7.app.AlertDialog
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_USER
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_NAME_FIRST
import org.mariotaku.twidere.model.ParcelableUser
class ReportSpamDialogFragment : BaseDialogFragment(), DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface, which: Int) {
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
val user = user ?: return
twitterWrapper.reportSpamAsync(user.account_key, user.key)
}
else -> {
}
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(context)
val user = user
if (user != null) {
val nameFirst = preferences.getBoolean(KEY_NAME_FIRST)
val displayName = userColorNameManager.getDisplayName(user, nameFirst)
builder.setTitle(getString(R.string.report_user, displayName))
builder.setMessage(getString(R.string.report_user_confirm_message, displayName))
}
builder.setPositiveButton(android.R.string.ok, this)
builder.setNegativeButton(android.R.string.cancel, null)
return builder.create()
}
private val user: ParcelableUser?
get() {
val args = arguments
if (!args.containsKey(EXTRA_USER)) return null
return args.getParcelable<ParcelableUser>(EXTRA_USER)
}
companion object {
val FRAGMENT_TAG = "create_user_block"
fun show(fm: FragmentManager, user: ParcelableUser): ReportSpamDialogFragment {
val args = Bundle()
args.putParcelable(EXTRA_USER, user)
val f = ReportSpamDialogFragment()
f.arguments = args
f.show(fm, FRAGMENT_TAG)
return f
}
}
}

View File

@ -130,7 +130,7 @@ public class RetweetQuoteDialogFragment extends BaseDialogFragment {
commentContainer.setVisibility(useQuote ? View.VISIBLE : View.GONE);
editComment.setAccountKey(status.account_key);
final boolean sendByEnter = mPreferences.getBoolean(KEY_QUICK_SEND);
final boolean sendByEnter = preferences.getBoolean(KEY_QUICK_SEND);
final EditTextEnterHandler enterHandler = EditTextEnterHandler.attach(editComment, new EditTextEnterHandler.EnterListener() {
@Override
public boolean shouldCallListener() {
@ -176,7 +176,7 @@ public class RetweetQuoteDialogFragment extends BaseDialogFragment {
commentMenu.setOnTouchListener(mPopupMenu.getDragToOpenListener());
mPopupMenu.inflate(R.menu.menu_dialog_comment);
final Menu menu = mPopupMenu.getMenu();
MenuUtils.setMenuItemAvailability(menu, R.id.quote_original_status,
MenuUtils.Companion.setMenuItemAvailability(menu, R.id.quote_original_status,
status.retweet_id != null || status.quoted_id != null);
mPopupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
@ -196,7 +196,7 @@ public class RetweetQuoteDialogFragment extends BaseDialogFragment {
if (editComment.length() > 0) {
dismissDialog = retweetOrQuote(credentials, status, SHOW_PROTECTED_CONFIRM);
} else if (isMyRetweet(status)) {
mTwitterWrapper.cancelRetweetAsync(status.account_key, status.id, status.my_retweet_id);
twitterWrapper.cancelRetweetAsync(status.account_key, status.id, status.my_retweet_id);
dismissDialog = true;
} else if (useQuote(!status.user_is_protected, credentials)) {
dismissDialog = retweetOrQuote(credentials, status, SHOW_PROTECTED_CONFIRM);
@ -235,7 +235,7 @@ public class RetweetQuoteDialogFragment extends BaseDialogFragment {
}
final StatusTextCountView textCountView = (StatusTextCountView) alertDialog.findViewById(R.id.comment_text_count);
assert textCountView != null;
textCountView.setTextCount(mValidator.getTweetLength(s.toString()));
textCountView.setTextCount(validator.getTweetLength(s.toString()));
}
private ParcelableStatus getStatus() {
@ -247,7 +247,7 @@ public class RetweetQuoteDialogFragment extends BaseDialogFragment {
@CheckResult
private boolean retweetOrQuote(ParcelableAccount account, ParcelableStatus status,
boolean showProtectedConfirmation) {
AsyncTwitterWrapper twitter = mTwitterWrapper;
AsyncTwitterWrapper twitter = twitterWrapper;
final Dialog dialog = getDialog();
if (dialog == null || twitter == null) return false;
final EditText editComment = (EditText) dialog.findViewById(R.id.edit_comment);

View File

@ -1,73 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AlertDialog;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.util.IntentUtils;
import org.mariotaku.twidere.util.Utils;
public class SensitiveContentWarningDialogFragment extends BaseDialogFragment implements
DialogInterface.OnClickListener {
@Override
public void onClick(final DialogInterface dialog, final int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE: {
final Context context = getActivity();
final Bundle args = getArguments();
if (args == null || context == null) return;
final UserKey accountKey = args.getParcelable(EXTRA_ACCOUNT_KEY);
final ParcelableMedia current = args.getParcelable(EXTRA_CURRENT_MEDIA);
final ParcelableStatus status = args.getParcelable(EXTRA_STATUS);
final Bundle option = args.getBundle(EXTRA_ACTIVITY_OPTIONS);
final boolean newDocument = args.getBoolean(EXTRA_NEW_DOCUMENT);
final ParcelableMedia[] media = Utils.newParcelableArray(args.getParcelableArray(EXTRA_MEDIA),
ParcelableMedia.CREATOR);
IntentUtils.openMediaDirectly(context, accountKey, status, null, current, media,
option, newDocument);
break;
}
}
}
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Context context = getActivity();
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(android.R.string.dialog_alert_title);
builder.setMessage(R.string.sensitive_content_warning);
builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, null);
return builder.create();
}
}

View File

@ -0,0 +1,66 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.support.v7.app.AlertDialog
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.IntentConstants.*
import org.mariotaku.twidere.model.ParcelableMedia
import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.util.IntentUtils
import org.mariotaku.twidere.util.Utils
class SensitiveContentWarningDialogFragment : BaseDialogFragment(), DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface, which: Int) {
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
val context = activity
val args = arguments
if (args == null || context == null) return
val accountKey = args.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
val current = args.getParcelable<ParcelableMedia>(EXTRA_CURRENT_MEDIA)
val status = args.getParcelable<ParcelableStatus>(EXTRA_STATUS)
val option = args.getBundle(EXTRA_ACTIVITY_OPTIONS)
val newDocument = args.getBoolean(EXTRA_NEW_DOCUMENT)
val media = Utils.newParcelableArray(args.getParcelableArray(EXTRA_MEDIA),
ParcelableMedia.CREATOR)
IntentUtils.openMediaDirectly(context, accountKey, status, null, current, media,
option, newDocument)
}
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val context = activity
val builder = AlertDialog.Builder(context)
builder.setTitle(android.R.string.dialog_alert_title)
builder.setMessage(R.string.sensitive_content_warning)
builder.setPositiveButton(android.R.string.ok, this)
builder.setNegativeButton(android.R.string.cancel, null)
return builder.create()
}
}

View File

@ -1,103 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.AppCompatEditText;
import android.text.TextUtils;
import android.widget.EditText;
import android.widget.FrameLayout;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.util.ParseUtils;
public class SetUserNicknameDialogFragment extends BaseDialogFragment implements OnClickListener {
private static final String FRAGMENT_TAG_SET_USER_NICKNAME = "set_user_nickname";
private EditText mEditText;
@Override
public void onClick(final DialogInterface dialog, final int which) {
final Bundle args = getArguments();
assert args != null;
final String text = ParseUtils.parseString(mEditText.getText());
final UserKey userId = args.getParcelable(EXTRA_USER_KEY);
assert userId != null;
switch (which) {
case DialogInterface.BUTTON_POSITIVE: {
if (TextUtils.isEmpty(text)) {
mUserColorNameManager.clearUserNickname(userId);
} else {
mUserColorNameManager.setUserNickname(userId, text);
}
break;
}
case DialogInterface.BUTTON_NEUTRAL: {
mUserColorNameManager.clearUserNickname(userId);
break;
}
}
}
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Bundle args = getArguments();
final String nick = args.getString(EXTRA_NAME);
final Context context = getActivity();
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.set_nickname);
builder.setPositiveButton(android.R.string.ok, this);
if (!TextUtils.isEmpty(nick)) {
builder.setNeutralButton(R.string.clear, this);
}
builder.setNegativeButton(android.R.string.cancel, null);
final FrameLayout view = new FrameLayout(context);
mEditText = new AppCompatEditText(context);
final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
lp.leftMargin = lp.topMargin = lp.bottomMargin = lp.rightMargin = getResources().getDimensionPixelSize(
R.dimen.element_spacing_normal);
view.addView(mEditText, lp);
builder.setView(view);
mEditText.setText(nick);
return builder.create();
}
public static SetUserNicknameDialogFragment show(final FragmentManager fm, final UserKey userKey, final String nickname) {
final SetUserNicknameDialogFragment f = new SetUserNicknameDialogFragment();
final Bundle args = new Bundle();
args.putParcelable(EXTRA_USER_KEY, userKey);
args.putString(EXTRA_NAME, nickname);
f.setArguments(args);
f.show(fm, FRAGMENT_TAG_SET_USER_NICKNAME);
return f;
}
}

View File

@ -0,0 +1,87 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.Dialog
import android.content.DialogInterface
import android.content.DialogInterface.OnClickListener
import android.os.Bundle
import android.support.v4.app.FragmentManager
import android.support.v7.app.AlertDialog
import android.text.TextUtils
import android.widget.EditText
import org.mariotaku.ktextension.empty
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_NAME
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_USER_KEY
import org.mariotaku.twidere.model.UserKey
class SetUserNicknameDialogFragment : BaseDialogFragment(), OnClickListener {
override fun onClick(dialog: DialogInterface, which: Int) {
val args = arguments!!
val editName = (dialog as AlertDialog).findViewById(R.id.editName) as EditText
val userId = args.getParcelable<UserKey>(EXTRA_USER_KEY)!!
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
if (editName.empty) {
userColorNameManager.clearUserNickname(userId)
} else {
userColorNameManager.setUserNickname(userId, editName.text.toString())
}
}
DialogInterface.BUTTON_NEUTRAL -> {
userColorNameManager.clearUserNickname(userId)
}
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val args = arguments
val nick = args.getString(EXTRA_NAME)
val context = activity
val builder = AlertDialog.Builder(context)
builder.setTitle(R.string.set_nickname)
builder.setPositiveButton(android.R.string.ok, this)
if (!TextUtils.isEmpty(nick)) {
builder.setNeutralButton(R.string.clear, this)
}
builder.setNegativeButton(android.R.string.cancel, null)
builder.setView(R.layout.dialog_edit_user_nickname)
return builder.create()
}
companion object {
private val FRAGMENT_TAG_SET_USER_NICKNAME = "set_user_nickname"
fun show(fm: FragmentManager, userKey: UserKey, nickname: String): SetUserNicknameDialogFragment {
val f = SetUserNicknameDialogFragment()
val args = Bundle()
args.putParcelable(EXTRA_USER_KEY, userKey)
args.putString(EXTRA_NAME, nickname)
f.arguments = args
f.show(fm, FRAGMENT_TAG_SET_USER_NICKNAME)
return f
}
}
}

View File

@ -1,506 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.app.Activity;
import android.app.Dialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
import android.nfc.NfcEvent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CheckBox;
import com.rengwuxian.materialedittext.MaterialEditText;
import com.squareup.otto.Subscribe;
import org.mariotaku.microblog.library.MicroBlog;
import org.mariotaku.microblog.library.MicroBlogException;
import org.mariotaku.microblog.library.twitter.model.UserList;
import org.mariotaku.microblog.library.twitter.model.UserListUpdate;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.AccountSelectorActivity;
import org.mariotaku.twidere.activity.UserListSelectorActivity;
import org.mariotaku.twidere.adapter.SupportTabsAdapter;
import org.mariotaku.twidere.fragment.iface.IBaseFragment.SystemWindowsInsetsCallback;
import org.mariotaku.twidere.fragment.iface.SupportFragmentCallback;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.ParcelableUserList;
import org.mariotaku.twidere.model.SingleResponse;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.message.UserListSubscriptionEvent;
import org.mariotaku.twidere.model.message.UserListUpdatedEvent;
import org.mariotaku.twidere.model.util.ParcelableUserListUtils;
import org.mariotaku.twidere.text.validator.UserListNameValidator;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.IntentUtils;
import org.mariotaku.twidere.util.LinkCreator;
import org.mariotaku.twidere.util.MenuUtils;
import org.mariotaku.twidere.util.MicroBlogAPIFactory;
import org.mariotaku.twidere.util.ParseUtils;
import org.mariotaku.twidere.util.Utils;
public class UserListFragment extends AbsToolbarTabPagesFragment implements OnClickListener,
LoaderCallbacks<SingleResponse<ParcelableUserList>>, SystemWindowsInsetsCallback,
SupportFragmentCallback {
private boolean mUserListLoaderInitialized;
private ParcelableUserList mUserList;
public void displayUserList(final ParcelableUserList userList) {
final FragmentActivity activity = getActivity();
if (activity == null) return;
getLoaderManager().destroyLoader(0);
mUserList = userList;
if (userList != null) {
activity.setTitle(userList.name);
} else {
activity.setTitle(R.string.user_list);
}
invalidateOptionsMenu();
}
public void getUserListInfo(final boolean omitIntentExtra) {
final LoaderManager lm = getLoaderManager();
lm.destroyLoader(0);
final Bundle args = new Bundle(getArguments());
args.putBoolean(EXTRA_OMIT_INTENT_EXTRA, omitIntentExtra);
if (!mUserListLoaderInitialized) {
lm.initLoader(0, args, this);
mUserListLoaderInitialized = true;
} else {
lm.restartLoader(0, args, this);
}
}
@Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
final AsyncTwitterWrapper twitter = twitterWrapper;
switch (requestCode) {
case REQUEST_SELECT_USER: {
final ParcelableUserList userList = mUserList;
if (resultCode != Activity.RESULT_OK || !data.hasExtra(EXTRA_USER) || twitter == null
|| userList == null) return;
final ParcelableUser user = data.getParcelableExtra(EXTRA_USER);
twitter.addUserListMembersAsync(userList.account_key, userList.id, user);
return;
}
case REQUEST_SELECT_ACCOUNT: {
if (resultCode == Activity.RESULT_OK) {
if (data == null || !data.hasExtra(EXTRA_ID)) return;
final ParcelableUserList userList = mUserList;
final UserKey accountKey = data.getParcelableExtra(EXTRA_ACCOUNT_KEY);
IntentUtils.openUserListDetails(getActivity(), accountKey, userList.id,
userList.user_key, userList.user_screen_name, userList.name);
}
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final FragmentActivity activity = getActivity();
setHasOptionsMenu(true);
Utils.setNdefPushMessageCallback(activity, new CreateNdefMessageCallback() {
@Override
public NdefMessage createNdefMessage(NfcEvent event) {
final ParcelableUserList userList = getUserList();
if (userList == null) return null;
return new NdefMessage(new NdefRecord[]{
NdefRecord.createUri(LinkCreator.getTwitterUserListLink(userList.user_screen_name, userList.name)),
});
}
});
getUserListInfo(false);
}
@Override
protected void addTabs(SupportTabsAdapter adapter) {
final Bundle args = getArguments(), tabArgs = new Bundle();
if (args.containsKey(EXTRA_USER_LIST)) {
final ParcelableUserList userList = args.getParcelable(EXTRA_USER_LIST);
assert userList != null;
tabArgs.putParcelable(EXTRA_ACCOUNT_KEY, userList.account_key);
tabArgs.putParcelable(EXTRA_USER_KEY, userList.user_key);
tabArgs.putString(EXTRA_SCREEN_NAME, userList.user_screen_name);
tabArgs.putString(EXTRA_LIST_ID, userList.id);
tabArgs.putString(EXTRA_LIST_NAME, userList.name);
} else {
tabArgs.putParcelable(EXTRA_ACCOUNT_KEY, args.getParcelable(EXTRA_ACCOUNT_KEY));
tabArgs.putParcelable(EXTRA_USER_KEY, args.getParcelable(EXTRA_USER_KEY));
tabArgs.putString(EXTRA_SCREEN_NAME, args.getString(EXTRA_SCREEN_NAME));
tabArgs.putString(EXTRA_LIST_ID, args.getString(EXTRA_LIST_ID));
tabArgs.putString(EXTRA_LIST_NAME, args.getString(EXTRA_LIST_NAME));
}
adapter.addTab(UserListTimelineFragment.class, tabArgs, getString(R.string.statuses), null, 0, null);
adapter.addTab(UserListMembersFragment.class, tabArgs, getString(R.string.members), null, 1, null);
adapter.addTab(UserListSubscribersFragment.class, tabArgs, getString(R.string.subscribers), null, 2, null);
}
public ParcelableUserList getUserList() {
return mUserList;
}
@Override
public void onStart() {
super.onStart();
bus.register(this);
}
@Override
public void onStop() {
bus.unregister(this);
super.onStop();
}
@Override
public void onDestroyView() {
mUserList = null;
getLoaderManager().destroyLoader(0);
super.onDestroyView();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_user_list, menu);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
final ParcelableUserList userList = mUserList;
MenuUtils.setMenuItemAvailability(menu, R.id.info, userList != null);
menu.removeGroup(MENU_GROUP_USER_LIST_EXTENSION);
if (userList != null) {
final boolean isMyList = userList.user_key.equals(userList.account_key);
final boolean isFollowing = userList.is_following;
MenuUtils.setMenuItemAvailability(menu, R.id.edit, isMyList);
MenuUtils.setMenuItemAvailability(menu, R.id.follow, !isMyList);
MenuUtils.setMenuItemAvailability(menu, R.id.add, isMyList);
MenuUtils.setMenuItemAvailability(menu, R.id.delete, isMyList);
final MenuItem followItem = menu.findItem(R.id.follow);
if (isFollowing) {
followItem.setIcon(R.drawable.ic_action_cancel);
followItem.setTitle(R.string.unsubscribe);
} else {
followItem.setIcon(R.drawable.ic_action_add);
followItem.setTitle(R.string.subscribe);
}
final Intent extensionsIntent = new Intent(INTENT_ACTION_EXTENSION_OPEN_USER_LIST);
extensionsIntent.setExtrasClassLoader(getActivity().getClassLoader());
extensionsIntent.putExtra(EXTRA_USER_LIST, userList);
MenuUtils.addIntentToMenu(getActivity(), menu, extensionsIntent, MENU_GROUP_USER_LIST_EXTENSION);
} else {
MenuUtils.setMenuItemAvailability(menu, R.id.edit, false);
MenuUtils.setMenuItemAvailability(menu, R.id.follow, false);
MenuUtils.setMenuItemAvailability(menu, R.id.add, false);
MenuUtils.setMenuItemAvailability(menu, R.id.delete, false);
}
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
final AsyncTwitterWrapper twitter = twitterWrapper;
final ParcelableUserList userList = mUserList;
if (twitter == null || userList == null) return false;
switch (item.getItemId()) {
case R.id.add: {
if (!userList.user_key.equals(userList.account_key)) return false;
final Intent intent = new Intent(INTENT_ACTION_SELECT_USER);
intent.setClass(getActivity(), UserListSelectorActivity.class);
intent.putExtra(EXTRA_ACCOUNT_KEY, userList.account_key);
startActivityForResult(intent, REQUEST_SELECT_USER);
break;
}
case R.id.delete: {
if (!userList.user_key.equals(userList.account_key)) return false;
DestroyUserListDialogFragment.show(getFragmentManager(), userList);
break;
}
case R.id.edit: {
final Bundle args = new Bundle();
args.putParcelable(EXTRA_ACCOUNT_KEY, userList.account_key);
args.putString(EXTRA_LIST_NAME, userList.name);
args.putString(EXTRA_DESCRIPTION, userList.description);
args.putBoolean(EXTRA_IS_PUBLIC, userList.is_public);
args.putString(EXTRA_LIST_ID, userList.id);
final DialogFragment f = new EditUserListDialogFragment();
f.setArguments(args);
f.show(getFragmentManager(), "edit_user_list_details");
return true;
}
case R.id.follow: {
if (userList.is_following) {
DestroyUserListSubscriptionDialogFragment.show(getFragmentManager(), userList);
} else {
twitter.createUserListSubscriptionAsync(userList.account_key, userList.id);
}
return true;
}
case R.id.open_with_account: {
final Intent intent = new Intent(INTENT_ACTION_SELECT_ACCOUNT);
intent.setClass(getActivity(), AccountSelectorActivity.class);
intent.putExtra(EXTRA_SINGLE_SELECTION, true);
startActivityForResult(intent, REQUEST_SELECT_ACCOUNT);
break;
}
default: {
if (item.getIntent() != null) {
try {
startActivity(item.getIntent());
} catch (final ActivityNotFoundException e) {
Log.w(LOGTAG, e);
return false;
}
}
break;
}
}
return true;
}
@Override
public void onClick(final View view) {
switch (view.getId()) {
case R.id.errorContainer: {
getUserListInfo(true);
break;
}
case R.id.profile_image: {
final ParcelableUserList userList = mUserList;
if (userList == null) return;
IntentUtils.openUserProfile(getActivity(), userList.account_key,
userList.user_key, userList.user_screen_name, null,
preferences.getBoolean(KEY_NEW_DOCUMENT_API), null);
break;
}
}
}
@Override
public Loader<SingleResponse<ParcelableUserList>> onCreateLoader(final int id, final Bundle args) {
final UserKey accountKey = args.getParcelable(EXTRA_ACCOUNT_KEY);
final UserKey userKey = args.getParcelable(EXTRA_USER_KEY);
final String listId = args.getString(EXTRA_LIST_ID);
final String listName = args.getString(EXTRA_LIST_NAME);
final String screenName = args.getString(EXTRA_SCREEN_NAME);
final boolean omitIntentExtra = args.getBoolean(EXTRA_OMIT_INTENT_EXTRA, true);
return new ParcelableUserListLoader(getActivity(), omitIntentExtra, getArguments(), accountKey, listId,
listName, userKey, screenName);
}
@Override
public void onLoadFinished(final Loader<SingleResponse<ParcelableUserList>> loader,
final SingleResponse<ParcelableUserList> data) {
if (data == null) return;
if (getActivity() == null) return;
if (data.hasData()) {
final ParcelableUserList list = data.getData();
displayUserList(list);
} else if (data.hasException()) {
}
}
@Override
public void onLoaderReset(final Loader<SingleResponse<ParcelableUserList>> loader) {
}
@Subscribe
public void onUserListUpdated(UserListUpdatedEvent event) {
if (mUserList == null) return;
if (TextUtils.equals(event.getUserList().id, mUserList.id)) {
getUserListInfo(true);
}
}
@Subscribe
public void onUserListSubscriptionChanged(UserListSubscriptionEvent event) {
if (mUserList == null) return;
if (TextUtils.equals(event.getUserList().id, mUserList.id)) {
getUserListInfo(true);
}
}
public static class EditUserListDialogFragment extends BaseDialogFragment implements
DialogInterface.OnClickListener {
private String mName, mDescription;
private UserKey mAccountKey;
private String mListId;
private boolean mIsPublic;
@Override
public void onClick(final DialogInterface dialog, final int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE: {
final AlertDialog alertDialog = (AlertDialog) dialog;
final MaterialEditText editName = (MaterialEditText) alertDialog.findViewById(R.id.name);
final MaterialEditText editDescription = (MaterialEditText) alertDialog.findViewById(R.id.description);
final CheckBox editIsPublic = (CheckBox) alertDialog.findViewById(R.id.is_public);
assert editName != null && editDescription != null && editIsPublic != null;
final String name = ParseUtils.parseString(editName.getText());
final String description = ParseUtils.parseString(editDescription.getText());
final boolean isPublic = editIsPublic.isChecked();
if (TextUtils.isEmpty(name)) return;
final UserListUpdate update = new UserListUpdate();
update.setMode(isPublic ? UserList.Mode.PUBLIC : UserList.Mode.PRIVATE);
update.setName(name);
update.setDescription(description);
mTwitterWrapper.updateUserListDetails(mAccountKey, mListId, update);
break;
}
}
}
@NonNull
@Override
public Dialog onCreateDialog(final Bundle savedInstanceState) {
final Bundle bundle = savedInstanceState == null ? getArguments() : savedInstanceState;
mAccountKey = bundle != null ? bundle.<UserKey>getParcelable(EXTRA_ACCOUNT_KEY) : null;
mListId = bundle != null ? bundle.getString(EXTRA_LIST_ID) : null;
mName = bundle != null ? bundle.getString(EXTRA_LIST_NAME) : null;
mDescription = bundle != null ? bundle.getString(EXTRA_DESCRIPTION) : null;
mIsPublic = bundle == null || bundle.getBoolean(EXTRA_IS_PUBLIC, true);
final Context context = getActivity();
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setView(R.layout.dialog_user_list_detail_editor);
builder.setTitle(R.string.user_list);
builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, this);
final AlertDialog dialog = builder.create();
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
AlertDialog alertDialog = (AlertDialog) dialog;
MaterialEditText editName = (MaterialEditText) alertDialog.findViewById(R.id.name);
MaterialEditText editDescription = (MaterialEditText) alertDialog.findViewById(R.id.description);
CheckBox editPublic = (CheckBox) alertDialog.findViewById(R.id.is_public);
assert editName != null && editDescription != null && editPublic != null;
editName.addValidator(new UserListNameValidator(getString(R.string.invalid_list_name)));
if (mName != null) {
editName.setText(mName);
}
if (mDescription != null) {
editDescription.setText(mDescription);
}
editPublic.setChecked(mIsPublic);
}
});
return dialog;
}
@Override
public void onSaveInstanceState(final Bundle outState) {
outState.putParcelable(EXTRA_ACCOUNT_KEY, mAccountKey);
outState.putString(EXTRA_LIST_ID, mListId);
outState.putString(EXTRA_LIST_NAME, mName);
outState.putString(EXTRA_DESCRIPTION, mDescription);
outState.putBoolean(EXTRA_IS_PUBLIC, mIsPublic);
super.onSaveInstanceState(outState);
}
}
static class ParcelableUserListLoader extends AsyncTaskLoader<SingleResponse<ParcelableUserList>> {
private final boolean mOmitIntentExtra;
private final Bundle mExtras;
private final UserKey mAccountKey;
private final UserKey mUserKey;
private final String mListId;
private final String mScreenName, mListName;
private ParcelableUserListLoader(final Context context, final boolean omitIntentExtra,
final Bundle extras, final UserKey accountKey,
final String listId, final String listName,
final UserKey userKey, final String screenName) {
super(context);
mOmitIntentExtra = omitIntentExtra;
mExtras = extras;
mAccountKey = accountKey;
mUserKey = userKey;
mListId = listId;
mScreenName = screenName;
mListName = listName;
}
@Override
public SingleResponse<ParcelableUserList> loadInBackground() {
if (!mOmitIntentExtra && mExtras != null) {
final ParcelableUserList cache = mExtras.getParcelable(EXTRA_USER_LIST);
if (cache != null) return SingleResponse.getInstance(cache);
}
final MicroBlog twitter = MicroBlogAPIFactory.getInstance(getContext(), mAccountKey,
true);
if (twitter == null) return SingleResponse.getInstance();
try {
final UserList list;
if (mListId != null) {
list = twitter.showUserList(mListId);
} else if (mUserKey != null) {
list = twitter.showUserList(mListName, mUserKey.getId());
} else if (mScreenName != null) {
list = twitter.showUserListByScrenName(mListName, mScreenName);
} else
return SingleResponse.getInstance();
return SingleResponse.getInstance(ParcelableUserListUtils.from(list, mAccountKey));
} catch (final MicroBlogException e) {
return SingleResponse.getInstance(e);
}
}
@Override
public void onStartLoading() {
forceLoad();
}
}
}

View File

@ -0,0 +1,437 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.app.Activity
import android.app.Dialog
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.nfc.NdefMessage
import android.nfc.NdefRecord
import android.nfc.NfcAdapter.CreateNdefMessageCallback
import android.os.Bundle
import android.support.v4.app.LoaderManager.LoaderCallbacks
import android.support.v4.content.AsyncTaskLoader
import android.support.v4.content.Loader
import android.support.v7.app.AlertDialog
import android.text.TextUtils
import android.util.Log
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.View.OnClickListener
import android.widget.CheckBox
import com.rengwuxian.materialedittext.MaterialEditText
import com.squareup.otto.Subscribe
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.microblog.library.twitter.model.UserList
import org.mariotaku.microblog.library.twitter.model.UserListUpdate
import org.mariotaku.twidere.Constants.*
import org.mariotaku.twidere.R
import org.mariotaku.twidere.activity.AccountSelectorActivity
import org.mariotaku.twidere.activity.UserListSelectorActivity
import org.mariotaku.twidere.adapter.SupportTabsAdapter
import org.mariotaku.twidere.fragment.iface.IBaseFragment.SystemWindowsInsetsCallback
import org.mariotaku.twidere.fragment.iface.SupportFragmentCallback
import org.mariotaku.twidere.model.ParcelableUser
import org.mariotaku.twidere.model.ParcelableUserList
import org.mariotaku.twidere.model.SingleResponse
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.message.UserListSubscriptionEvent
import org.mariotaku.twidere.model.message.UserListUpdatedEvent
import org.mariotaku.twidere.model.util.ParcelableUserListUtils
import org.mariotaku.twidere.text.validator.UserListNameValidator
import org.mariotaku.twidere.util.*
class UserListFragment : AbsToolbarTabPagesFragment(), OnClickListener, LoaderCallbacks<SingleResponse<ParcelableUserList>>, SystemWindowsInsetsCallback, SupportFragmentCallback {
private var mUserListLoaderInitialized: Boolean = false
var userList: ParcelableUserList? = null
private set
fun displayUserList(userList: ParcelableUserList?) {
val activity = activity ?: return
loaderManager.destroyLoader(0)
this.userList = userList
if (userList != null) {
activity.title = userList.name
} else {
activity.setTitle(R.string.user_list)
}
invalidateOptionsMenu()
}
fun getUserListInfo(omitIntentExtra: Boolean) {
val lm = loaderManager
lm.destroyLoader(0)
val args = Bundle(arguments)
args.putBoolean(EXTRA_OMIT_INTENT_EXTRA, omitIntentExtra)
if (!mUserListLoaderInitialized) {
lm.initLoader(0, args, this)
mUserListLoaderInitialized = true
} else {
lm.restartLoader(0, args, this)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
val twitter = twitterWrapper
when (requestCode) {
REQUEST_SELECT_USER -> {
val userList = this.userList
if (resultCode != Activity.RESULT_OK || !data!!.hasExtra(EXTRA_USER) || twitter == null
|| userList == null)
return
val user = data.getParcelableExtra<ParcelableUser>(EXTRA_USER)
twitter.addUserListMembersAsync(userList.account_key, userList.id, user)
return
}
REQUEST_SELECT_ACCOUNT -> {
if (resultCode == Activity.RESULT_OK) {
if (data == null || !data.hasExtra(EXTRA_ID)) return
val userList = this.userList
val accountKey = data.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY)
IntentUtils.openUserListDetails(activity, accountKey, userList!!.id,
userList.user_key, userList.user_screen_name, userList.name)
}
}
}
super.onActivityResult(requestCode, resultCode, data)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val activity = activity
setHasOptionsMenu(true)
Utils.setNdefPushMessageCallback(activity, CreateNdefMessageCallback {
val userList = userList ?: return@CreateNdefMessageCallback null
NdefMessage(arrayOf(NdefRecord.createUri(LinkCreator.getTwitterUserListLink(userList.user_screen_name, userList.name))))
})
getUserListInfo(false)
}
override fun addTabs(adapter: SupportTabsAdapter) {
val args = arguments
val tabArgs = Bundle()
if (args.containsKey(EXTRA_USER_LIST)) {
val userList = args.getParcelable<ParcelableUserList>(EXTRA_USER_LIST)!!
tabArgs.putParcelable(EXTRA_ACCOUNT_KEY, userList.account_key)
tabArgs.putParcelable(EXTRA_USER_KEY, userList.user_key)
tabArgs.putString(EXTRA_SCREEN_NAME, userList.user_screen_name)
tabArgs.putString(EXTRA_LIST_ID, userList.id)
tabArgs.putString(EXTRA_LIST_NAME, userList.name)
} else {
tabArgs.putParcelable(EXTRA_ACCOUNT_KEY, args.getParcelable(EXTRA_ACCOUNT_KEY))
tabArgs.putParcelable(EXTRA_USER_KEY, args.getParcelable(EXTRA_USER_KEY))
tabArgs.putString(EXTRA_SCREEN_NAME, args.getString(EXTRA_SCREEN_NAME))
tabArgs.putString(EXTRA_LIST_ID, args.getString(EXTRA_LIST_ID))
tabArgs.putString(EXTRA_LIST_NAME, args.getString(EXTRA_LIST_NAME))
}
adapter.addTab(UserListTimelineFragment::class.java, tabArgs, getString(R.string.statuses), null, 0, null)
adapter.addTab(UserListMembersFragment::class.java, tabArgs, getString(R.string.members), null, 1, null)
adapter.addTab(UserListSubscribersFragment::class.java, tabArgs, getString(R.string.subscribers), null, 2, null)
}
override fun onStart() {
super.onStart()
bus.register(this)
}
override fun onStop() {
bus.unregister(this)
super.onStop()
}
override fun onDestroyView() {
userList = null
loaderManager.destroyLoader(0)
super.onDestroyView()
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
inflater!!.inflate(R.menu.menu_user_list, menu)
}
override fun onPrepareOptionsMenu(menu: Menu?) {
val userList = this.userList
MenuUtils.setMenuItemAvailability(menu, R.id.info, userList != null)
menu!!.removeGroup(MENU_GROUP_USER_LIST_EXTENSION)
if (userList != null) {
val isMyList = userList.user_key == userList.account_key
val isFollowing = userList.is_following
MenuUtils.setMenuItemAvailability(menu, R.id.edit, isMyList)
MenuUtils.setMenuItemAvailability(menu, R.id.follow, !isMyList)
MenuUtils.setMenuItemAvailability(menu, R.id.add, isMyList)
MenuUtils.setMenuItemAvailability(menu, R.id.delete, isMyList)
val followItem = menu.findItem(R.id.follow)
if (isFollowing) {
followItem.setIcon(R.drawable.ic_action_cancel)
followItem.setTitle(R.string.unsubscribe)
} else {
followItem.setIcon(R.drawable.ic_action_add)
followItem.setTitle(R.string.subscribe)
}
val extensionsIntent = Intent(INTENT_ACTION_EXTENSION_OPEN_USER_LIST)
extensionsIntent.setExtrasClassLoader(activity.classLoader)
extensionsIntent.putExtra(EXTRA_USER_LIST, userList)
MenuUtils.addIntentToMenu(activity, menu, extensionsIntent, MENU_GROUP_USER_LIST_EXTENSION)
} else {
MenuUtils.setMenuItemAvailability(menu, R.id.edit, false)
MenuUtils.setMenuItemAvailability(menu, R.id.follow, false)
MenuUtils.setMenuItemAvailability(menu, R.id.add, false)
MenuUtils.setMenuItemAvailability(menu, R.id.delete, false)
}
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
val twitter = twitterWrapper
val userList = userList ?: return false
when (item!!.itemId) {
R.id.add -> {
if (userList.user_key != userList.account_key) return false
val intent = Intent(INTENT_ACTION_SELECT_USER)
intent.setClass(activity, UserListSelectorActivity::class.java)
intent.putExtra(EXTRA_ACCOUNT_KEY, userList.account_key)
startActivityForResult(intent, REQUEST_SELECT_USER)
}
R.id.delete -> {
if (userList.user_key != userList.account_key) return false
DestroyUserListDialogFragment.show(fragmentManager, userList)
}
R.id.edit -> {
val args = Bundle()
args.putParcelable(EXTRA_ACCOUNT_KEY, userList.account_key)
args.putString(EXTRA_LIST_NAME, userList.name)
args.putString(EXTRA_DESCRIPTION, userList.description)
args.putBoolean(EXTRA_IS_PUBLIC, userList.is_public)
args.putString(EXTRA_LIST_ID, userList.id)
val f = EditUserListDialogFragment()
f.arguments = args
f.show(fragmentManager, "edit_user_list_details")
return true
}
R.id.follow -> {
if (userList.is_following) {
DestroyUserListSubscriptionDialogFragment.show(fragmentManager, userList)
} else {
twitter.createUserListSubscriptionAsync(userList.account_key, userList.id)
}
return true
}
R.id.open_with_account -> {
val intent = Intent(INTENT_ACTION_SELECT_ACCOUNT)
intent.setClass(activity, AccountSelectorActivity::class.java)
intent.putExtra(EXTRA_SINGLE_SELECTION, true)
startActivityForResult(intent, REQUEST_SELECT_ACCOUNT)
}
else -> {
if (item.intent != null) {
try {
startActivity(item.intent)
} catch (e: ActivityNotFoundException) {
Log.w(LOGTAG, e)
return false
}
}
}
}
return true
}
override fun onClick(view: View) {
when (view.id) {
R.id.errorContainer -> {
getUserListInfo(true)
}
R.id.profile_image -> {
val userList = this.userList ?: return
IntentUtils.openUserProfile(activity, userList.account_key,
userList.user_key, userList.user_screen_name, null,
preferences.getBoolean(KEY_NEW_DOCUMENT_API), null)
}
}
}
override fun onCreateLoader(id: Int, args: Bundle): Loader<SingleResponse<ParcelableUserList>> {
val accountKey = args.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
val userKey = args.getParcelable<UserKey>(EXTRA_USER_KEY)
val listId = args.getString(EXTRA_LIST_ID)
val listName = args.getString(EXTRA_LIST_NAME)
val screenName = args.getString(EXTRA_SCREEN_NAME)
val omitIntentExtra = args.getBoolean(EXTRA_OMIT_INTENT_EXTRA, true)
return ParcelableUserListLoader(activity, omitIntentExtra, arguments, accountKey, listId,
listName, userKey, screenName)
}
override fun onLoadFinished(loader: Loader<SingleResponse<ParcelableUserList>>,
data: SingleResponse<ParcelableUserList>?) {
if (data == null) return
if (activity == null) return
if (data.hasData()) {
val list = data.data
displayUserList(list)
} else if (data.hasException()) {
}
}
override fun onLoaderReset(loader: Loader<SingleResponse<ParcelableUserList>>) {
}
@Subscribe
fun onUserListUpdated(event: UserListUpdatedEvent) {
if (userList == null) return
if (TextUtils.equals(event.userList.id, userList!!.id)) {
getUserListInfo(true)
}
}
@Subscribe
fun onUserListSubscriptionChanged(event: UserListSubscriptionEvent) {
if (userList == null) return
if (TextUtils.equals(event.userList.id, userList!!.id)) {
getUserListInfo(true)
}
}
class EditUserListDialogFragment : BaseDialogFragment(), DialogInterface.OnClickListener {
private var mName: String? = null
private var mDescription: String? = null
private var mAccountKey: UserKey? = null
private var mListId: String? = null
private var mIsPublic: Boolean = false
override fun onClick(dialog: DialogInterface, which: Int) {
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
val alertDialog = dialog as AlertDialog
val editName = alertDialog.findViewById(R.id.name) as MaterialEditText?
val editDescription = alertDialog.findViewById(R.id.description) as MaterialEditText?
val editIsPublic = alertDialog.findViewById(R.id.is_public) as CheckBox?
assert(editName != null && editDescription != null && editIsPublic != null)
val name = ParseUtils.parseString(editName!!.text)
val description = ParseUtils.parseString(editDescription!!.text)
val isPublic = editIsPublic!!.isChecked
if (TextUtils.isEmpty(name)) return
val update = UserListUpdate()
update.setMode(if (isPublic) UserList.Mode.PUBLIC else UserList.Mode.PRIVATE)
update.setName(name)
update.setDescription(description)
twitterWrapper.updateUserListDetails(mAccountKey, mListId, update)
}
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val bundle = savedInstanceState ?: arguments
mAccountKey = bundle?.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
mListId = bundle?.getString(EXTRA_LIST_ID)
mName = bundle?.getString(EXTRA_LIST_NAME)
mDescription = bundle?.getString(EXTRA_DESCRIPTION)
mIsPublic = bundle == null || bundle.getBoolean(EXTRA_IS_PUBLIC, true)
val context = activity
val builder = AlertDialog.Builder(context)
builder.setView(R.layout.dialog_user_list_detail_editor)
builder.setTitle(R.string.user_list)
builder.setPositiveButton(android.R.string.ok, this)
builder.setNegativeButton(android.R.string.cancel, this)
val dialog = builder.create()
dialog.setOnShowListener { dialog ->
val alertDialog = dialog as AlertDialog
val editName = alertDialog.findViewById(R.id.name) as MaterialEditText?
val editDescription = alertDialog.findViewById(R.id.description) as MaterialEditText?
val editPublic = alertDialog.findViewById(R.id.is_public) as CheckBox?
assert(editName != null && editDescription != null && editPublic != null)
editName!!.addValidator(UserListNameValidator(getString(R.string.invalid_list_name)))
if (mName != null) {
editName.setText(mName)
}
if (mDescription != null) {
editDescription!!.setText(mDescription)
}
editPublic!!.isChecked = mIsPublic
}
return dialog
}
override fun onSaveInstanceState(outState: Bundle?) {
outState!!.putParcelable(EXTRA_ACCOUNT_KEY, mAccountKey)
outState.putString(EXTRA_LIST_ID, mListId)
outState.putString(EXTRA_LIST_NAME, mName)
outState.putString(EXTRA_DESCRIPTION, mDescription)
outState.putBoolean(EXTRA_IS_PUBLIC, mIsPublic)
super.onSaveInstanceState(outState)
}
}
internal class ParcelableUserListLoader(
context: Context,
private val omitIntentExtra: Boolean,
private val extras: Bundle?,
private val accountKey: UserKey,
private val listId: String?,
private val listName: String,
private val userKey: UserKey?,
private val screenName: String?
) : AsyncTaskLoader<SingleResponse<ParcelableUserList>>(context) {
override fun loadInBackground(): SingleResponse<ParcelableUserList> {
if (!omitIntentExtra && extras != null) {
val cache = extras.getParcelable<ParcelableUserList>(EXTRA_USER_LIST)
if (cache != null) return SingleResponse.getInstance(cache)
}
val twitter = MicroBlogAPIFactory.getInstance(context, accountKey,
true) ?: return SingleResponse.getInstance<ParcelableUserList>()
try {
val list: UserList
if (listId != null) {
list = twitter.showUserList(listId)
} else if (userKey != null) {
list = twitter.showUserList(listName, userKey.id)
} else if (screenName != null) {
list = twitter.showUserListByScrenName(listName, screenName)
} else
return SingleResponse.getInstance<ParcelableUserList>()
return SingleResponse.getInstance(ParcelableUserListUtils.from(list, accountKey))
} catch (e: MicroBlogException) {
return SingleResponse.getInstance<ParcelableUserList>(e)
}
}
public override fun onStartLoading() {
forceLoad()
}
}
}

View File

@ -1,666 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.Toast;
import com.rengwuxian.materialedittext.MaterialEditText;
import com.twitter.Validator;
import org.mariotaku.abstask.library.AbstractTask;
import org.mariotaku.abstask.library.TaskStarter;
import org.mariotaku.microblog.library.MicroBlog;
import org.mariotaku.microblog.library.MicroBlogException;
import org.mariotaku.microblog.library.twitter.model.ProfileUpdate;
import org.mariotaku.microblog.library.twitter.model.User;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.ColorPickerDialogActivity;
import org.mariotaku.twidere.activity.ThemedImagePickerActivity;
import org.mariotaku.twidere.fragment.iface.IBaseFragment;
import org.mariotaku.twidere.loader.ParcelableUserLoader;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.SingleResponse;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.util.ParcelableCredentialsUtils;
import org.mariotaku.twidere.model.util.ParcelableUserUtils;
import org.mariotaku.twidere.task.UpdateAccountInfoTask;
import org.mariotaku.twidere.task.UpdateProfileBackgroundImageTask;
import org.mariotaku.twidere.task.UpdateProfileBannerImageTask;
import org.mariotaku.twidere.util.AsyncTwitterWrapper.UpdateProfileImageTask;
import org.mariotaku.twidere.util.HtmlEscapeHelper;
import org.mariotaku.twidere.util.KeyboardShortcutsHandler;
import org.mariotaku.twidere.util.MicroBlogAPIFactory;
import org.mariotaku.twidere.util.ParseUtils;
import org.mariotaku.twidere.util.TwitterValidatorMETLengthChecker;
import org.mariotaku.twidere.util.TwitterWrapper;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.ForegroundColorView;
import org.mariotaku.twidere.view.iface.IExtendedView.OnSizeChangedListener;
import static android.text.TextUtils.isEmpty;
public class UserProfileEditorFragment extends BaseSupportFragment implements OnSizeChangedListener, TextWatcher,
OnClickListener, LoaderCallbacks<SingleResponse<ParcelableUser>>,
KeyboardShortcutsHandler.TakeAllKeyboardShortcut {
private static final int LOADER_ID_USER = 1;
private static final int REQUEST_UPLOAD_PROFILE_IMAGE = 1;
private static final int REQUEST_UPLOAD_PROFILE_BANNER_IMAGE = 2;
private static final int REQUEST_UPLOAD_PROFILE_BACKGROUND_IMAGE = 3;
private static final int REQUEST_PICK_LINK_COLOR = 11;
private static final int REQUEST_PICK_BACKGROUND_COLOR = 12;
private static final int RESULT_REMOVE_BANNER = 101;
private static final String UPDATE_PROFILE_DIALOG_FRAGMENT_TAG = "update_profile";
private AbstractTask<?, ?, UserProfileEditorFragment> mTask;
private ImageView mProfileImageView;
private ImageView mProfileBannerView;
private ImageView mProfileBackgroundView;
private MaterialEditText mEditName;
private MaterialEditText mEditDescription;
private MaterialEditText mEditLocation;
private MaterialEditText mEditUrl;
private View mProgressContainer, mEditProfileContent;
private View mEditProfileImage;
private View mEditProfileBanner;
private View mEditProfileBackground;
private View mSetLinkColor, mSetBackgroundColor;
private ForegroundColorView mLinkColor, mBackgroundColor;
private UserKey mAccountId;
private ParcelableUser mUser;
private boolean mUserInfoLoaderInitialized;
private boolean mGetUserInfoCalled;
@Override
public void beforeTextChanged(final CharSequence s, final int length, final int start, final int end) {
}
@Override
public void onTextChanged(final CharSequence s, final int length, final int start, final int end) {
updateDoneButton();
}
@Override
public void afterTextChanged(final Editable s) {
}
@Override
public void onClick(final View view) {
final ParcelableUser user = mUser;
if (user == null || (mTask != null && !mTask.isFinished()))
return;
switch (view.getId()) {
case R.id.profile_image: {
break;
}
case R.id.profileBanner: {
break;
}
case R.id.edit_profile_image: {
final Intent intent = ThemedImagePickerActivity.withThemed(getActivity()).aspectRatio(1, 1)
.maximumSize(512, 512).build();
startActivityForResult(intent, REQUEST_UPLOAD_PROFILE_IMAGE);
break;
}
case R.id.edit_profile_banner: {
final Intent intent = ThemedImagePickerActivity.withThemed(getActivity()).aspectRatio(3, 1)
.maximumSize(1500, 500).addEntry(getString(R.string.remove), "remove_banner", RESULT_REMOVE_BANNER).build();
startActivityForResult(intent, REQUEST_UPLOAD_PROFILE_BANNER_IMAGE);
break;
}
case R.id.edit_profile_background: {
final Intent intent = ThemedImagePickerActivity.withThemed(getActivity()).build();
startActivityForResult(intent, REQUEST_UPLOAD_PROFILE_BACKGROUND_IMAGE);
break;
}
case R.id.set_link_color: {
final Intent intent = new Intent(getActivity(), ColorPickerDialogActivity.class);
intent.putExtra(EXTRA_COLOR, user.link_color);
intent.putExtra(EXTRA_ALPHA_SLIDER, false);
startActivityForResult(intent, REQUEST_PICK_LINK_COLOR);
break;
}
case R.id.set_background_color: {
final Intent intent = new Intent(getActivity(), ColorPickerDialogActivity.class);
intent.putExtra(EXTRA_COLOR, user.background_color);
intent.putExtra(EXTRA_ALPHA_SLIDER, false);
startActivityForResult(intent, REQUEST_PICK_BACKGROUND_COLOR);
break;
}
}
}
@Override
public Loader<SingleResponse<ParcelableUser>> onCreateLoader(final int id, final Bundle args) {
mProgressContainer.setVisibility(View.VISIBLE);
mEditProfileContent.setVisibility(View.GONE);
return new ParcelableUserLoader(getActivity(), mAccountId, mAccountId, null, getArguments(),
false, false);
}
@Override
public void onLoadFinished(final Loader<SingleResponse<ParcelableUser>> loader,
final SingleResponse<ParcelableUser> data) {
if (data.getData() != null && data.getData().key != null) {
displayUser(data.getData());
} else if (mUser == null) {
}
}
@Override
public void onLoaderReset(final Loader<SingleResponse<ParcelableUser>> loader) {
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_profile_editor, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.save: {
final String name = ParseUtils.parseString(mEditName.getText());
final String url = ParseUtils.parseString(mEditUrl.getText());
final String location = ParseUtils.parseString(mEditLocation.getText());
final String description = ParseUtils.parseString(mEditDescription.getText());
final int linkColor = mLinkColor.getColor();
final int backgroundColor = mBackgroundColor.getColor();
mTask = new UpdateProfileTaskInternal(this, mAccountId, mUser, name, url, location,
description, linkColor, backgroundColor);
TaskStarter.execute(mTask);
return true;
}
}
return super.onOptionsItemSelected(item);
}
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
final Bundle args = getArguments();
final UserKey accountKey = args.getParcelable(EXTRA_ACCOUNT_KEY);
mAccountId = accountKey;
if (!Utils.isMyAccount(getActivity(), accountKey)) {
getActivity().finish();
return;
}
final TwitterValidatorMETLengthChecker lengthChecker = new TwitterValidatorMETLengthChecker(new Validator());
mEditName.addTextChangedListener(this);
mEditDescription.addTextChangedListener(this);
mEditLocation.addTextChangedListener(this);
mEditUrl.addTextChangedListener(this);
mEditDescription.setLengthChecker(lengthChecker);
mProfileImageView.setOnClickListener(this);
mProfileBannerView.setOnClickListener(this);
mProfileBackgroundView.setOnClickListener(this);
mEditProfileImage.setOnClickListener(this);
mEditProfileBanner.setOnClickListener(this);
mEditProfileBackground.setOnClickListener(this);
mSetLinkColor.setOnClickListener(this);
mSetBackgroundColor.setOnClickListener(this);
if (savedInstanceState != null && savedInstanceState.getParcelable(EXTRA_USER) != null) {
final ParcelableUser user = savedInstanceState.getParcelable(EXTRA_USER);
assert user != null;
displayUser(user);
mEditName.setText(savedInstanceState.getString(EXTRA_NAME, user.name));
mEditLocation.setText(savedInstanceState.getString(EXTRA_LOCATION, user.location));
mEditDescription.setText(savedInstanceState.getString(EXTRA_DESCRIPTION, ParcelableUserUtils.getExpandedDescription(user)));
mEditUrl.setText(savedInstanceState.getString(EXTRA_URL, user.url_expanded));
} else {
getUserInfo();
}
}
@Override
public void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(EXTRA_USER, mUser);
outState.putString(EXTRA_NAME, ParseUtils.parseString(mEditName.getText()));
outState.putString(EXTRA_DESCRIPTION, ParseUtils.parseString(mEditDescription.getText()));
outState.putString(EXTRA_LOCATION, ParseUtils.parseString(mEditLocation.getText()));
outState.putString(EXTRA_URL, ParseUtils.parseString(mEditUrl.getText()));
}
@Override
public void onSizeChanged(final View view, final int w, final int h, final int oldw, final int oldh) {
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_user_profile_editor, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mProgressContainer = view.findViewById(R.id.progress_container);
mEditProfileContent = view.findViewById(R.id.edit_profile_content);
mProfileImageView = (ImageView) view.findViewById(R.id.profile_image);
mProfileBannerView = (ImageView) view.findViewById(R.id.profileBanner);
mProfileBackgroundView = (ImageView) view.findViewById(R.id.profile_background);
mEditName = (MaterialEditText) view.findViewById(R.id.name);
mEditDescription = (MaterialEditText) view.findViewById(R.id.description);
mEditLocation = (MaterialEditText) view.findViewById(R.id.location);
mEditUrl = (MaterialEditText) view.findViewById(R.id.url);
mEditProfileImage = view.findViewById(R.id.edit_profile_image);
mEditProfileBanner = view.findViewById(R.id.edit_profile_banner);
mEditProfileBackground = view.findViewById(R.id.edit_profile_background);
mLinkColor = (ForegroundColorView) view.findViewById(R.id.link_color);
mBackgroundColor = (ForegroundColorView) view.findViewById(R.id.background_color);
mSetLinkColor = view.findViewById(R.id.set_link_color);
mSetBackgroundColor = view.findViewById(R.id.set_background_color);
}
@Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
if (resultCode == FragmentActivity.RESULT_CANCELED) return;
switch (requestCode) {
case REQUEST_UPLOAD_PROFILE_BANNER_IMAGE: {
if (mTask != null && !mTask.isFinished()) return;
if (resultCode == RESULT_REMOVE_BANNER) {
mTask = new RemoveProfileBannerTaskInternal(mAccountId);
} else {
mTask = new UpdateProfileBannerImageTaskInternal(getActivity(), mAccountId,
data.getData(), true);
}
break;
}
case REQUEST_UPLOAD_PROFILE_BACKGROUND_IMAGE: {
//TODO upload profile background
if (mTask != null && !mTask.isFinished()) return;
mTask = new UpdateProfileBackgroundImageTaskInternal(getActivity(), mAccountId,
data.getData(), false, true);
break;
}
case REQUEST_UPLOAD_PROFILE_IMAGE: {
if (mTask != null && !mTask.isFinished()) return;
mTask = new UpdateProfileImageTaskInternal(getActivity(), mAccountId,
data.getData(), true);
break;
}
case REQUEST_PICK_LINK_COLOR: {
if (resultCode == ColorPickerDialogActivity.RESULT_OK) {
mLinkColor.setColor(data.getIntExtra(EXTRA_COLOR, 0));
updateDoneButton();
}
break;
}
case REQUEST_PICK_BACKGROUND_COLOR: {
if (resultCode == ColorPickerDialogActivity.RESULT_OK) {
mBackgroundColor.setColor(data.getIntExtra(EXTRA_COLOR, 0));
updateDoneButton();
}
break;
}
}
}
private void displayUser(final ParcelableUser user) {
if (!mGetUserInfoCalled) return;
mGetUserInfoCalled = false;
mUser = user;
if (user != null) {
mProgressContainer.setVisibility(View.GONE);
mEditProfileContent.setVisibility(View.VISIBLE);
mEditName.setText(user.name);
mEditDescription.setText(ParcelableUserUtils.getExpandedDescription(user));
mEditLocation.setText(user.location);
mEditUrl.setText(isEmpty(user.url_expanded) ? user.url : user.url_expanded);
mediaLoader.displayProfileImage(mProfileImageView, user);
final int defWidth = getResources().getDisplayMetrics().widthPixels;
mediaLoader.displayProfileBanner(mProfileBannerView, user.profile_banner_url, defWidth);
mediaLoader.displayImage(mProfileBackgroundView, user.profile_background_url);
mLinkColor.setColor(user.link_color);
mBackgroundColor.setColor(user.background_color);
if (USER_TYPE_FANFOU_COM.equals(user.key.getHost())) {
mEditProfileBanner.setVisibility(View.GONE);
} else {
mEditProfileBanner.setVisibility(View.VISIBLE);
}
} else {
mProgressContainer.setVisibility(View.GONE);
mEditProfileContent.setVisibility(View.GONE);
}
updateDoneButton();
}
private void getUserInfo() {
if (getActivity() == null || isDetached()) return;
final LoaderManager lm = getLoaderManager();
lm.destroyLoader(LOADER_ID_USER);
mGetUserInfoCalled = true;
if (mUserInfoLoaderInitialized) {
lm.restartLoader(LOADER_ID_USER, null, this);
} else {
lm.initLoader(LOADER_ID_USER, null, this);
mUserInfoLoaderInitialized = true;
}
}
@Override
public void onResume() {
super.onResume();
if (mTask != null && !mTask.isFinished()) {
TaskStarter.execute(mTask);
}
}
private void dismissDialogFragment(final String tag) {
executeAfterFragmentResumed(new Action() {
@Override
public void execute(IBaseFragment fragment) {
final FragmentManager fm = getChildFragmentManager();
final Fragment f = fm.findFragmentByTag(tag);
if (f instanceof DialogFragment) {
((DialogFragment) f).dismiss();
}
}
});
}
private void setUpdateState(final boolean start) {
if (!start) {
dismissDialogFragment(UPDATE_PROFILE_DIALOG_FRAGMENT_TAG);
return;
}
executeAfterFragmentResumed(new Action() {
@Override
public void execute(IBaseFragment fragment) {
final FragmentManager fm = getChildFragmentManager();
ProgressDialogFragment df = new ProgressDialogFragment();
df.show(fm, UPDATE_PROFILE_DIALOG_FRAGMENT_TAG);
df.setCancelable(false);
}
});
}
private static boolean stringEquals(final CharSequence str1, final CharSequence str2) {
if (str1 == null || str2 == null) return str1 == str2;
if (str1.length() != str2.length()) return false;
for (int i = 0, j = str1.length(); i < j; i++) {
if (str1.charAt(i) != str2.charAt(i)) return false;
}
return true;
}
private void updateDoneButton() {
}
static class UpdateProfileTaskInternal extends AbstractTask<Object, SingleResponse<ParcelableUser>,
UserProfileEditorFragment> {
private static final String DIALOG_FRAGMENT_TAG = "updating_user_profile";
private final FragmentActivity mActivity;
// Data fields
private final UserKey mAccountKey;
private final ParcelableUser mOriginal;
private final String mName;
private final String mUrl;
private final String mLocation;
private final String mDescription;
private final int mLinkColor;
private final int mBackgroundColor;
public UpdateProfileTaskInternal(final UserProfileEditorFragment fragment,
final UserKey accountKey, final ParcelableUser original,
final String name, final String url, final String location,
final String description, final int linkColor,
final int backgroundColor) {
mActivity = fragment.getActivity();
mAccountKey = accountKey;
mOriginal = original;
mName = name;
mUrl = url;
mLocation = location;
mDescription = description;
mLinkColor = linkColor;
mBackgroundColor = backgroundColor;
}
@Override
protected SingleResponse<ParcelableUser> doLongOperation(final Object params) {
final ParcelableCredentials credentials = ParcelableCredentialsUtils.getCredentials(mActivity, mAccountKey);
if (credentials == null) return SingleResponse.getInstance();
final MicroBlog twitter = MicroBlogAPIFactory.getInstance(mActivity, credentials,
true, true);
if (twitter == null) return SingleResponse.getInstance();
try {
User user = null;
if (isProfileChanged()) {
final ProfileUpdate profileUpdate = new ProfileUpdate();
profileUpdate.name(HtmlEscapeHelper.escapeBasic(mName));
profileUpdate.location(HtmlEscapeHelper.escapeBasic(mLocation));
profileUpdate.description(HtmlEscapeHelper.escapeBasic(mDescription));
profileUpdate.url(mUrl);
profileUpdate.linkColor(mLinkColor);
profileUpdate.backgroundColor(mBackgroundColor);
user = twitter.updateProfile(profileUpdate);
}
if (user == null) {
// User profile unchanged
return SingleResponse.getInstance();
}
final SingleResponse<ParcelableUser> response = SingleResponse.getInstance(
ParcelableUserUtils.fromUser(user, mAccountKey));
response.getExtras().putParcelable(EXTRA_ACCOUNT, credentials);
return response;
} catch (MicroBlogException e) {
return SingleResponse.getInstance(e);
}
}
private boolean isProfileChanged() {
final ParcelableUser orig = mOriginal;
if (orig == null) return true;
if (mLinkColor != orig.link_color) return true;
if (mBackgroundColor != orig.background_color) return true;
if (!stringEquals(mName, orig.name)) return true;
if (!stringEquals(mDescription, ParcelableUserUtils.getExpandedDescription(orig)))
return true;
if (!stringEquals(mLocation, orig.location)) return true;
if (!stringEquals(mUrl, isEmpty(orig.url_expanded) ? orig.url : orig.url_expanded))
return true;
return false;
}
@Override
protected void afterExecute(UserProfileEditorFragment callback, SingleResponse<ParcelableUser> result) {
super.afterExecute(callback, result);
if (result.hasData()) {
final ParcelableAccount account = result.getExtras().getParcelable(EXTRA_ACCOUNT);
if (account != null) {
final UpdateAccountInfoTask task = new UpdateAccountInfoTask(mActivity);
task.setParams(Pair.create(account, result.getData()));
TaskStarter.execute(task);
}
}
callback.executeAfterFragmentResumed(new Action() {
@Override
public void execute(IBaseFragment fragment) {
final Fragment f = ((UserProfileEditorFragment) fragment).getFragmentManager().findFragmentByTag(DIALOG_FRAGMENT_TAG);
if (f instanceof DialogFragment) {
((DialogFragment) f).dismissAllowingStateLoss();
}
f.getActivity().finish();
}
});
}
@Override
protected void beforeExecute() {
super.beforeExecute();
final UserProfileEditorFragment callback = getCallback();
if (callback != null) {
callback.executeAfterFragmentResumed(new Action() {
@Override
public void execute(IBaseFragment fragment) {
final DialogFragment df = ProgressDialogFragment.show(((UserProfileEditorFragment) fragment).getActivity(), DIALOG_FRAGMENT_TAG);
df.setCancelable(false);
}
});
}
}
}
class RemoveProfileBannerTaskInternal extends AbstractTask<Object, SingleResponse<Boolean>, UserProfileEditorFragment> {
private final UserKey mAccountKey;
RemoveProfileBannerTaskInternal(final UserKey accountKey) {
this.mAccountKey = accountKey;
}
@Override
protected SingleResponse<Boolean> doLongOperation(final Object params) {
return TwitterWrapper.deleteProfileBannerImage(getActivity(), mAccountKey);
}
@Override
protected void afterExecute(UserProfileEditorFragment callback, final SingleResponse<Boolean> result) {
super.afterExecute(callback, result);
if (result.getData() != null && result.getData()) {
getUserInfo();
Toast.makeText(getActivity(), R.string.profile_banner_image_updated, Toast.LENGTH_SHORT).show();
} else {
Utils.showErrorMessage(getActivity(), R.string.action_removing_profile_banner_image,
result.getException(), true);
}
setUpdateState(false);
}
@Override
protected void beforeExecute() {
super.beforeExecute();
setUpdateState(true);
}
}
private class UpdateProfileBannerImageTaskInternal extends UpdateProfileBannerImageTask<UserProfileEditorFragment> {
public UpdateProfileBannerImageTaskInternal(final Context context, final UserKey accountKey,
final Uri imageUri, final boolean deleteImage) {
super(context, accountKey, imageUri, deleteImage);
}
@Override
protected void afterExecute(UserProfileEditorFragment callback, final SingleResponse<ParcelableUser> result) {
super.afterExecute(callback, result);
setUpdateState(false);
getUserInfo();
}
@Override
protected void beforeExecute() {
super.beforeExecute();
setUpdateState(true);
}
}
private class UpdateProfileBackgroundImageTaskInternal extends UpdateProfileBackgroundImageTask<UserProfileEditorFragment> {
public UpdateProfileBackgroundImageTaskInternal(final Context context, final UserKey accountKey,
final Uri imageUri, final boolean tile,
final boolean deleteImage) {
super(context, accountKey, imageUri, tile, deleteImage);
}
@Override
protected void afterExecute(UserProfileEditorFragment callback, final SingleResponse<ParcelableUser> result) {
super.afterExecute(callback, result);
setUpdateState(false);
getUserInfo();
}
@Override
protected void beforeExecute() {
super.beforeExecute();
setUpdateState(true);
}
}
private class UpdateProfileImageTaskInternal extends UpdateProfileImageTask<UserProfileEditorFragment> {
public UpdateProfileImageTaskInternal(final Context context, final UserKey accountKey,
final Uri imageUri, final boolean deleteImage) {
super(context, accountKey, imageUri, deleteImage);
}
@Override
protected void afterExecute(UserProfileEditorFragment callback, SingleResponse<ParcelableUser> result) {
super.afterExecute(callback, result);
if (result != null && result.getData() != null) {
displayUser(result.getData());
}
setUpdateState(false);
}
@Override
protected void beforeExecute() {
super.beforeExecute();
setUpdateState(true);
}
}
}

View File

@ -0,0 +1,526 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.Parcelable
import android.support.v4.app.DialogFragment
import android.support.v4.app.FragmentActivity
import android.support.v4.app.LoaderManager.LoaderCallbacks
import android.support.v4.content.Loader
import android.text.Editable
import android.text.TextUtils.isEmpty
import android.text.TextWatcher
import android.view.*
import android.view.View.OnClickListener
import android.widget.Toast
import com.twitter.Validator
import kotlinx.android.synthetic.main.fragment_user_profile_editor.*
import org.mariotaku.abstask.library.AbstractTask
import org.mariotaku.abstask.library.TaskStarter
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.microblog.library.twitter.model.ProfileUpdate
import org.mariotaku.microblog.library.twitter.model.User
import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.*
import org.mariotaku.twidere.activity.ColorPickerDialogActivity
import org.mariotaku.twidere.activity.ThemedImagePickerActivity
import org.mariotaku.twidere.loader.ParcelableUserLoader
import org.mariotaku.twidere.model.ParcelableAccount
import org.mariotaku.twidere.model.ParcelableUser
import org.mariotaku.twidere.model.SingleResponse
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.util.ParcelableCredentialsUtils
import org.mariotaku.twidere.model.util.ParcelableUserUtils
import org.mariotaku.twidere.task.UpdateAccountInfoTask
import org.mariotaku.twidere.task.UpdateProfileBackgroundImageTask
import org.mariotaku.twidere.task.UpdateProfileBannerImageTask
import org.mariotaku.twidere.util.*
import org.mariotaku.twidere.util.AsyncTwitterWrapper.UpdateProfileImageTask
import org.mariotaku.twidere.view.iface.IExtendedView.OnSizeChangedListener
class UserProfileEditorFragment : BaseSupportFragment(), OnSizeChangedListener, TextWatcher, OnClickListener, LoaderCallbacks<SingleResponse<ParcelableUser>>, KeyboardShortcutsHandler.TakeAllKeyboardShortcut {
private var task: AbstractTask<*, *, UserProfileEditorFragment>? = null
private val accountKey: UserKey
get() = arguments.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
private var user: ParcelableUser? = null
private var userInfoLoaderInitialized: Boolean = false
private var getUserInfoCalled: Boolean = false
override fun beforeTextChanged(s: CharSequence, length: Int, start: Int, end: Int) {
}
override fun onTextChanged(s: CharSequence, length: Int, start: Int, end: Int) {
updateDoneButton()
}
override fun afterTextChanged(s: Editable) {
}
override fun onClick(view: View) {
val user = user
if (user == null || task != null && !task!!.isFinished)
return
when (view.id) {
R.id.profile_image -> {
}
R.id.profileBanner -> {
}
R.id.editProfileImage -> {
val intent = ThemedImagePickerActivity.withThemed(activity).aspectRatio(1, 1).maximumSize(512, 512).build()
startActivityForResult(intent, REQUEST_UPLOAD_PROFILE_IMAGE)
}
R.id.editProfileBanner -> {
val intent = ThemedImagePickerActivity.withThemed(activity).aspectRatio(3, 1).maximumSize(1500, 500).addEntry(getString(R.string.remove), "remove_banner", RESULT_REMOVE_BANNER).build()
startActivityForResult(intent, REQUEST_UPLOAD_PROFILE_BANNER_IMAGE)
}
R.id.editProfileBackground -> {
val intent = ThemedImagePickerActivity.withThemed(activity).build()
startActivityForResult(intent, REQUEST_UPLOAD_PROFILE_BACKGROUND_IMAGE)
}
R.id.setLinkColor -> {
val intent = Intent(activity, ColorPickerDialogActivity::class.java)
intent.putExtra(EXTRA_COLOR, user.link_color)
intent.putExtra(EXTRA_ALPHA_SLIDER, false)
startActivityForResult(intent, REQUEST_PICK_LINK_COLOR)
}
R.id.setBackgroundColor -> {
val intent = Intent(activity, ColorPickerDialogActivity::class.java)
intent.putExtra(EXTRA_COLOR, user.background_color)
intent.putExtra(EXTRA_ALPHA_SLIDER, false)
startActivityForResult(intent, REQUEST_PICK_BACKGROUND_COLOR)
}
}
}
override fun onCreateLoader(id: Int, args: Bundle): Loader<SingleResponse<ParcelableUser>> {
progressContainer!!.visibility = View.VISIBLE
editProfileContent!!.visibility = View.GONE
return ParcelableUserLoader(activity, accountKey, accountKey, null, arguments,
false, false)
}
override fun onLoadFinished(loader: Loader<SingleResponse<ParcelableUser>>,
data: SingleResponse<ParcelableUser>) {
if (data.data != null && data.data.key != null) {
displayUser(data.data)
} else if (user == null) {
}
}
override fun onLoaderReset(loader: Loader<SingleResponse<ParcelableUser>>) {
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
inflater!!.inflate(R.menu.menu_profile_editor, menu)
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item!!.itemId) {
R.id.save -> {
val name = ParseUtils.parseString(editName!!.text)
val url = ParseUtils.parseString(editUrl.text)
val location = ParseUtils.parseString(editLocation!!.text)
val description = ParseUtils.parseString(editDescription!!.text)
val linkColor = linkColor!!.color
val backgroundColor = backgroundColor!!.color
task = UpdateProfileTaskInternal(this, accountKey, user, name, url, location,
description, linkColor, backgroundColor)
TaskStarter.execute(task)
return true
}
}
return super.onOptionsItemSelected(item)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setHasOptionsMenu(true)
if (!Utils.isMyAccount(activity, accountKey)) {
activity.finish()
return
}
val lengthChecker = TwitterValidatorMETLengthChecker(Validator())
editName!!.addTextChangedListener(this)
editDescription!!.addTextChangedListener(this)
editLocation!!.addTextChangedListener(this)
editUrl!!.addTextChangedListener(this)
editDescription!!.setLengthChecker(lengthChecker)
profileImage!!.setOnClickListener(this)
profileBanner!!.setOnClickListener(this)
profileBackground!!.setOnClickListener(this)
editProfileImage!!.setOnClickListener(this)
editProfileBanner!!.setOnClickListener(this)
editProfileBackground!!.setOnClickListener(this)
setLinkColor!!.setOnClickListener(this)
setBackgroundColor!!.setOnClickListener(this)
if (savedInstanceState != null && savedInstanceState.getParcelable<Parcelable>(EXTRA_USER) != null) {
val user = savedInstanceState.getParcelable<ParcelableUser>(EXTRA_USER)!!
displayUser(user)
editName!!.setText(savedInstanceState.getString(EXTRA_NAME, user.name))
editLocation!!.setText(savedInstanceState.getString(EXTRA_LOCATION, user.location))
editDescription!!.setText(savedInstanceState.getString(EXTRA_DESCRIPTION, ParcelableUserUtils.getExpandedDescription(user)))
editUrl!!.setText(savedInstanceState.getString(EXTRA_URL, user.url_expanded))
} else {
getUserInfo()
}
}
override fun onSaveInstanceState(outState: Bundle?) {
super.onSaveInstanceState(outState)
outState!!.putParcelable(EXTRA_USER, user)
outState.putString(EXTRA_NAME, ParseUtils.parseString(editName!!.text))
outState.putString(EXTRA_DESCRIPTION, ParseUtils.parseString(editDescription!!.text))
outState.putString(EXTRA_LOCATION, ParseUtils.parseString(editLocation!!.text))
outState.putString(EXTRA_URL, ParseUtils.parseString(editUrl!!.text))
}
override fun onSizeChanged(view: View, w: Int, h: Int, oldw: Int, oldh: Int) {
}
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater!!.inflate(R.layout.fragment_user_profile_editor, container, false)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == FragmentActivity.RESULT_CANCELED) return
when (requestCode) {
REQUEST_UPLOAD_PROFILE_BANNER_IMAGE -> {
if (task != null && !task!!.isFinished) return
if (resultCode == RESULT_REMOVE_BANNER) {
task = RemoveProfileBannerTaskInternal(accountKey)
} else {
task = UpdateProfileBannerImageTaskInternal(activity, accountKey,
data!!.data, true)
}
}
REQUEST_UPLOAD_PROFILE_BACKGROUND_IMAGE -> {
//TODO upload profile background
if (task != null && !task!!.isFinished) return
task = UpdateProfileBackgroundImageTaskInternal(activity, accountKey,
data!!.data, false, true)
}
REQUEST_UPLOAD_PROFILE_IMAGE -> {
if (task != null && !task!!.isFinished) return
task = UpdateProfileImageTaskInternal(activity, accountKey,
data!!.data, true)
}
REQUEST_PICK_LINK_COLOR -> {
if (resultCode == ColorPickerDialogActivity.RESULT_OK) {
linkColor!!.color = data!!.getIntExtra(EXTRA_COLOR, 0)
updateDoneButton()
}
}
REQUEST_PICK_BACKGROUND_COLOR -> {
if (resultCode == ColorPickerDialogActivity.RESULT_OK) {
backgroundColor!!.color = data!!.getIntExtra(EXTRA_COLOR, 0)
updateDoneButton()
}
}
}
}
private fun displayUser(user: ParcelableUser?) {
if (!getUserInfoCalled) return
getUserInfoCalled = false
this.user = user
if (user != null) {
progressContainer!!.visibility = View.GONE
editProfileContent!!.visibility = View.VISIBLE
editName.setText(user.name)
editDescription.setText(ParcelableUserUtils.getExpandedDescription(user))
editLocation.setText(user.location)
editUrl.setText(if (isEmpty(user.url_expanded)) user.url else user.url_expanded)
mediaLoader.displayProfileImage(profileImage, user)
val defWidth = resources.displayMetrics.widthPixels
mediaLoader.displayProfileBanner(profileBanner, user.profile_banner_url, defWidth)
mediaLoader.displayImage(profileBackground, user.profile_background_url)
linkColor!!.color = user.link_color
backgroundColor!!.color = user.background_color
if (USER_TYPE_FANFOU_COM == user.key.host) {
editProfileBanner!!.visibility = View.GONE
} else {
editProfileBanner!!.visibility = View.VISIBLE
}
} else {
progressContainer!!.visibility = View.GONE
editProfileContent!!.visibility = View.GONE
}
updateDoneButton()
}
private fun getUserInfo() {
if (activity == null || isDetached) return
val lm = loaderManager
lm.destroyLoader(LOADER_ID_USER)
getUserInfoCalled = true
if (userInfoLoaderInitialized) {
lm.restartLoader(LOADER_ID_USER, null, this)
} else {
lm.initLoader(LOADER_ID_USER, null, this)
userInfoLoaderInitialized = true
}
}
override fun onResume() {
super.onResume()
if (task != null && !task!!.isFinished) {
TaskStarter.execute(task)
}
}
private fun dismissDialogFragment(tag: String) {
executeAfterFragmentResumed {
val fm = childFragmentManager
val f = fm.findFragmentByTag(tag)
if (f is DialogFragment) {
f.dismiss()
}
}
}
private fun setUpdateState(start: Boolean) {
if (!start) {
dismissDialogFragment(UPDATE_PROFILE_DIALOG_FRAGMENT_TAG)
return
}
executeAfterFragmentResumed {
val fm = childFragmentManager
val df = ProgressDialogFragment()
df.show(fm, UPDATE_PROFILE_DIALOG_FRAGMENT_TAG)
df.isCancelable = false
}
}
private fun updateDoneButton() {
}
internal class UpdateProfileTaskInternal(
fragment: UserProfileEditorFragment,
private val accountKey: UserKey,
private val original: ParcelableUser?,
private val name: String,
private val url: String,
private val location: String,
private val description: String,
private val linkColor: Int,
private val backgroundColor: Int
) : AbstractTask<Any, SingleResponse<ParcelableUser>, UserProfileEditorFragment>() {
private val activity: FragmentActivity
init {
activity = fragment.activity
}
override fun doLongOperation(params: Any): SingleResponse<ParcelableUser> {
val credentials = ParcelableCredentialsUtils.getCredentials(activity, accountKey) ?: return SingleResponse.getInstance<ParcelableUser>()
val twitter = MicroBlogAPIFactory.getInstance(activity, credentials,
true, true) ?: return SingleResponse.getInstance<ParcelableUser>()
try {
var user: User? = null
if (isProfileChanged) {
val profileUpdate = ProfileUpdate()
profileUpdate.name(HtmlEscapeHelper.escapeBasic(name))
profileUpdate.location(HtmlEscapeHelper.escapeBasic(location))
profileUpdate.description(HtmlEscapeHelper.escapeBasic(description))
profileUpdate.url(url)
profileUpdate.linkColor(linkColor)
profileUpdate.backgroundColor(backgroundColor)
user = twitter.updateProfile(profileUpdate)
}
if (user == null) {
// User profile unchanged
return SingleResponse.getInstance<ParcelableUser>()
}
val response = SingleResponse.getInstance(
ParcelableUserUtils.fromUser(user, accountKey))
response.extras.putParcelable(EXTRA_ACCOUNT, credentials)
return response
} catch (e: MicroBlogException) {
return SingleResponse.getInstance<ParcelableUser>(e)
}
}
private val isProfileChanged: Boolean
get() {
val orig = original ?: return true
if (linkColor != orig.link_color) return true
if (backgroundColor != orig.background_color) return true
if (!stringEquals(name, orig.name)) return true
if (!stringEquals(description, ParcelableUserUtils.getExpandedDescription(orig)))
return true
if (!stringEquals(location, orig.location)) return true
if (!stringEquals(url, if (isEmpty(orig.url_expanded)) orig.url else orig.url_expanded))
return true
return false
}
override fun afterExecute(callback: UserProfileEditorFragment?, result: SingleResponse<ParcelableUser>?) {
super.afterExecute(callback, result)
if (result!!.hasData()) {
val account = result.extras.getParcelable<ParcelableAccount>(EXTRA_ACCOUNT)
if (account != null) {
val task = UpdateAccountInfoTask(activity)
task.setParams(Pair(account, result.data))
TaskStarter.execute(task)
}
}
callback!!.executeAfterFragmentResumed { fragment ->
val f = (fragment as UserProfileEditorFragment).fragmentManager.findFragmentByTag(DIALOG_FRAGMENT_TAG)
if (f is DialogFragment) {
f.dismissAllowingStateLoss()
}
f.activity.finish()
}
}
override fun beforeExecute() {
super.beforeExecute()
val callback = callback
callback?.executeAfterFragmentResumed { fragment ->
val df = ProgressDialogFragment.show((fragment as UserProfileEditorFragment).activity, DIALOG_FRAGMENT_TAG)
df.isCancelable = false
}
}
companion object {
private val DIALOG_FRAGMENT_TAG = "updating_user_profile"
}
}
internal inner class RemoveProfileBannerTaskInternal(private val accountKey: UserKey) : AbstractTask<Any, SingleResponse<Boolean>, UserProfileEditorFragment>() {
override fun doLongOperation(params: Any): SingleResponse<Boolean> {
return TwitterWrapper.deleteProfileBannerImage(activity, accountKey)
}
override fun afterExecute(callback: UserProfileEditorFragment?, result: SingleResponse<Boolean>?) {
super.afterExecute(callback, result)
if (result!!.data != null && result.data) {
getUserInfo()
Toast.makeText(activity, R.string.profile_banner_image_updated, Toast.LENGTH_SHORT).show()
} else {
Utils.showErrorMessage(activity, R.string.action_removing_profile_banner_image,
result.exception, true)
}
setUpdateState(false)
}
override fun beforeExecute() {
super.beforeExecute()
setUpdateState(true)
}
}
private inner class UpdateProfileBannerImageTaskInternal(context: Context, accountKey: UserKey,
imageUri: Uri, deleteImage: Boolean) : UpdateProfileBannerImageTask<UserProfileEditorFragment>(context, accountKey, imageUri, deleteImage) {
override fun afterExecute(callback: UserProfileEditorFragment?, result: SingleResponse<ParcelableUser>?) {
super.afterExecute(callback, result)
setUpdateState(false)
getUserInfo()
}
override fun beforeExecute() {
super.beforeExecute()
setUpdateState(true)
}
}
private inner class UpdateProfileBackgroundImageTaskInternal(context: Context, accountKey: UserKey,
imageUri: Uri, tile: Boolean,
deleteImage: Boolean) : UpdateProfileBackgroundImageTask<UserProfileEditorFragment>(context, accountKey, imageUri, tile, deleteImage) {
override fun afterExecute(callback: UserProfileEditorFragment?, result: SingleResponse<ParcelableUser>?) {
super.afterExecute(callback, result)
setUpdateState(false)
getUserInfo()
}
override fun beforeExecute() {
super.beforeExecute()
setUpdateState(true)
}
}
private inner class UpdateProfileImageTaskInternal(context: Context, accountKey: UserKey,
imageUri: Uri, deleteImage: Boolean) : UpdateProfileImageTask<UserProfileEditorFragment>(context, accountKey, imageUri, deleteImage) {
override fun afterExecute(callback: UserProfileEditorFragment?, result: SingleResponse<ParcelableUser>?) {
super.afterExecute(callback, result)
if (result != null && result.data != null) {
displayUser(result.data)
}
setUpdateState(false)
}
override fun beforeExecute() {
super.beforeExecute()
setUpdateState(true)
}
}
companion object {
private val LOADER_ID_USER = 1
private val REQUEST_UPLOAD_PROFILE_IMAGE = 1
private val REQUEST_UPLOAD_PROFILE_BANNER_IMAGE = 2
private val REQUEST_UPLOAD_PROFILE_BACKGROUND_IMAGE = 3
private val REQUEST_PICK_LINK_COLOR = 11
private val REQUEST_PICK_BACKGROUND_COLOR = 12
private val RESULT_REMOVE_BANNER = 101
private val UPDATE_PROFILE_DIALOG_FRAGMENT_TAG = "update_profile"
private fun stringEquals(str1: CharSequence?, str2: CharSequence?): Boolean {
if (str1 == null || str2 == null) return str1 === str2
if (str1.length != str2.length) return false
var i = 0
val j = str1.length
while (i < j) {
if (str1[i] != str2[i]) return false
i++
}
return true
}
}
}

View File

@ -180,7 +180,7 @@ public abstract class MicroBlogAPIStatusesLoader extends ParcelableStatusesLoade
data.add(item);
}
final SQLiteDatabase db = TwidereApplication.getInstance(context).getSQLiteDatabase();
final SQLiteDatabase db = TwidereApplication.Companion.getInstance(context).getSqLiteDatabase();
final ParcelableStatus[] array = data.toArray(new ParcelableStatus[data.size()]);
for (int i = 0, size = array.length; i < size; i++) {
final ParcelableStatus status = array[i];

View File

@ -1,212 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.loader;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.content.AsyncTaskLoader;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import org.mariotaku.abstask.library.TaskStarter;
import org.mariotaku.microblog.library.MicroBlog;
import org.mariotaku.microblog.library.MicroBlogException;
import org.mariotaku.microblog.library.twitter.model.User;
import org.mariotaku.sqliteqb.library.Columns;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.annotation.Referral;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.ParcelableUserCursorIndices;
import org.mariotaku.twidere.model.ParcelableUserValuesCreator;
import org.mariotaku.twidere.model.SingleResponse;
import org.mariotaku.twidere.model.UserKey;
import org.mariotaku.twidere.model.util.ParcelableCredentialsUtils;
import org.mariotaku.twidere.model.util.ParcelableUserUtils;
import org.mariotaku.twidere.model.util.UserKeyUtils;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers;
import org.mariotaku.twidere.task.UpdateAccountInfoTask;
import org.mariotaku.twidere.util.MicroBlogAPIFactory;
import org.mariotaku.twidere.util.TwitterWrapper;
import org.mariotaku.twidere.util.UserColorNameManager;
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper;
import javax.inject.Inject;
import static org.mariotaku.twidere.util.ContentValuesCreator.createCachedUser;
public final class ParcelableUserLoader extends AsyncTaskLoader<SingleResponse<ParcelableUser>>
implements Constants {
private final boolean mOmitIntentExtra, mLoadFromCache;
private final Bundle mExtras;
private final UserKey mAccountKey;
private final UserKey mUserKey;
private final String mScreenName;
@Inject
UserColorNameManager mUserColorNameManager;
public ParcelableUserLoader(final Context context, final UserKey accountKey,
final UserKey userKey, final String screenName,
final Bundle extras, final boolean omitIntentExtra,
final boolean loadFromCache) {
super(context);
GeneralComponentHelper.build(context).inject(this);
this.mOmitIntentExtra = omitIntentExtra;
this.mLoadFromCache = loadFromCache;
this.mExtras = extras;
this.mAccountKey = accountKey;
this.mUserKey = userKey;
this.mScreenName = screenName;
}
@Override
public SingleResponse<ParcelableUser> loadInBackground() {
final Context context = getContext();
final ContentResolver resolver = context.getContentResolver();
final UserKey accountKey = mAccountKey;
ParcelableCredentials credentials = null;
for (ParcelableCredentials cred : ParcelableCredentialsUtils.getCredentialses(context)) {
if (cred.account_key.equals(accountKey)) {
credentials = cred;
break;
} else if (cred.account_user != null && cred.account_user.account_key.equals(accountKey)) {
credentials = cred;
break;
}
}
if (credentials == null) return SingleResponse.getInstance();
if (!mOmitIntentExtra && mExtras != null) {
final ParcelableUser user = mExtras.getParcelable(EXTRA_USER);
if (user != null) {
final ContentValues values = ParcelableUserValuesCreator.create(user);
resolver.insert(CachedUsers.CONTENT_URI, values);
ParcelableUserUtils.updateExtraInformation(user, credentials, mUserColorNameManager);
return SingleResponse.getInstance(user);
}
}
final MicroBlog twitter = MicroBlogAPIFactory.getInstance(context, credentials, true, true);
if (twitter == null) return SingleResponse.getInstance();
if (mLoadFromCache) {
final Expression where;
final String[] whereArgs;
if (mUserKey != null) {
where = Expression.equalsArgs(CachedUsers.USER_KEY);
whereArgs = new String[]{mUserKey.toString()};
} else if (mScreenName != null) {
final String host = mAccountKey.getHost();
if (host != null) {
where = Expression.and(
Expression.likeRaw(new Columns.Column(CachedUsers.USER_KEY), "'%@'||?"),
Expression.equalsArgs(CachedUsers.SCREEN_NAME)
);
whereArgs = new String[]{host, mScreenName};
} else {
where = Expression.equalsArgs(CachedUsers.SCREEN_NAME);
whereArgs = new String[]{mScreenName};
}
} else {
return SingleResponse.getInstance();
}
final Cursor cur = resolver.query(CachedUsers.CONTENT_URI, CachedUsers.COLUMNS,
where.getSQL(), whereArgs, null);
if (cur != null) {
try {
cur.moveToFirst();
final ParcelableUserCursorIndices indices = new ParcelableUserCursorIndices(cur);
while (!cur.isAfterLast()) {
final ParcelableUser user = indices.newObject(cur);
if (TextUtils.equals(UserKeyUtils.getUserHost(user), user.key.getHost())) {
user.account_key = accountKey;
user.account_color = credentials.color;
return SingleResponse.getInstance(user);
}
cur.moveToNext();
}
} finally {
cur.close();
}
}
}
try {
final User twitterUser;
if (mExtras != null && Referral.SELF_PROFILE.equals(mExtras.getString(EXTRA_REFERRAL))) {
twitterUser = twitter.verifyCredentials();
} else {
String profileUrl = null;
if (mExtras != null) {
profileUrl = mExtras.getString(EXTRA_PROFILE_URL);
}
if (MicroBlogAPIFactory.isStatusNetCredentials(credentials) && mUserKey != null &&
profileUrl != null && !TextUtils.equals(credentials.account_key.getHost(),
mUserKey.getHost())) {
twitterUser = twitter.showExternalProfile(profileUrl);
} else {
final String id = mUserKey != null ? mUserKey.getId() : null;
twitterUser = TwitterWrapper.tryShowUser(twitter, id, mScreenName,
credentials.account_type);
}
}
final ContentValues cachedUserValues = createCachedUser(twitterUser);
resolver.insert(CachedUsers.CONTENT_URI, cachedUserValues);
final ParcelableUser user = ParcelableUserUtils.fromUser(twitterUser, accountKey);
ParcelableUserUtils.updateExtraInformation(user, credentials, mUserColorNameManager);
final SingleResponse<ParcelableUser> response = SingleResponse.getInstance(user);
response.getExtras().putParcelable(EXTRA_ACCOUNT, credentials);
return response;
} catch (final MicroBlogException e) {
Log.w(LOGTAG, e);
return SingleResponse.getInstance(e);
}
}
@Override
protected void onStartLoading() {
if (!mOmitIntentExtra && mExtras != null) {
final ParcelableUser user = mExtras.getParcelable(EXTRA_USER);
if (user != null) {
deliverResult(SingleResponse.getInstance(user));
}
}
forceLoad();
}
@Override
public void deliverResult(SingleResponse<ParcelableUser> data) {
super.deliverResult(data);
if (data.hasData()) {
final ParcelableUser user = data.getData();
if (user.is_cache) return;
final ParcelableAccount account = data.getExtras().getParcelable(EXTRA_ACCOUNT);
if (account != null) {
final UpdateAccountInfoTask task = new UpdateAccountInfoTask(getContext());
task.setParams(Pair.create(account, user));
TaskStarter.execute(task);
}
}
}
}

View File

@ -0,0 +1,186 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.loader
import android.content.Context
import android.os.Bundle
import android.support.v4.content.AsyncTaskLoader
import android.text.TextUtils
import android.util.Log
import org.mariotaku.abstask.library.TaskStarter
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.microblog.library.twitter.model.User
import org.mariotaku.sqliteqb.library.Columns
import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.twidere.Constants
import org.mariotaku.twidere.TwidereConstants.*
import org.mariotaku.twidere.annotation.Referral
import org.mariotaku.twidere.model.*
import org.mariotaku.twidere.model.util.ParcelableCredentialsUtils
import org.mariotaku.twidere.model.util.ParcelableUserUtils
import org.mariotaku.twidere.model.util.UserKeyUtils
import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers
import org.mariotaku.twidere.task.UpdateAccountInfoTask
import org.mariotaku.twidere.util.ContentValuesCreator.createCachedUser
import org.mariotaku.twidere.util.MicroBlogAPIFactory
import org.mariotaku.twidere.util.TwitterWrapper
import org.mariotaku.twidere.util.UserColorNameManager
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
import javax.inject.Inject
class ParcelableUserLoader(
context: Context,
private val accountKey: UserKey,
private val userKey: UserKey?,
private val screenName: String?,
private val extras: Bundle?,
private val omitIntentExtra: Boolean,
private val loadFromCache: Boolean
) : AsyncTaskLoader<SingleResponse<ParcelableUser>>(context), Constants {
@Inject
lateinit var userColorNameManager: UserColorNameManager
init {
GeneralComponentHelper.build(context).inject(this)
}
override fun loadInBackground(): SingleResponse<ParcelableUser> {
val context = context
val resolver = context.contentResolver
val accountKey = accountKey
var credentials: ParcelableCredentials? = null
for (cred in ParcelableCredentialsUtils.getCredentialses(context)) {
if (cred.account_key == accountKey) {
credentials = cred
break
} else if (cred.account_user != null && cred.account_user!!.account_key == accountKey) {
credentials = cred
break
}
}
if (credentials == null) return SingleResponse.getInstance<ParcelableUser>()
if (!omitIntentExtra && extras != null) {
val user = extras.getParcelable<ParcelableUser>(EXTRA_USER)
if (user != null) {
val values = ParcelableUserValuesCreator.create(user)
resolver.insert(CachedUsers.CONTENT_URI, values)
ParcelableUserUtils.updateExtraInformation(user, credentials, userColorNameManager)
return SingleResponse.getInstance(user)
}
}
val twitter = MicroBlogAPIFactory.getInstance(context, credentials, true, true) ?: return SingleResponse.getInstance<ParcelableUser>()
if (loadFromCache) {
val where: Expression
val whereArgs: Array<String>
if (userKey != null) {
where = Expression.equalsArgs(CachedUsers.USER_KEY)
whereArgs = arrayOf(userKey.toString())
} else if (screenName != null) {
val host = this.accountKey.host
if (host != null) {
where = Expression.and(
Expression.likeRaw(Columns.Column(CachedUsers.USER_KEY), "'%@'||?"),
Expression.equalsArgs(CachedUsers.SCREEN_NAME))
whereArgs = arrayOf(host, screenName)
} else {
where = Expression.equalsArgs(CachedUsers.SCREEN_NAME)
whereArgs = arrayOf(screenName)
}
} else {
return SingleResponse.getInstance<ParcelableUser>()
}
val cur = resolver.query(CachedUsers.CONTENT_URI, CachedUsers.COLUMNS,
where.sql, whereArgs, null)
if (cur != null) {
try {
cur.moveToFirst()
val indices = ParcelableUserCursorIndices(cur)
while (!cur.isAfterLast) {
val user = indices.newObject(cur)
if (TextUtils.equals(UserKeyUtils.getUserHost(user), user.key.host)) {
user.account_key = accountKey
user.account_color = credentials.color
return SingleResponse.getInstance(user)
}
cur.moveToNext()
}
} finally {
cur.close()
}
}
}
try {
val twitterUser: User
if (extras != null && Referral.SELF_PROFILE == extras.getString(EXTRA_REFERRAL)) {
twitterUser = twitter.verifyCredentials()
} else {
var profileUrl: String? = null
if (extras != null) {
profileUrl = extras.getString(EXTRA_PROFILE_URL)
}
if (MicroBlogAPIFactory.isStatusNetCredentials(credentials) && userKey != null &&
profileUrl != null && !TextUtils.equals(credentials.account_key.host,
userKey.host)) {
twitterUser = twitter.showExternalProfile(profileUrl)
} else {
val id = userKey?.id
twitterUser = TwitterWrapper.tryShowUser(twitter, id, screenName,
credentials.account_type)
}
}
val cachedUserValues = createCachedUser(twitterUser)
resolver.insert(CachedUsers.CONTENT_URI, cachedUserValues)
val user = ParcelableUserUtils.fromUser(twitterUser, accountKey)
ParcelableUserUtils.updateExtraInformation(user, credentials, userColorNameManager)
val response = SingleResponse.getInstance(user)
response.extras.putParcelable(EXTRA_ACCOUNT, credentials)
return response
} catch (e: MicroBlogException) {
Log.w(LOGTAG, e)
return SingleResponse.getInstance<ParcelableUser>(e)
}
}
override fun onStartLoading() {
if (!omitIntentExtra && extras != null) {
val user = extras.getParcelable<ParcelableUser>(EXTRA_USER)
if (user != null) {
deliverResult(SingleResponse.getInstance(user))
}
}
forceLoad()
}
override fun deliverResult(data: SingleResponse<ParcelableUser>) {
super.deliverResult(data)
if (data.hasData()) {
val user = data.data
if (user.is_cache) return
val account = data.extras.getParcelable<ParcelableAccount>(EXTRA_ACCOUNT)
if (account != null) {
val task = UpdateAccountInfoTask(context)
task.setParams(Pair(account, user))
TaskStarter.execute<Pair<ParcelableAccount, ParcelableUser>, Any, Any>(task)
}
}
}
}

View File

@ -1,80 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.menu;
import android.content.Context;
import android.content.Intent;
import android.support.v4.view.ActionProvider;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.MenuUtils;
import static org.mariotaku.twidere.Constants.MENU_GROUP_STATUS_SHARE;
import static org.mariotaku.twidere.util.Utils.createStatusShareIntent;
/**
* Created by mariotaku on 14/12/7.
*/
public class SupportStatusShareProvider extends ActionProvider {
private final Context mContext;
private ParcelableStatus mStatus;
public SupportStatusShareProvider(Context context) {
super(context);
mContext = context;
}
@Override
public View onCreateActionView() {
return null;
}
@Override
public View onCreateActionView(MenuItem forItem) {
return null;
}
@Override
public boolean onPerformDefaultAction() {
return true;
}
@Override
public boolean hasSubMenu() {
return true;
}
@Override
public void onPrepareSubMenu(SubMenu subMenu) {
final ParcelableStatus status = mStatus;
if (status == null) return;
final Intent shareIntent = createStatusShareIntent(mContext, status);
subMenu.removeGroup(MENU_GROUP_STATUS_SHARE);
MenuUtils.addIntentToMenu(mContext, subMenu, shareIntent, MENU_GROUP_STATUS_SHARE);
}
public void setStatus(ParcelableStatus status) {
mStatus = status;
}
}

View File

@ -0,0 +1,53 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.menu
import android.content.Context
import android.support.v4.view.ActionProvider
import android.view.MenuItem
import android.view.SubMenu
import android.view.View
import org.mariotaku.twidere.Constants.MENU_GROUP_STATUS_SHARE
import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.util.MenuUtils
import org.mariotaku.twidere.util.Utils.createStatusShareIntent
/**
* Created by mariotaku on 14/12/7.
*/
class SupportStatusShareProvider(context: Context) : ActionProvider(context) {
var status: ParcelableStatus? = null
override fun onCreateActionView(): View? = null
override fun onCreateActionView(forItem: MenuItem?): View? = null
override fun onPerformDefaultAction(): Boolean = true
override fun hasSubMenu(): Boolean = true
override fun onPrepareSubMenu(subMenu: SubMenu?) {
val status = status ?: return
val shareIntent = createStatusShareIntent(context, status)
subMenu!!.removeGroup(MENU_GROUP_STATUS_SHARE)
MenuUtils.addIntentToMenu(context, subMenu, shareIntent, MENU_GROUP_STATUS_SHARE)
}
}

View File

@ -24,7 +24,7 @@ import org.mariotaku.twidere.provider.TwidereDataStore.Tabs;
/**
* Created by mariotaku on 16/3/6.
*/
@CursorObject(valuesCreator = true)
@CursorObject(valuesCreator = true, tableInfo = true)
@JsonObject
public class Tab {
@CursorField(value = Tabs._ID, excludeWrite = true)

View File

@ -604,8 +604,8 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
@Override
public SQLiteDatabase onCreateSQLiteDatabase() {
final TwidereApplication app = TwidereApplication.getInstance(getContext());
final SQLiteOpenHelper helper = app.getSQLiteOpenHelper();
final TwidereApplication app = TwidereApplication.Companion.getInstance(getContext());
final SQLiteOpenHelper helper = app.getSqLiteOpenHelper();
return helper.getWritableDatabase();
}

View File

@ -46,7 +46,7 @@ public class ConnectivityStateReceiver extends BroadcastReceiver implements Cons
Log.d(RECEIVER_LOGTAG, String.format("Received Broadcast %s", intent));
}
if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) return;
final TwidereApplication application = TwidereApplication.getInstance(context);
final TwidereApplication application = TwidereApplication.Companion.getInstance(context);
// application.reloadConnectivitySettings();
Utils.startRefreshServiceIfNeeded(application);
final SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME,

View File

@ -7,7 +7,6 @@ import android.database.Cursor;
import android.support.annotation.NonNull;
import android.support.v4.util.LongSparseArray;
import android.text.TextUtils;
import android.util.Pair;
import org.mariotaku.abstask.library.AbstractTask;
import org.mariotaku.sqliteqb.library.Expression;
@ -27,6 +26,8 @@ import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
import org.mariotaku.twidere.provider.TwidereDataStore.Tabs;
import org.mariotaku.twidere.util.JsonSerializer;
import kotlin.Pair;
/**
* Created by mariotaku on 16/3/8.
*/
@ -40,8 +41,8 @@ public class UpdateAccountInfoTask extends AbstractTask<Pair<ParcelableAccount,
@Override
protected Object doLongOperation(Pair<ParcelableAccount, ParcelableUser> params) {
final ContentResolver resolver = context.getContentResolver();
final ParcelableAccount account = params.first;
final ParcelableUser user = params.second;
final ParcelableAccount account = params.getFirst();
final ParcelableUser user = params.getSecond();
if (account == null || user == null) return null;
if (user.is_cache) {
return null;

View File

@ -225,7 +225,7 @@ public abstract class GetStatusesTask extends AbstractTask<RefreshTaskParam,
int olderCount = -1;
if (minPositionKey > 0) {
olderCount = DataStoreUtils.getStatusesCount(context, uri, null, minPositionKey,
Statuses.POSITION_KEY, false, accountKey);
Statuses.POSITION_KEY, false, new UserKey[]{accountKey});
}
final int rowsDeleted = resolver.delete(writeUri, deleteWhere, deleteWhereArgs);

View File

@ -119,7 +119,7 @@ public class UpdateStatusTask extends AbstractTask<Pair<String, ParcelableStatus
@NonNull
private UpdateStatusResult doUpdateStatus(ParcelableStatusUpdate update) throws UpdateStatusException {
final TwidereApplication app = TwidereApplication.getInstance(context);
final TwidereApplication app = TwidereApplication.Companion.getInstance(context);
final MediaUploaderInterface uploader = getMediaUploader(app);
final StatusShortenerInterface shortener = getStatusShortener(app);

View File

@ -19,6 +19,7 @@
package org.mariotaku.twidere.util;
import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
@ -444,6 +445,7 @@ public class DataImportExportUtils implements Constants {
this.supportedMap = getSupportedPreferencesMap(cls);
}
@SuppressLint("SwitchIntDef")
@Override
public boolean importValue(JsonParser jsonParser, String key, SharedPreferences.Editor editor) throws IOException {
final JsonToken token = jsonParser.nextToken();
@ -478,6 +480,7 @@ public class DataImportExportUtils implements Constants {
return true;
}
@SuppressLint("SwitchIntDef")
@Override
public boolean exportValue(JsonGenerator jsonGenerator, String key, SharedPreferences preferences) throws IOException {
final Preference preference = supportedMap.get(key);

View File

@ -470,7 +470,8 @@ public class DataStoreUtils implements Constants {
public static int getStatusesCount(@NonNull final Context context, final Uri uri,
@Nullable final Bundle extraArgs, final long compare,
String compareColumn, boolean greaterThan, UserKey... accountKeys) {
String compareColumn, boolean greaterThan,
@Nullable UserKey[] accountKeys) {
if (accountKeys == null) {
accountKeys = getActivatedAccountKeys(context);
}

View File

@ -1,374 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.annotation.UiThread;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ActionProvider;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.ShareActionProvider;
import android.util.Log;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.AccountSelectorActivity;
import org.mariotaku.twidere.activity.ColorPickerDialogActivity;
import org.mariotaku.twidere.constant.SharedPreferenceConstants;
import org.mariotaku.twidere.fragment.AbsStatusesFragment;
import org.mariotaku.twidere.fragment.AddStatusFilterDialogFragment;
import org.mariotaku.twidere.fragment.DestroyStatusDialogFragment;
import org.mariotaku.twidere.fragment.SetUserNicknameDialogFragment;
import org.mariotaku.twidere.graphic.ActionIconDrawable;
import org.mariotaku.twidere.graphic.PaddingDrawable;
import org.mariotaku.twidere.menu.FavoriteItemProvider;
import org.mariotaku.twidere.menu.SupportStatusShareProvider;
import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.util.ParcelableCredentialsUtils;
import org.mariotaku.twidere.util.menu.TwidereMenuInfo;
import java.util.List;
/**
* Created by mariotaku on 15/4/12.
*/
public class MenuUtils implements Constants {
private MenuUtils() {
}
public static void setMenuItemAvailability(final Menu menu, final int id, final boolean available) {
if (menu == null) return;
final MenuItem item = menu.findItem(id);
if (item == null) return;
item.setVisible(available);
item.setEnabled(available);
}
public static void setMenuItemChecked(final Menu menu, final int id, final boolean checked) {
if (menu == null) return;
final MenuItem item = menu.findItem(id);
if (item == null) return;
item.setChecked(checked);
}
public static void setMenuItemIcon(final Menu menu, final int id, @DrawableRes final int icon) {
if (menu == null) return;
final MenuItem item = menu.findItem(id);
if (item == null) return;
item.setIcon(icon);
}
public static void setMenuItemShowAsActionFlags(Menu menu, int id, int flags) {
if (menu == null) return;
final MenuItem item = menu.findItem(id);
if (item == null) return;
item.setShowAsActionFlags(flags);
MenuItemCompat.setShowAsAction(item, flags);
}
public static void setMenuItemTitle(final Menu menu, final int id, @StringRes final int icon) {
if (menu == null) return;
final MenuItem item = menu.findItem(id);
if (item == null) return;
item.setTitle(icon);
}
public static void addIntentToMenu(final Context context, final Menu menu, final Intent queryIntent) {
addIntentToMenu(context, menu, queryIntent, Menu.NONE);
}
public static void addIntentToMenu(final Context context, final Menu menu, final Intent queryIntent,
final int groupId) {
if (context == null || menu == null || queryIntent == null) return;
final PackageManager pm = context.getPackageManager();
final Resources res = context.getResources();
final float density = res.getDisplayMetrics().density;
final int padding = Math.round(density * 4);
final List<ResolveInfo> activities = pm.queryIntentActivities(queryIntent, 0);
for (final ResolveInfo info : activities) {
final Intent intent = new Intent(queryIntent);
final Drawable icon = info.loadIcon(pm);
intent.setClassName(info.activityInfo.packageName, info.activityInfo.name);
final MenuItem item = menu.add(groupId, Menu.NONE, Menu.NONE, info.loadLabel(pm));
item.setIntent(intent);
final int iw = icon.getIntrinsicWidth(), ih = icon.getIntrinsicHeight();
if (iw > 0 && ih > 0) {
final Drawable iconWithPadding = new PaddingDrawable(icon, padding);
iconWithPadding.setBounds(0, 0, iw, ih);
item.setIcon(iconWithPadding);
} else {
item.setIcon(icon);
}
}
}
public static void setupForStatus(@NonNull final Context context,
@NonNull final SharedPreferencesWrapper preferences,
@NonNull final Menu menu,
@NonNull final ParcelableStatus status,
@NonNull final AsyncTwitterWrapper twitter) {
final ParcelableCredentials account = ParcelableCredentialsUtils.getCredentials(context,
status.account_key);
if (account == null) return;
setupForStatus(context, preferences, menu, status, account, twitter);
}
@UiThread
public static void setupForStatus(@NonNull final Context context,
@NonNull final SharedPreferencesWrapper preferences,
@NonNull final Menu menu,
@NonNull final ParcelableStatus status,
@NonNull final ParcelableCredentials account,
@NonNull final AsyncTwitterWrapper twitter) {
if (menu instanceof ContextMenu) {
((ContextMenu) menu).setHeaderTitle(context.getString(R.string.status_menu_title_format,
UserColorNameManager.decideDisplayName(status.user_nickname, status.user_name,
status.user_screen_name, preferences.getBoolean(KEY_NAME_FIRST)),
status.text_unescaped));
}
final int retweetHighlight = ContextCompat.getColor(context, R.color.highlight_retweet);
final int favoriteHighlight = ContextCompat.getColor(context, R.color.highlight_favorite);
final int likeHighlight = ContextCompat.getColor(context, R.color.highlight_like);
final boolean isMyRetweet;
if (twitter.isCreatingRetweet(status.account_key, status.id)) {
isMyRetweet = true;
} else if (twitter.isDestroyingStatus(status.account_key, status.id)) {
isMyRetweet = false;
} else {
isMyRetweet = status.retweeted || Utils.isMyRetweet(status);
}
final MenuItem delete = menu.findItem(R.id.delete);
if (delete != null) {
delete.setVisible(Utils.isMyStatus(status));
}
final MenuItem retweet = menu.findItem(R.id.retweet);
if (retweet != null) {
ActionIconDrawable.setMenuHighlight(retweet, new TwidereMenuInfo(isMyRetweet, retweetHighlight));
retweet.setTitle(isMyRetweet ? R.string.cancel_retweet : R.string.retweet);
}
final MenuItem favorite = menu.findItem(R.id.favorite);
if (favorite != null) {
final boolean isFavorite;
if (twitter.isCreatingFavorite(status.account_key, status.id)) {
isFavorite = true;
} else if (twitter.isDestroyingFavorite(status.account_key, status.id)) {
isFavorite = false;
} else {
isFavorite = status.is_favorite;
}
ActionProvider provider = MenuItemCompat.getActionProvider(favorite);
final boolean useStar = preferences.getBoolean(SharedPreferenceConstants.KEY_I_WANT_MY_STARS_BACK);
if (provider instanceof FavoriteItemProvider) {
((FavoriteItemProvider) provider).setIsFavorite(favorite, isFavorite);
} else {
if (useStar) {
final Drawable oldIcon = favorite.getIcon();
if (oldIcon instanceof ActionIconDrawable) {
final Drawable starIcon = ContextCompat.getDrawable(context, R.drawable.ic_action_star);
favorite.setIcon(new ActionIconDrawable(starIcon, ((ActionIconDrawable) oldIcon).getDefaultColor()));
} else {
favorite.setIcon(R.drawable.ic_action_star);
}
ActionIconDrawable.setMenuHighlight(favorite, new TwidereMenuInfo(isFavorite, favoriteHighlight));
} else {
ActionIconDrawable.setMenuHighlight(favorite, new TwidereMenuInfo(isFavorite, likeHighlight));
}
}
if (useStar) {
favorite.setTitle(isFavorite ? R.string.unfavorite : R.string.favorite);
} else {
favorite.setTitle(isFavorite ? R.string.undo_like : R.string.like);
}
}
final MenuItem translate = menu.findItem(R.id.translate);
if (translate != null) {
final boolean isOfficialKey = Utils.isOfficialCredentials(context, account);
final SharedPreferencesWrapper prefs = SharedPreferencesWrapper.getInstance(context, SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
setMenuItemAvailability(menu, R.id.translate, isOfficialKey);
}
menu.removeGroup(Constants.MENU_GROUP_STATUS_EXTENSION);
Utils.addIntentToMenuForExtension(context, menu, Constants.MENU_GROUP_STATUS_EXTENSION, INTENT_ACTION_EXTENSION_OPEN_STATUS,
EXTRA_STATUS, EXTRA_STATUS_JSON, status);
final MenuItem shareItem = menu.findItem(R.id.share);
final ActionProvider shareProvider = MenuItemCompat.getActionProvider(shareItem);
if (shareProvider instanceof SupportStatusShareProvider) {
((SupportStatusShareProvider) shareProvider).setStatus(status);
} else if (shareProvider instanceof ShareActionProvider) {
final Intent shareIntent = Utils.createStatusShareIntent(context, status);
((ShareActionProvider) shareProvider).setShareIntent(shareIntent);
} else if (shareItem.hasSubMenu()) {
final Menu shareSubMenu = shareItem.getSubMenu();
final Intent shareIntent = Utils.createStatusShareIntent(context, status);
shareSubMenu.removeGroup(Constants.MENU_GROUP_STATUS_SHARE);
addIntentToMenu(context, shareSubMenu, shareIntent, Constants.MENU_GROUP_STATUS_SHARE);
} else {
final Intent shareIntent = Utils.createStatusShareIntent(context, status);
final Intent chooserIntent = Intent.createChooser(shareIntent, context.getString(R.string.share_status));
Utils.addCopyLinkIntent(context, chooserIntent, LinkCreator.getStatusWebLink(status));
shareItem.setIntent(chooserIntent);
}
}
public static boolean handleStatusClick(@NonNull final Context context,
@Nullable final Fragment fragment,
@NonNull final FragmentManager fm,
@NonNull final UserColorNameManager colorNameManager,
@NonNull final AsyncTwitterWrapper twitter,
@NonNull final ParcelableStatus status,
@NonNull final MenuItem item) {
switch (item.getItemId()) {
case R.id.copy: {
if (ClipboardUtils.setText(context, status.text_plain)) {
Utils.showOkMessage(context, R.string.text_copied, false);
}
break;
}
case R.id.retweet: {
if (Utils.isMyRetweet(status)) {
twitter.cancelRetweetAsync(status.account_key,
status.id, status.my_retweet_id);
} else {
twitter.retweetStatusAsync(status.account_key,
status.id);
}
break;
}
case R.id.quote: {
final Intent intent = new Intent(INTENT_ACTION_QUOTE);
intent.putExtra(EXTRA_STATUS, status);
context.startActivity(intent);
break;
}
case R.id.reply: {
final Intent intent = new Intent(INTENT_ACTION_REPLY);
intent.putExtra(EXTRA_STATUS, status);
context.startActivity(intent);
break;
}
case R.id.favorite: {
if (status.is_favorite) {
twitter.destroyFavoriteAsync(status.account_key, status.id);
} else {
ActionProvider provider = MenuItemCompat.getActionProvider(item);
if (provider instanceof FavoriteItemProvider) {
((FavoriteItemProvider) provider).invokeItem(item,
new AbsStatusesFragment.DefaultOnLikedListener(twitter, status));
} else {
twitter.createFavoriteAsync(status.account_key, status.id);
}
}
break;
}
case R.id.delete: {
DestroyStatusDialogFragment.show(fm, status);
break;
}
case R.id.add_to_filter: {
AddStatusFilterDialogFragment.show(fm, status);
break;
}
case R.id.set_color: {
final Intent intent = new Intent(context, ColorPickerDialogActivity.class);
final int color = colorNameManager.getUserColor(status.user_key);
if (color != 0) {
intent.putExtra(EXTRA_COLOR, color);
}
intent.putExtra(EXTRA_CLEAR_BUTTON, color != 0);
intent.putExtra(EXTRA_ALPHA_SLIDER, false);
if (fragment != null) {
fragment.startActivityForResult(intent, REQUEST_SET_COLOR);
} else if (context instanceof Activity) {
((Activity) context).startActivityForResult(intent, REQUEST_SET_COLOR);
}
break;
}
case R.id.clear_nickname: {
colorNameManager.clearUserNickname(status.user_key);
break;
}
case R.id.set_nickname: {
final String nick = colorNameManager.getUserNickname(status.user_key);
final SetUserNicknameDialogFragment df = SetUserNicknameDialogFragment.show(fm,
status.user_key, nick);
if (fragment != null) {
df.setTargetFragment(fragment, REQUEST_SET_NICKNAME);
}
break;
}
case R.id.open_with_account: {
final Intent intent = new Intent(INTENT_ACTION_SELECT_ACCOUNT);
intent.setClass(context, AccountSelectorActivity.class);
intent.putExtra(EXTRA_SINGLE_SELECTION, true);
intent.putExtra(EXTRA_ACCOUNT_HOST, status.user_key.getHost());
if (fragment != null) {
fragment.startActivityForResult(intent, REQUEST_SELECT_ACCOUNT);
} else if (context instanceof Activity) {
((Activity) context).startActivityForResult(intent, REQUEST_SELECT_ACCOUNT);
}
break;
}
case R.id.open_in_browser: {
final Uri uri = LinkCreator.getStatusWebLink(status);
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setPackage(IntentUtils.getDefaultBrowserPackage(context, uri, true));
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
intent.setPackage(null);
context.startActivity(Intent.createChooser(intent,
context.getString(R.string.open_in_browser)));
}
break;
}
default: {
if (item.getIntent() != null) {
try {
context.startActivity(item.getIntent());
} catch (final ActivityNotFoundException e) {
Log.w(LOGTAG, e);
return false;
}
}
break;
}
}
return true;
}
}

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