Skip to content

Commit

Permalink
#384 Small amount of "TimelineTypes" is being replaced with individua…
Browse files Browse the repository at this point in the history
…l timelines (of the same types) per Account. Transition is in progress.
  • Loading branch information
yvolk committed Jun 4, 2016
1 parent 59b52a5 commit 1ab5165
Show file tree
Hide file tree
Showing 23 changed files with 473 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
import android.app.Notification;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.support.annotation.NonNull;

import org.andstatus.app.account.PersistentAccounts;
import org.andstatus.app.data.AssertionData;
import org.andstatus.app.database.DatabaseHolder;
import org.andstatus.app.data.TimelineType;
import org.andstatus.app.msg.PersistentTimelines;
import org.andstatus.app.net.http.HttpConnection;
import org.andstatus.app.origin.PersistentOrigins;
import org.andstatus.app.service.ConnectionState;
Expand Down Expand Up @@ -176,6 +178,12 @@ public PersistentOrigins persistentOrigins() {
return myContext.persistentOrigins();
}

@NonNull
@Override
public PersistentTimelines persistentTimelines() {
return myContext.persistentTimelines();
}

@Override
public HttpConnection getHttpConnectionMock() {
if (httpConnectionMockInstance != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* Copyright (C) 2016 yvolk (Yuri Volkov), http://yurivolkov.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.andstatus.app.msg;

import android.test.InstrumentationTestCase;

import org.andstatus.app.account.MyAccount;
import org.andstatus.app.context.MyContextHolder;
import org.andstatus.app.context.TestSuite;

import java.util.List;

public class PersistentTimelinesTest extends InstrumentationTestCase {

@Override
protected void setUp() throws Exception {
super.setUp();
TestSuite.initializeWithData(this);
}

public void testList() throws Exception {
List<Timeline> timelines = MyContextHolder.get().persistentTimelines().getList();
assertTrue(timelines.size() > 0);
}

public void testFilteredList() throws Exception {
List<Timeline> timelines = MyContextHolder.get().persistentTimelines().getList();
List<Timeline> filtered = MyContextHolder.get().persistentTimelines().getFiltered(true, false, null, null);
assertTrue(filtered.isEmpty());

filtered = MyContextHolder.get().persistentTimelines().getFiltered(true, true, null, null);
assertTrue(!filtered.isEmpty());
assertTrue(timelines.size() > filtered.size());

filtered = MyContextHolder.get().persistentTimelines().getFiltered(false, true, null, null);
assertEquals(timelines.size(), filtered.size());

MyAccount myAccount = MyContextHolder.get().persistentAccounts().fromAccountName(TestSuite.CONVERSATION_ACCOUNT_NAME);
filtered = MyContextHolder.get().persistentTimelines().getFiltered(true, false, myAccount, null);
assertTrue(!filtered.isEmpty());

List<Timeline> filtered2 = MyContextHolder.get().persistentTimelines().getFiltered(true, false, null, myAccount.getOrigin());
assertEquals(filtered.size(), filtered2.size());
}
}
1 change: 1 addition & 0 deletions app/src/main/java/org/andstatus/app/IntentExtra.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public enum IntentExtra{
* TimelineActivity Value is {@link TimelineType}
*/
TIMELINE_TYPE("TIMELINE_TYPE"),
TIMELINE_ID("TIMELINE_ID"),
/**
* Is the timeline combined
*/
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/org/andstatus/app/SelectorDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import android.view.ViewGroup;
import android.widget.ListView;

import org.andstatus.app.account.MySimpleAdapter;
import org.andstatus.app.widget.MySimpleAdapter;
import org.andstatus.app.context.MyTheme;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.TextView;

import org.andstatus.app.ActivityRequestCode;
import org.andstatus.app.IntentExtra;
import org.andstatus.app.R;
import org.andstatus.app.SelectorDialog;
import org.andstatus.app.context.MyContextHolder;
import org.andstatus.app.widget.MySimpleAdapter;

import java.util.ArrayList;
import java.util.HashMap;
Expand All @@ -49,7 +49,7 @@ public class AccountSelector extends SelectorDialog {

private static final String TYPE_ACCOUNT = "account";

public static void selectAccount(FragmentActivity activity, long originId, ActivityRequestCode requestCode) {
public static void selectAccount(FragmentActivity activity, ActivityRequestCode requestCode, long originId) {
SelectorDialog selector = new AccountSelector();
selector.setRequestCode(requestCode).putLong(IntentExtra.ORIGIN_ID.key, originId);
selector.show(activity);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ protected void restoreState(Intent intent, String calledFrom) {
if (state.originShouldBeSelected) {
selectOrigin();
} else if (state.accountShouldBeSelected) {
AccountSelector.selectAccount(this, 0, ActivityRequestCode.SELECT_ACCOUNT);
AccountSelector.selectAccount(this, ActivityRequestCode.SELECT_ACCOUNT, 0);
message += "Select account; ";
}
message += "action=" + state.getAccountAction() + "; ";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import android.app.Activity;
import android.app.Fragment;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
Expand Down Expand Up @@ -60,7 +61,11 @@ private void onRemoveAccount() {
for (android.accounts.Account account : aa) {
if (state.getAccount().getAccountName().equals(account.name)) {
MyLog.i(this, "Removing account: " + account.name);
am.removeAccount(account, null, null);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
am.removeAccount(account, getActivity(), null, null);
} else {
am.removeAccount(account, null, null);
}
}
}
getActivity().finish();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response,
MyAccount ma = MyContextHolder.get().persistentAccounts().fromAccountName(account.name);
boolean deleted = true;
if (ma.isValid()) {
MyContextHolder.get().persistentTimelines().onAccountDelete(ma);
deleted = MyContextHolder.get().persistentAccounts().delete(ma);
}
MyPreferences.onPreferencesChanged();
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/org/andstatus/app/account/MyAccount.java
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,8 @@ SaveResult saveSilently() {
}
MyLog.v(this, (result.savedToAccountManager ? " Saved "
: ( result.changed ? " Didn't save?! " : " Didn't change") ) + this.toString());

myContext.persistentTimelines().onAccountSave(myAccount);
} catch (Exception e) {
MyLog.e(this, "Saving " + myAccount.getAccountName(), e);
}
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/org/andstatus/app/context/MyContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.andstatus.app.data.AssertionData;
import org.andstatus.app.database.DatabaseHolder;
import org.andstatus.app.data.TimelineType;
import org.andstatus.app.msg.PersistentTimelines;
import org.andstatus.app.net.http.HttpConnection;
import org.andstatus.app.origin.PersistentOrigins;
import org.andstatus.app.service.ConnectionState;
Expand All @@ -45,7 +46,10 @@ public interface MyContext {
SQLiteDatabase getDatabase();
@NonNull
PersistentAccounts persistentAccounts();
@NonNull
PersistentOrigins persistentOrigins();
@NonNull
PersistentTimelines persistentTimelines();
void put(AssertionData data);
void release();
boolean isExpired();
Expand Down
24 changes: 17 additions & 7 deletions app/src/main/java/org/andstatus/app/context/MyContextImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Environment;
import android.support.annotation.NonNull;

import net.jcip.annotations.ThreadSafe;

Expand All @@ -34,6 +35,7 @@
import org.andstatus.app.database.DatabaseConverterController;
import org.andstatus.app.data.TimelineType;
import org.andstatus.app.graphics.MyImageCache;
import org.andstatus.app.msg.PersistentTimelines;
import org.andstatus.app.net.http.HttpConnection;
import org.andstatus.app.net.http.TlsSniSocketFactory;
import org.andstatus.app.origin.PersistentOrigins;
Expand Down Expand Up @@ -71,15 +73,16 @@ public final class MyContextImpl implements MyContext {
private volatile DatabaseHolder mDb;
private final PersistentAccounts mPersistentAccounts = PersistentAccounts.getEmpty();
private final PersistentOrigins mPersistentOrigins = PersistentOrigins.getEmpty();

private final PersistentTimelines persistentTimelines = PersistentTimelines.getEmpty();

private volatile boolean mExpired = false;

private final Locale mLocale = Locale.getDefault();

private static volatile boolean mInForeground = false;
private static volatile long mInForegroundChangedAt = 0;
private static final long CONSIDER_IN_BACKGROUND_AFTER_SECONDS = 20;

private MyContextImpl() {
}

Expand All @@ -105,12 +108,13 @@ public MyContext newInitialized(Context context, String initializerName) {
}
switch (myContext.mState) {
case READY:
myContext.mDb = newDb;
myContext.mPersistentOrigins.initialize(myContext);
myContext.mPersistentAccounts.initialize(myContext);
MyImageCache.initialize(myContext.context());
myContext.mDb = newDb;
myContext.mPersistentOrigins.initialize(myContext);
myContext.mPersistentAccounts.initialize(myContext);
myContext.persistentTimelines.initialize(myContext);
MyImageCache.initialize(myContext.context());
break;
default:
default:
break;
}
} catch (SQLiteException e) {
Expand Down Expand Up @@ -265,6 +269,12 @@ public PersistentOrigins persistentOrigins() {
return mPersistentOrigins;
}

@NonNull
@Override
public PersistentTimelines persistentTimelines() {
return persistentTimelines;
}

@Override
public HttpConnection getHttpConnectionMock() {
return null;
Expand Down
60 changes: 37 additions & 23 deletions app/src/main/java/org/andstatus/app/data/TimelineType.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ public enum TimelineType {
HOME("home", R.string.timeline_title_home, Connection.ApiRoutineEnum.STATUSES_HOME_TIMELINE,
true, false,
UserTable.HOME_TIMELINE_POSITION, UserTable.HOME_TIMELINE_ITEM_DATE, UserTable.HOME_TIMELINE_DATE),
/** Favorites (favorited messages) */
FAVORITES("favorites", R.string.timeline_title_favorites, Connection.ApiRoutineEnum.DUMMY,
false, false,
UserTable.FAVORITES_TIMELINE_POSITION, UserTable.FAVORITES_TIMELINE_ITEM_DATE, UserTable.FAVORITES_TIMELINE_DATE),
/** The Mentions timeline and other information (replies...). */
MENTIONS("mentions", R.string.timeline_title_mentions, Connection.ApiRoutineEnum.STATUSES_MENTIONS_TIMELINE,
true, false,
Expand All @@ -42,52 +46,62 @@ public enum TimelineType {
DIRECT("direct", R.string.timeline_title_direct_messages, Connection.ApiRoutineEnum.DIRECT_MESSAGES,
true, false,
UserTable.DIRECT_TIMELINE_POSITION, UserTable.DIRECT_TIMELINE_ITEM_DATE, UserTable.DIRECT_TIMELINE_DATE),
/** Favorites (favorited messages) */
FAVORITES("favorites", R.string.timeline_title_favorites, Connection.ApiRoutineEnum.DUMMY,
false, false,
UserTable.FAVORITES_TIMELINE_POSITION, UserTable.FAVORITES_TIMELINE_ITEM_DATE, UserTable.FAVORITES_TIMELINE_DATE),
/** Messages of the selected User (where he is an Author or a Sender only (e.g. for Reblog/Retweet).
* This User may be not the same as a user of current account ( {@link PersistentAccounts#getCurrentAccountName()} ).
* Moreover, the User may not be "AndStatus account" at all.
* Hence this timeline type requires the User parameter. */
USER("user", R.string.timeline_title_user, Connection.ApiRoutineEnum.STATUSES_USER_TIMELINE,
false, true,
UserTable.USER_TIMELINE_POSITION, UserTable.USER_TIMELINE_ITEM_DATE, UserTable.USER_TIMELINE_DATE),
/** For the selected user, the timeline includes all messages of the same origin irrespectively existence
* of the link between the message and the User. So the User may "Act" on this message. */
MESSAGES_TO_ACT("messages_to_act", R.string.timeline_title_home, Connection.ApiRoutineEnum.STATUSES_HOME_TIMELINE,
false, true,
"", "", ""),
/** Latest messages of every Friend of this user - AndStatus account
* (i.e of every user, followed by this User).
* So this is essentially a list of "Friends". See {@link FriendshipTable} */
FRIENDS("friends", R.string.friends, Connection.ApiRoutineEnum.DUMMY,
false, false,
"", "", UserTable.FOLLOWING_USER_DATE),
FOLLOWERS("followers", R.string.followers, Connection.ApiRoutineEnum.DUMMY, false, false,
"", "", UserTable.FOLLOWERS_USER_DATE),

REPLIES("replies", R.string.timeline_title_replies, Connection.ApiRoutineEnum.DUMMY,
FOLLOWERS("followers", R.string.followers, Connection.ApiRoutineEnum.DUMMY,
false, false,
"", "", ""),
"", "", UserTable.FOLLOWERS_USER_DATE),
PUBLIC("public", R.string.timeline_title_public, Connection.ApiRoutineEnum.PUBLIC_TIMELINE,
false, true,
"", "", ""),
EVERYTHING("everything", R.string.timeline_title_everything, Connection.ApiRoutineEnum.DUMMY,
false, true,
"", "", ""),
DRAFTS("drafts", R.string.timeline_title_drafts, Connection.ApiRoutineEnum.DUMMY,
false, false,
"", "", ""),
OUTBOX("outbox", R.string.timeline_title_outbox, Connection.ApiRoutineEnum.DUMMY,
false, false,
"", "", ""),
EVERYTHING("everything", R.string.timeline_title_everything, Connection.ApiRoutineEnum.DUMMY,
/** For the selected user, the timeline includes all messages of the same origin irrespectively existence
* of the link between the message and the User. So the User may "Act" on this message. */
MESSAGES_TO_ACT("messages_to_act", R.string.timeline_title_home, Connection.ApiRoutineEnum.STATUSES_HOME_TIMELINE,
false, true,
"", "", ""),
REPLIES("replies", R.string.timeline_title_replies, Connection.ApiRoutineEnum.DUMMY,
false, false,
"", "", ""),
/** All timelines (e.g. for download of all timelines.
* This is generally done after addition of the new MyAccount). */
ALL("all", R.string.timeline_title_all, Connection.ApiRoutineEnum.DUMMY,
false, false,
UserTable.HOME_TIMELINE_POSITION, UserTable.HOME_TIMELINE_ITEM_DATE, UserTable.HOME_TIMELINE_DATE);


public static final TimelineType[] defaultTimelineTypes = {
HOME,
FAVORITES,
MENTIONS,
DIRECT,
USER,
FRIENDS,
FOLLOWERS,
PUBLIC,
EVERYTHING,
DRAFTS,
OUTBOX
};

/** Code - identifier of the type */
private final String code;
/** The id of the string resource with the localized name of this enum to use in UI */
Expand All @@ -102,17 +116,17 @@ public enum TimelineType {
private final String columnNameTimelineDownloadedDate;
/** Api routine to download this timeline */
private final Connection.ApiRoutineEnum connectionApiRoutine;
private final boolean syncableAutomatically;
private final boolean syncableByDefault;
private final boolean atOrigin;

private TimelineType(String code, int resId, Connection.ApiRoutineEnum connectionApiRoutine,
boolean syncableAutomatically, boolean atOrigin,
String columnNameLatestTimelinePosition, String columnNameLatestTimelineItemDate,
String columnNameTimelineDownloadedDate) {
boolean syncableByDefault, boolean atOrigin,
String columnNameLatestTimelinePosition, String columnNameLatestTimelineItemDate,
String columnNameTimelineDownloadedDate) {
this.code = code;
this.titleResId = resId;
this.connectionApiRoutine = connectionApiRoutine;
this.syncableAutomatically = syncableAutomatically;
this.syncableByDefault = syncableByDefault;
this.atOrigin = atOrigin;
this.columnNameLatestTimelinePosition = columnNameLatestTimelinePosition;
this.columnNameLatestTimelineItemDate = columnNameLatestTimelineItemDate;
Expand Down Expand Up @@ -159,8 +173,8 @@ public CharSequence getPrepositionForNotCombinedTimeline(Context context) {
}
}

public boolean isSyncableAutomatically() {
return syncableAutomatically;
public boolean isSyncableByDefault() {
return syncableByDefault;
}

public boolean isAtOrigin() {
Expand Down

0 comments on commit 1ab5165

Please sign in to comment.