mirror of
https://github.com/TwidereProject/Twidere-Android
synced 2025-02-17 04:00:48 +01:00
mastodon improvement
fixed link handler crashes updated version
This commit is contained in:
parent
3c7de6f284
commit
9a6f9e09f6
@ -81,7 +81,7 @@ public interface AccountsResources {
|
||||
Relationship unmuteUser(@Path("id") String id) throws MicroBlogException;
|
||||
|
||||
@GET("/v1/accounts/relationships")
|
||||
LinkHeaderList<Relationship> getRelationships(@Query(value = "id", arrayDelimiter = ',')
|
||||
LinkHeaderList<Relationship> getRelationships(@Query(value = "id[]")
|
||||
String[] id) throws MicroBlogException;
|
||||
|
||||
@GET("/v1/accounts/search")
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
package org.mariotaku.microblog.library.mastodon.api;
|
||||
|
||||
import org.mariotaku.microblog.library.MicroBlogException;
|
||||
import org.mariotaku.microblog.library.mastodon.model.Account;
|
||||
import org.mariotaku.microblog.library.mastodon.model.LinkHeaderList;
|
||||
import org.mariotaku.microblog.library.twitter.model.Paging;
|
||||
@ -30,5 +31,5 @@ import org.mariotaku.restfu.annotation.param.Query;
|
||||
|
||||
public interface BlocksResources {
|
||||
@GET("/v1/blocks")
|
||||
LinkHeaderList<Account> getBlocks(@Query Paging paging);
|
||||
LinkHeaderList<Account> getBlocks(@Query Paging paging) throws MicroBlogException;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
package org.mariotaku.microblog.library.mastodon.api;
|
||||
|
||||
import org.mariotaku.microblog.library.MicroBlogException;
|
||||
import org.mariotaku.microblog.library.mastodon.model.Account;
|
||||
import org.mariotaku.restfu.annotation.method.POST;
|
||||
import org.mariotaku.restfu.annotation.param.Param;
|
||||
@ -35,5 +36,5 @@ public interface FollowsResources {
|
||||
* @return The local representation of the followed account, as an {@link Account}.
|
||||
*/
|
||||
@POST("/v1/follows")
|
||||
Account followRemoteUser(@Param("uri") String uri);
|
||||
Account followRemoteUser(@Param("uri") String uri) throws MicroBlogException;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
package org.mariotaku.microblog.library.mastodon.api;
|
||||
|
||||
import org.mariotaku.microblog.library.MicroBlogException;
|
||||
import org.mariotaku.microblog.library.mastodon.model.Account;
|
||||
import org.mariotaku.microblog.library.mastodon.model.LinkHeaderList;
|
||||
import org.mariotaku.microblog.library.twitter.model.Paging;
|
||||
@ -30,5 +31,5 @@ import org.mariotaku.restfu.annotation.param.Query;
|
||||
|
||||
public interface MutesResources {
|
||||
@GET("/v1/mutes")
|
||||
LinkHeaderList<Account> getMutes(@Query Paging paging);
|
||||
LinkHeaderList<Account> getMutes(@Query Paging paging) throws MicroBlogException;
|
||||
}
|
||||
|
@ -18,9 +18,20 @@
|
||||
|
||||
package org.mariotaku.microblog.library.mastodon.api;
|
||||
|
||||
import org.mariotaku.microblog.library.MicroBlogException;
|
||||
import org.mariotaku.microblog.library.mastodon.model.Results;
|
||||
import org.mariotaku.microblog.library.twitter.model.Paging;
|
||||
import org.mariotaku.restfu.annotation.method.GET;
|
||||
import org.mariotaku.restfu.annotation.param.Query;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/4/17.
|
||||
*/
|
||||
|
||||
public interface SearchResources {
|
||||
|
||||
@GET("/v1/search")
|
||||
Results search(@Query("q") String query, @Query("resolve") boolean resolve,
|
||||
@Query Paging paging) throws MicroBlogException;
|
||||
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ package org.mariotaku.microblog.library.mastodon.model;
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@see https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md#context}
|
||||
@ -34,26 +34,26 @@ public class Context {
|
||||
* The ancestors of the status in the conversation, as a list of {@link Status}
|
||||
*/
|
||||
@JsonField(name = "ancestors")
|
||||
Status[] ancestors;
|
||||
List<Status> ancestors;
|
||||
/**
|
||||
* The descendants of the status in the conversation, as a list of {@link Status}
|
||||
*/
|
||||
@JsonField(name = "descendants")
|
||||
Status[] descendants;
|
||||
List<Status> descendants;
|
||||
|
||||
public Status[] getAncestors() {
|
||||
public List<Status> getAncestors() {
|
||||
return ancestors;
|
||||
}
|
||||
|
||||
public Status[] getDescendants() {
|
||||
public List<Status> getDescendants() {
|
||||
return descendants;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Context{" +
|
||||
"ancestors=" + Arrays.toString(ancestors) +
|
||||
", descendants=" + Arrays.toString(descendants) +
|
||||
"ancestors=" + ancestors +
|
||||
", descendants=" + descendants +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -20,22 +20,20 @@ package org.mariotaku.microblog.library.mastodon.model;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.mariotaku.restfu.http.HttpResponse;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/4/21.
|
||||
*/
|
||||
public class LinkHeaderList<E> extends ArrayList<E> {
|
||||
public class LinkHeaderList<E> extends ArrayList<E> implements LinkHeaderResponse {
|
||||
|
||||
@NonNull
|
||||
private Map<String, String> linkParts = new HashMap<>();
|
||||
@Nullable
|
||||
private Map<String, String> linkParts;
|
||||
|
||||
public LinkHeaderList(int initialCapacity) {
|
||||
super(initialCapacity);
|
||||
@ -48,33 +46,15 @@ public class LinkHeaderList<E> extends ArrayList<E> {
|
||||
super(c);
|
||||
}
|
||||
|
||||
public final void processResponseHeader(HttpResponse resp) {
|
||||
linkParts.clear();
|
||||
String linkHeader = resp.getHeader("Link");
|
||||
if (linkHeader == null) return;
|
||||
for (String link : TextUtils.split(linkHeader, ",")) {
|
||||
String[] segments = TextUtils.split(link, ";");
|
||||
if (segments.length < 2) continue;
|
||||
String linkPart = segments[0].trim();
|
||||
if (!linkPart.startsWith("<") || !linkPart.endsWith(">"))
|
||||
continue;
|
||||
linkPart = linkPart.substring(1, linkPart.length() - 1);
|
||||
for (int i = 1; i < segments.length; i++) {
|
||||
String[] rel = TextUtils.split(segments[i].trim(), "=");
|
||||
if (rel.length < 2 || !"rel".equals(rel[0]))
|
||||
continue;
|
||||
|
||||
String relValue = rel[1];
|
||||
if (relValue.startsWith("\"") && relValue.endsWith("\""))
|
||||
relValue = relValue.substring(1, relValue.length() - 1);
|
||||
|
||||
linkParts.put(relValue, linkPart);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public final void processResponseHeader(@NonNull HttpResponse resp) {
|
||||
linkParts = Parser.parse(resp);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getLinkPart(String key) {
|
||||
if (linkParts == null) return null;
|
||||
return linkParts.get(key);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mariotaku.microblog.library.mastodon.model;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.mariotaku.restfu.http.HttpResponse;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/4/23.
|
||||
*/
|
||||
|
||||
public interface LinkHeaderResponse {
|
||||
|
||||
void processResponseHeader(@NonNull HttpResponse resp);
|
||||
|
||||
@Nullable
|
||||
String getLinkPart(String key);
|
||||
|
||||
class Parser {
|
||||
|
||||
@Nullable
|
||||
public static Map<String, String> parse(@NonNull HttpResponse resp) {
|
||||
String linkHeader = resp.getHeader("Link");
|
||||
if (linkHeader == null) return null;
|
||||
Map<String, String> linkParts = new HashMap<>();
|
||||
for (String link : TextUtils.split(linkHeader, ",")) {
|
||||
String[] segments = TextUtils.split(link, ";");
|
||||
if (segments.length < 2) continue;
|
||||
String linkPart = segments[0].trim();
|
||||
if (!linkPart.startsWith("<") || !linkPart.endsWith(">"))
|
||||
continue;
|
||||
linkPart = linkPart.substring(1, linkPart.length() - 1);
|
||||
for (int i = 1; i < segments.length; i++) {
|
||||
String[] rel = TextUtils.split(segments[i].trim(), "=");
|
||||
if (rel.length < 2 || !"rel".equals(rel[0]))
|
||||
continue;
|
||||
|
||||
String relValue = rel[1];
|
||||
if (relValue.startsWith("\"") && relValue.endsWith("\""))
|
||||
relValue = relValue.substring(1, relValue.length() - 1);
|
||||
|
||||
linkParts.put(relValue, linkPart);
|
||||
}
|
||||
}
|
||||
return linkParts;
|
||||
}
|
||||
}
|
||||
}
|
@ -18,10 +18,16 @@
|
||||
|
||||
package org.mariotaku.microblog.library.mastodon.model;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.mariotaku.restfu.http.HttpResponse;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* {@see https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md#results}
|
||||
@ -29,41 +35,56 @@ import java.util.Arrays;
|
||||
* Created by mariotaku on 2017/4/17.
|
||||
*/
|
||||
@JsonObject
|
||||
public class Results {
|
||||
public class Results implements LinkHeaderResponse {
|
||||
/**
|
||||
* An array of matched {@link Account}
|
||||
* A list of matched {@link Account}
|
||||
*/
|
||||
@JsonField(name = "accounts")
|
||||
Account[] accounts;
|
||||
List<Account> accounts;
|
||||
/**
|
||||
* An array of matched {@link Status}
|
||||
* A list of matched {@link Status}
|
||||
*/
|
||||
@JsonField(name = "statuses")
|
||||
Status[] statuses;
|
||||
List<Status> statuses;
|
||||
/**
|
||||
* An array of matched hashtags, as strings
|
||||
* A list of matched hashtags, as strings
|
||||
*/
|
||||
@JsonField(name = "hashtags")
|
||||
String[] hashtags;
|
||||
List<String> hashtags;
|
||||
|
||||
public Account[] getAccounts() {
|
||||
@Nullable
|
||||
private Map<String, String> linkParts;
|
||||
|
||||
public List<Account> getAccounts() {
|
||||
return accounts;
|
||||
}
|
||||
|
||||
public Status[] getStatuses() {
|
||||
public List<Status> getStatuses() {
|
||||
return statuses;
|
||||
}
|
||||
|
||||
public String[] getHashtags() {
|
||||
public List<String> getHashtags() {
|
||||
return hashtags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void processResponseHeader(@NonNull HttpResponse resp) {
|
||||
linkParts = Parser.parse(resp);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getLinkPart(String key) {
|
||||
if (linkParts == null) return null;
|
||||
return linkParts.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Results{" +
|
||||
"accounts=" + Arrays.toString(accounts) +
|
||||
", statuses=" + Arrays.toString(statuses) +
|
||||
", hashtags=" + Arrays.toString(hashtags) +
|
||||
"accounts=" + accounts +
|
||||
", statuses=" + statuses +
|
||||
", hashtags=" + hashtags +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +93,7 @@ public interface TwidereConstants extends SharedPreferenceConstants, IntentConst
|
||||
String AUTHORITY_USER_BLOCKS = "user_blocks";
|
||||
String AUTHORITY_STATUS = "status";
|
||||
String AUTHORITY_PUBLIC_TIMELINE = "public_timeline";
|
||||
String AUTHORITY_NETWORK_PUBLIC_TIMELINE = "network_public_timeline";
|
||||
String AUTHORITY_MESSAGES = "direct_messages";
|
||||
String AUTHORITY_SEARCH = "search";
|
||||
String AUTHORITY_MAP = "map";
|
||||
|
@ -102,7 +102,8 @@ public class TabArguments implements TwidereConstants {
|
||||
case CustomTabType.NOTIFICATIONS_TIMELINE:
|
||||
case CustomTabType.DIRECT_MESSAGES:
|
||||
case CustomTabType.TRENDS_SUGGESTIONS:
|
||||
case CustomTabType.PUBLIC_TIMELINE: {
|
||||
case CustomTabType.PUBLIC_TIMELINE:
|
||||
case CustomTabType.NETWORK_PUBLIC_TIMELINE: {
|
||||
return LoganSquare.parse(json, TabArguments.class);
|
||||
}
|
||||
case CustomTabType.USER_TIMELINE:
|
||||
|
@ -36,8 +36,8 @@ android {
|
||||
applicationId "org.mariotaku.twidere"
|
||||
minSdkVersion project.properties['overrideMinSdkVersion'] ?: 14
|
||||
targetSdkVersion 25
|
||||
versionCode 340
|
||||
versionName '3.5.23'
|
||||
versionCode 341
|
||||
versionName '3.5.24'
|
||||
multiDexEnabled true
|
||||
|
||||
buildConfigField 'boolean', 'LEAK_CANARY_ENABLED', 'Boolean.parseBoolean("true")'
|
||||
|
@ -78,6 +78,7 @@ public interface Constants extends TwidereConstants {
|
||||
|
||||
int LINK_ID_INTERACTIONS = 35;
|
||||
int LINK_ID_PUBLIC_TIMELINE = 36;
|
||||
int LINK_ID_NETWORK_PUBLIC_TIMELINE = 37;
|
||||
int LINK_ID_MUTES_USERS = 41;
|
||||
int LINK_ID_MAP = 51;
|
||||
int LINK_ID_ACCOUNTS = 101;
|
||||
|
@ -125,7 +125,8 @@ public class CustomTabUtils implements Constants {
|
||||
case CustomTabType.NOTIFICATIONS_TIMELINE:
|
||||
case CustomTabType.DIRECT_MESSAGES:
|
||||
case CustomTabType.TRENDS_SUGGESTIONS:
|
||||
case CustomTabType.PUBLIC_TIMELINE: {
|
||||
case CustomTabType.PUBLIC_TIMELINE:
|
||||
case CustomTabType.NETWORK_PUBLIC_TIMELINE: {
|
||||
return new TabArguments();
|
||||
}
|
||||
case CustomTabType.USER_TIMELINE:
|
||||
|
@ -62,7 +62,6 @@ import org.mariotaku.twidere.fragment.message.MessageConversationInfoFragment
|
||||
import org.mariotaku.twidere.fragment.message.MessageNewConversationFragment
|
||||
import org.mariotaku.twidere.fragment.message.MessagesConversationFragment
|
||||
import org.mariotaku.twidere.fragment.message.MessagesEntriesFragment
|
||||
import org.mariotaku.twidere.fragment.status.*
|
||||
import org.mariotaku.twidere.fragment.statuses.*
|
||||
import org.mariotaku.twidere.fragment.users.*
|
||||
import org.mariotaku.twidere.graphic.EmptyDrawable
|
||||
@ -461,6 +460,9 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
|
||||
LINK_ID_PUBLIC_TIMELINE -> {
|
||||
title = getString(R.string.title_public_timeline)
|
||||
}
|
||||
LINK_ID_NETWORK_PUBLIC_TIMELINE -> {
|
||||
title = getString(R.string.title_network_public_timeline)
|
||||
}
|
||||
LINK_ID_FILTERS_IMPORT_BLOCKS -> {
|
||||
title = getString(R.string.title_select_users)
|
||||
}
|
||||
@ -579,7 +581,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
|
||||
fragment = UserFragment()
|
||||
val paramScreenName = uri.getQueryParameter(QUERY_PARAM_SCREEN_NAME)
|
||||
val paramProfileUrl = uri.getQueryParameter(QUERY_PARAM_PROFILE_URL)
|
||||
val paramUserKey = Utils.getUserKeyParam(uri)?.let(UserKey::valueOf)
|
||||
val paramUserKey = uri.getUserKeyQueryParameter()
|
||||
if (!args.containsKey(EXTRA_SCREEN_NAME)) {
|
||||
args.putString(EXTRA_SCREEN_NAME, paramScreenName)
|
||||
}
|
||||
@ -598,7 +600,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
|
||||
LINK_ID_USER_LIST_MEMBERSHIPS -> {
|
||||
fragment = UserListMembershipsFragment()
|
||||
val paramScreenName = uri.getQueryParameter(QUERY_PARAM_SCREEN_NAME)
|
||||
val paramUserKey = Utils.getUserKeyParam(uri)?.let(UserKey::valueOf)
|
||||
val paramUserKey = uri.getUserKeyQueryParameter()
|
||||
if (!args.containsKey(EXTRA_SCREEN_NAME)) {
|
||||
args.putString(EXTRA_SCREEN_NAME, paramScreenName)
|
||||
}
|
||||
@ -610,7 +612,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
|
||||
fragment = UserTimelineFragment()
|
||||
val paramScreenName = uri.getQueryParameter(QUERY_PARAM_SCREEN_NAME)
|
||||
val paramProfileUrl = uri.getQueryParameter(QUERY_PARAM_PROFILE_URL)
|
||||
val paramUserKey = Utils.getUserKeyParam(uri)?.let(UserKey::valueOf)
|
||||
val paramUserKey = uri.getUserKeyQueryParameter()
|
||||
if (!args.containsKey(EXTRA_SCREEN_NAME)) {
|
||||
args.putString(EXTRA_SCREEN_NAME, paramScreenName)
|
||||
}
|
||||
@ -625,7 +627,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
|
||||
LINK_ID_USER_MEDIA_TIMELINE -> {
|
||||
fragment = UserMediaTimelineFragment()
|
||||
val paramScreenName = uri.getQueryParameter(QUERY_PARAM_SCREEN_NAME)
|
||||
val paramUserKey = Utils.getUserKeyParam(uri)?.let(UserKey::valueOf)
|
||||
val paramUserKey = uri.getUserKeyQueryParameter()
|
||||
if (!args.containsKey(EXTRA_SCREEN_NAME)) {
|
||||
args.putString(EXTRA_SCREEN_NAME, paramScreenName)
|
||||
}
|
||||
@ -637,7 +639,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
|
||||
LINK_ID_USER_FAVORITES -> {
|
||||
fragment = UserFavoritesFragment()
|
||||
val paramScreenName = uri.getQueryParameter(QUERY_PARAM_SCREEN_NAME)
|
||||
val paramUserKey = Utils.getUserKeyParam(uri)?.let(UserKey::valueOf)
|
||||
val paramUserKey = uri.getUserKeyQueryParameter()
|
||||
if (!args.containsKey(EXTRA_SCREEN_NAME)) {
|
||||
args.putString(EXTRA_SCREEN_NAME, paramScreenName)
|
||||
}
|
||||
@ -650,7 +652,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
|
||||
LINK_ID_USER_FOLLOWERS -> {
|
||||
fragment = UserFollowersFragment()
|
||||
val paramScreenName = uri.getQueryParameter(QUERY_PARAM_SCREEN_NAME)
|
||||
val paramUserKey = Utils.getUserKeyParam(uri)?.let(UserKey::valueOf)
|
||||
val paramUserKey = uri.getUserKeyQueryParameter()
|
||||
if (!args.containsKey(EXTRA_SCREEN_NAME)) {
|
||||
args.putString(EXTRA_SCREEN_NAME, paramScreenName)
|
||||
}
|
||||
@ -662,7 +664,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
|
||||
LINK_ID_USER_FRIENDS -> {
|
||||
fragment = UserFriendsFragment()
|
||||
val paramScreenName = uri.getQueryParameter(QUERY_PARAM_SCREEN_NAME)
|
||||
val paramUserKey = Utils.getUserKeyParam(uri)?.let(UserKey::valueOf)
|
||||
val paramUserKey = uri.getUserKeyQueryParameter()
|
||||
if (!args.containsKey(EXTRA_SCREEN_NAME)) {
|
||||
args.putString(EXTRA_SCREEN_NAME, paramScreenName)
|
||||
}
|
||||
@ -704,10 +706,13 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
|
||||
LINK_ID_PUBLIC_TIMELINE -> {
|
||||
fragment = PublicTimelineFragment()
|
||||
}
|
||||
LINK_ID_NETWORK_PUBLIC_TIMELINE -> {
|
||||
fragment = NetworkPublicTimelineFragment()
|
||||
}
|
||||
LINK_ID_USER_LIST -> {
|
||||
fragment = UserListFragment()
|
||||
val paramScreenName = uri.getQueryParameter(QUERY_PARAM_SCREEN_NAME)
|
||||
val paramUserKey = Utils.getUserKeyParam(uri)?.let(UserKey::valueOf)
|
||||
val paramUserKey = uri.getUserKeyQueryParameter()
|
||||
val paramListId = uri.getQueryParameter(QUERY_PARAM_LIST_ID)
|
||||
val paramListName = uri.getQueryParameter(QUERY_PARAM_LIST_NAME)
|
||||
if ((TextUtils.isEmpty(paramListName) || TextUtils.isEmpty(paramScreenName) && paramUserKey == null) && TextUtils.isEmpty(paramListId)) {
|
||||
@ -730,7 +735,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
|
||||
LINK_ID_USER_LISTS -> {
|
||||
fragment = ListsFragment()
|
||||
val paramScreenName = uri.getQueryParameter(QUERY_PARAM_SCREEN_NAME)
|
||||
val paramUserKey = Utils.getUserKeyParam(uri)?.let(UserKey::valueOf)
|
||||
val paramUserKey = uri.getUserKeyQueryParameter()
|
||||
if (!args.containsKey(EXTRA_SCREEN_NAME)) {
|
||||
args.putString(EXTRA_SCREEN_NAME, paramScreenName)
|
||||
}
|
||||
@ -742,7 +747,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
|
||||
LINK_ID_USER_GROUPS -> {
|
||||
fragment = UserGroupsFragment()
|
||||
val paramScreenName = uri.getQueryParameter(QUERY_PARAM_SCREEN_NAME)
|
||||
val paramUserKey = Utils.getUserKeyParam(uri)?.let(UserKey::valueOf)
|
||||
val paramUserKey = uri.getUserKeyQueryParameter()
|
||||
if (!args.containsKey(EXTRA_SCREEN_NAME)) {
|
||||
args.putString(EXTRA_SCREEN_NAME, paramScreenName)
|
||||
}
|
||||
@ -754,7 +759,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
|
||||
LINK_ID_USER_LIST_TIMELINE -> {
|
||||
fragment = UserListTimelineFragment()
|
||||
val paramScreenName = uri.getQueryParameter(QUERY_PARAM_SCREEN_NAME)
|
||||
val paramUserKey = Utils.getUserKeyParam(uri)?.let(UserKey::valueOf)
|
||||
val paramUserKey = uri.getUserKeyQueryParameter()
|
||||
val paramListId = uri.getQueryParameter(QUERY_PARAM_LIST_ID)
|
||||
val paramListName = uri.getQueryParameter(QUERY_PARAM_LIST_NAME)
|
||||
if ((TextUtils.isEmpty(paramListName) || TextUtils.isEmpty(paramScreenName) && paramUserKey == null) && TextUtils.isEmpty(paramListId)) {
|
||||
@ -768,7 +773,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
|
||||
LINK_ID_USER_LIST_MEMBERS -> {
|
||||
fragment = UserListMembersFragment()
|
||||
val paramScreenName = uri.getQueryParameter(QUERY_PARAM_SCREEN_NAME)
|
||||
val paramUserKey = Utils.getUserKeyParam(uri)?.let(UserKey::valueOf)
|
||||
val paramUserKey = uri.getUserKeyQueryParameter()
|
||||
val paramListId = uri.getQueryParameter(QUERY_PARAM_LIST_ID)
|
||||
val paramListName = uri.getQueryParameter(QUERY_PARAM_LIST_NAME)
|
||||
if ((TextUtils.isEmpty(paramListName) || TextUtils.isEmpty(paramScreenName) && paramUserKey == null) && TextUtils.isEmpty(paramListId))
|
||||
@ -781,7 +786,7 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
|
||||
LINK_ID_USER_LIST_SUBSCRIBERS -> {
|
||||
fragment = UserListSubscribersFragment()
|
||||
val paramScreenName = uri.getQueryParameter(QUERY_PARAM_SCREEN_NAME)
|
||||
val paramUserKey = Utils.getUserKeyParam(uri)?.let(UserKey::valueOf)
|
||||
val paramUserKey = uri.getUserKeyQueryParameter()
|
||||
val paramListId = uri.getQueryParameter(QUERY_PARAM_LIST_ID)
|
||||
val paramListName = uri.getQueryParameter(QUERY_PARAM_LIST_NAME)
|
||||
if (TextUtils.isEmpty(paramListId) && (TextUtils.isEmpty(paramListName) || TextUtils.isEmpty(paramScreenName) && paramUserKey == null))
|
||||
@ -883,4 +888,9 @@ class LinkHandlerActivity : BaseActivity(), SystemWindowsInsetsCallback, IContro
|
||||
}
|
||||
|
||||
interface HideUiOnScroll
|
||||
|
||||
private fun Uri.getUserKeyQueryParameter() : UserKey? {
|
||||
val value = getQueryParameter(QUERY_PARAM_USER_KEY) ?: getQueryParameter(QUERY_PARAM_USER_ID)
|
||||
return value?.let(UserKey::valueOf)
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ package org.mariotaku.twidere.extension.model.api.mastodon
|
||||
|
||||
import android.net.Uri
|
||||
import org.mariotaku.microblog.library.mastodon.model.LinkHeaderList
|
||||
import org.mariotaku.microblog.library.mastodon.model.LinkHeaderResponse
|
||||
import org.mariotaku.twidere.model.pagination.PaginatedArrayList
|
||||
import org.mariotaku.twidere.model.pagination.PaginatedList
|
||||
import org.mariotaku.twidere.model.pagination.Pagination
|
||||
@ -37,7 +38,7 @@ inline fun <T, R> LinkHeaderList<T>.mapToPaginated(transform: (T) -> R): Paginat
|
||||
return result
|
||||
}
|
||||
|
||||
fun LinkHeaderList<*>.getLinkPagination(key: String): Pagination? {
|
||||
fun LinkHeaderResponse.getLinkPagination(key: String): Pagination? {
|
||||
val uri = getLinkPart(key)?.let(Uri::parse) ?: return null
|
||||
val maxId = uri.getQueryParameter("max_id")
|
||||
val sinceId = uri.getQueryParameter("since_id")
|
||||
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2017 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.extension.model.api.mastodon
|
||||
|
||||
import org.mariotaku.microblog.library.mastodon.model.Results
|
||||
import org.mariotaku.twidere.model.pagination.PaginatedArrayList
|
||||
import org.mariotaku.twidere.model.pagination.PaginatedList
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 2017/4/23.
|
||||
*/
|
||||
|
||||
inline fun <T, R> Results.mapToPaginated(listSelector: (Results) -> List<T>?, transform: (T) -> R): PaginatedList<R> {
|
||||
val list = listSelector(this) ?: return PaginatedArrayList()
|
||||
val result = list.mapTo(PaginatedArrayList(list.size), transform)
|
||||
result.previousPage = getLinkPagination("prev")
|
||||
result.nextPage = getLinkPagination("next")
|
||||
return result
|
||||
}
|
@ -337,6 +337,7 @@ class AccountsDashboardFragment : BaseFragment(), LoaderCallbacks<AccountsInfo>,
|
||||
var hasDmTab = false
|
||||
var hasInteractionsTab = false
|
||||
var hasPublicTimelineTab = false
|
||||
var hasNetworkPublicTimelineTab = false
|
||||
for (tab in tabs) {
|
||||
when (tab.type) {
|
||||
CustomTabType.DIRECT_MESSAGES -> {
|
||||
@ -354,6 +355,11 @@ class AccountsDashboardFragment : BaseFragment(), LoaderCallbacks<AccountsInfo>,
|
||||
hasPublicTimelineTab = hasAccountInTab(tab, account.key, true)
|
||||
}
|
||||
}
|
||||
CustomTabType.NETWORK_PUBLIC_TIMELINE -> {
|
||||
if (!hasNetworkPublicTimelineTab) {
|
||||
hasNetworkPublicTimelineTab = hasAccountInTab(tab, account.key, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val menu = navigationView.menu
|
||||
@ -374,6 +380,7 @@ class AccountsDashboardFragment : BaseFragment(), LoaderCallbacks<AccountsInfo>,
|
||||
var hasLists = false
|
||||
var hasGroups = false
|
||||
var hasPublicTimeline = false
|
||||
var hasNetworkPublicTimeline = false
|
||||
when (account.type) {
|
||||
AccountType.TWITTER -> {
|
||||
hasLists = true
|
||||
@ -381,17 +388,20 @@ class AccountsDashboardFragment : BaseFragment(), LoaderCallbacks<AccountsInfo>,
|
||||
AccountType.STATUSNET -> {
|
||||
hasGroups = true
|
||||
hasPublicTimeline = !hasPublicTimelineTab
|
||||
hasNetworkPublicTimeline = !hasNetworkPublicTimelineTab
|
||||
}
|
||||
AccountType.FANFOU -> {
|
||||
hasPublicTimeline = !hasPublicTimelineTab
|
||||
}
|
||||
AccountType.MASTODON -> {
|
||||
hasPublicTimeline = !hasPublicTimelineTab
|
||||
hasNetworkPublicTimeline = !hasNetworkPublicTimelineTab
|
||||
}
|
||||
}
|
||||
menu.setItemAvailability(R.id.groups, hasGroups)
|
||||
menu.setItemAvailability(R.id.lists, hasLists)
|
||||
menu.setItemAvailability(R.id.public_timeline, hasPublicTimeline)
|
||||
menu.setItemAvailability(R.id.network_public_timeline, hasNetworkPublicTimeline)
|
||||
}
|
||||
|
||||
private fun hasAccountInTab(tab: SupportTabSpec, accountKey: UserKey, isActivated: Boolean): Boolean {
|
||||
@ -573,6 +583,9 @@ class AccountsDashboardFragment : BaseFragment(), LoaderCallbacks<AccountsInfo>,
|
||||
R.id.public_timeline -> {
|
||||
IntentUtils.openPublicTimeline(activity, account.key)
|
||||
}
|
||||
R.id.network_public_timeline -> {
|
||||
IntentUtils.openNetworkPublicTimeline(activity, account.key)
|
||||
}
|
||||
R.id.messages -> {
|
||||
IntentUtils.openDirectMessages(activity, account.key)
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ class NetworkPublicTimelineFragment : ParcelableStatusesFragment() {
|
||||
get() {
|
||||
val accountKey = Utils.getAccountKey(context, arguments)
|
||||
val result = ArrayList<String>()
|
||||
result.add(AUTHORITY_PUBLIC_TIMELINE)
|
||||
result.add(AUTHORITY_NETWORK_PUBLIC_TIMELINE)
|
||||
result.add("account=$accountKey")
|
||||
return result.toTypedArray()
|
||||
}
|
||||
|
@ -25,15 +25,20 @@ import android.support.annotation.WorkerThread
|
||||
import org.mariotaku.commons.parcel.ParcelUtils
|
||||
import org.mariotaku.microblog.library.MicroBlog
|
||||
import org.mariotaku.microblog.library.MicroBlogException
|
||||
import org.mariotaku.microblog.library.mastodon.Mastodon
|
||||
import org.mariotaku.microblog.library.twitter.model.Paging
|
||||
import org.mariotaku.microblog.library.twitter.model.SearchQuery
|
||||
import org.mariotaku.microblog.library.twitter.model.Status
|
||||
import org.mariotaku.twidere.alias.MastodonStatus
|
||||
import org.mariotaku.twidere.annotation.AccountType
|
||||
import org.mariotaku.twidere.exception.APINotSupportedException
|
||||
import org.mariotaku.twidere.extension.model.api.mastodon.toParcelable
|
||||
import org.mariotaku.twidere.extension.model.api.toParcelable
|
||||
import org.mariotaku.twidere.extension.model.isOfficial
|
||||
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
|
||||
import org.mariotaku.twidere.model.AccountDetails
|
||||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import org.mariotaku.twidere.model.pagination.PaginatedArrayList
|
||||
import org.mariotaku.twidere.model.pagination.PaginatedList
|
||||
import org.mariotaku.twidere.model.pagination.SinceMaxPagination
|
||||
import org.mariotaku.twidere.model.util.ParcelableStatusUtils
|
||||
@ -57,11 +62,23 @@ class ConversationLoader(
|
||||
|
||||
@Throws(MicroBlogException::class)
|
||||
override fun getStatuses(account: AccountDetails, paging: Paging): PaginatedList<ParcelableStatus> {
|
||||
return getMicroBlogStatuses(account, paging).mapMicroBlogToPaginated {
|
||||
it.toParcelable(account, profileImageSize)
|
||||
when (account.type) {
|
||||
AccountType.MASTODON -> return getMastodonStatuses(account, paging).mapTo(PaginatedArrayList()) {
|
||||
it.toParcelable(account)
|
||||
}
|
||||
else -> return getMicroBlogStatuses(account, paging).mapMicroBlogToPaginated {
|
||||
it.toParcelable(account, profileImageSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMastodonStatuses(account: AccountDetails, paging: Paging): List<MastodonStatus> {
|
||||
val mastodon = account.newMicroBlogInstance(context, Mastodon::class.java)
|
||||
canLoadAllReplies = true
|
||||
val statusContext = mastodon.getStatusContext(status.id)
|
||||
return statusContext.ancestors + statusContext.descendants
|
||||
}
|
||||
|
||||
@Throws(MicroBlogException::class)
|
||||
private fun getMicroBlogStatuses(account: AccountDetails, paging: Paging): List<Status> {
|
||||
val microBlog = account.newMicroBlogInstance(context, MicroBlog::class.java)
|
||||
@ -85,10 +102,12 @@ class ConversationLoader(
|
||||
canLoadAllReplies = true
|
||||
return microBlog.getContextTimeline(status.id, paging)
|
||||
}
|
||||
else -> {
|
||||
throw APINotSupportedException(account.type)
|
||||
}
|
||||
}
|
||||
// Set to true because there's no conversation support on this platform
|
||||
canLoadAllReplies = true
|
||||
return showConversationCompat(microBlog, account, status, false)
|
||||
return showConversationCompat(microBlog, account, status, true)
|
||||
}
|
||||
|
||||
@Throws(MicroBlogException::class)
|
||||
|
@ -24,11 +24,15 @@ import android.database.sqlite.SQLiteDatabase
|
||||
import android.support.annotation.WorkerThread
|
||||
import org.mariotaku.microblog.library.MicroBlog
|
||||
import org.mariotaku.microblog.library.MicroBlogException
|
||||
import org.mariotaku.microblog.library.mastodon.Mastodon
|
||||
import org.mariotaku.microblog.library.mastodon.model.Results
|
||||
import org.mariotaku.microblog.library.twitter.model.Paging
|
||||
import org.mariotaku.microblog.library.twitter.model.SearchQuery
|
||||
import org.mariotaku.microblog.library.twitter.model.Status
|
||||
import org.mariotaku.microblog.library.twitter.model.UniversalSearchQuery
|
||||
import org.mariotaku.twidere.annotation.AccountType
|
||||
import org.mariotaku.twidere.extension.model.api.mastodon.mapToPaginated
|
||||
import org.mariotaku.twidere.extension.model.api.mastodon.toParcelable
|
||||
import org.mariotaku.twidere.extension.model.api.toParcelable
|
||||
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
|
||||
import org.mariotaku.twidere.extension.model.official
|
||||
@ -54,8 +58,13 @@ open class TweetSearchLoader(
|
||||
|
||||
@Throws(MicroBlogException::class)
|
||||
override fun getStatuses(account: AccountDetails, paging: Paging): PaginatedList<ParcelableStatus> {
|
||||
return getMicroBlogStatuses(account, paging).mapMicroBlogToPaginated {
|
||||
it.toParcelable(account, profileImageSize)
|
||||
when (account.type) {
|
||||
AccountType.MASTODON -> return getMastodonStatuses(account, paging).mapToPaginated(Results::getStatuses) {
|
||||
it.toParcelable(account)
|
||||
}
|
||||
else -> return getMicroBlogStatuses(account, paging).mapMicroBlogToPaginated {
|
||||
it.toParcelable(account, profileImageSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,6 +92,12 @@ open class TweetSearchLoader(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMastodonStatuses(account: AccountDetails, paging: Paging): Results {
|
||||
val mastodon = account.newMicroBlogInstance(context, Mastodon::class.java)
|
||||
if (query == null) throw MicroBlogException("Empty query")
|
||||
return mastodon.search(query, true, paging)
|
||||
}
|
||||
|
||||
private fun getMicroBlogStatuses(account: AccountDetails, paging: Paging): List<Status> {
|
||||
val microBlog = account.newMicroBlogInstance(context, MicroBlog::class.java)
|
||||
if (query == null) throw MicroBlogException("Empty query")
|
||||
|
@ -596,6 +596,17 @@ object IntentUtils {
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
fun openNetworkPublicTimeline(context: Context, accountKey: UserKey?) {
|
||||
val builder = Uri.Builder()
|
||||
builder.scheme(SCHEME_TWIDERE)
|
||||
builder.authority(AUTHORITY_NETWORK_PUBLIC_TIMELINE)
|
||||
if (accountKey != null) {
|
||||
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_KEY, accountKey.toString())
|
||||
}
|
||||
val intent = Intent(Intent.ACTION_VIEW, builder.build())
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
fun openAccountsManager(context: Context) {
|
||||
val intent = Intent()
|
||||
val builder = Uri.Builder()
|
||||
|
@ -66,7 +66,6 @@ import org.mariotaku.sqliteqb.library.Selectable
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.TwidereConstants.LOGTAG
|
||||
import org.mariotaku.twidere.TwidereConstants.METADATA_KEY_EXTENSION_USE_JSON
|
||||
import org.mariotaku.twidere.TwidereConstants.QUERY_PARAM_USER_KEY
|
||||
import org.mariotaku.twidere.TwidereConstants.SHARED_PREFERENCES_NAME
|
||||
import org.mariotaku.twidere.TwidereConstants.TAB_CODE_DIRECT_MESSAGES
|
||||
import org.mariotaku.twidere.TwidereConstants.TAB_CODE_HOME_TIMELINE
|
||||
@ -74,7 +73,6 @@ import org.mariotaku.twidere.TwidereConstants.TAB_CODE_NOTIFICATIONS_TIMELINE
|
||||
import org.mariotaku.twidere.annotation.CustomTabType
|
||||
import org.mariotaku.twidere.annotation.ProfileImageSize
|
||||
import org.mariotaku.twidere.constant.CompatibilityConstants.EXTRA_ACCOUNT_ID
|
||||
import org.mariotaku.twidere.constant.CompatibilityConstants.QUERY_PARAM_USER_ID
|
||||
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_ACCOUNT_KEY
|
||||
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_ACCOUNT_KEYS
|
||||
import org.mariotaku.twidere.constant.IntentConstants.INTENT_ACTION_PEBBLE_NOTIFICATION
|
||||
@ -156,11 +154,6 @@ object Utils {
|
||||
return contentType
|
||||
}
|
||||
|
||||
fun getUserKeyParam(uri: Uri): String {
|
||||
val paramUserKey = uri.getQueryParameter(QUERY_PARAM_USER_KEY) ?: return uri.getQueryParameter(QUERY_PARAM_USER_ID)
|
||||
return paramUserKey
|
||||
}
|
||||
|
||||
fun createStatusShareIntent(context: Context, status: ParcelableStatus): Intent {
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
intent.type = "text/plain"
|
||||
|
@ -24,6 +24,7 @@ object TwidereLinkMatcher {
|
||||
addURI(AUTHORITY_MESSAGES, PATH_MESSAGES_CONVERSATION_INFO, LINK_ID_MESSAGES_CONVERSATION_INFO)
|
||||
addURI(AUTHORITY_INTERACTIONS, null, LINK_ID_INTERACTIONS)
|
||||
addURI(AUTHORITY_PUBLIC_TIMELINE, null, LINK_ID_PUBLIC_TIMELINE)
|
||||
addURI(AUTHORITY_NETWORK_PUBLIC_TIMELINE, null, LINK_ID_NETWORK_PUBLIC_TIMELINE)
|
||||
addURI(AUTHORITY_USER_LIST, null, LINK_ID_USER_LIST)
|
||||
addURI(AUTHORITY_GROUP, null, LINK_ID_GROUP)
|
||||
addURI(AUTHORITY_USER_LIST_TIMELINE, null, LINK_ID_USER_LIST_TIMELINE)
|
||||
|
@ -37,6 +37,10 @@
|
||||
android:id="@id/public_timeline"
|
||||
android:icon="@drawable/ic_action_quote"
|
||||
android:title="@string/title_public_timeline"/>
|
||||
<item
|
||||
android:id="@+id/network_public_timeline"
|
||||
android:icon="@drawable/ic_action_web"
|
||||
android:title="@string/title_network_public_timeline"/>
|
||||
</group>
|
||||
<group
|
||||
android:id="@+id/app_menu"
|
||||
|
Loading…
x
Reference in New Issue
Block a user