Many improvements

Removed cache, fixed bugs, implemented account switching

Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Danic 2017-11-07 13:20:09 +01:00
parent 643672a312
commit 40a27e55ec
14 changed files with 447 additions and 458 deletions

View File

@ -77,6 +77,10 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
return user;
}
public UserEntity getEntity() {
return userEntity;
}
@Override
public int getLayoutRes() {
return R.layout.rv_item_contact;

View File

@ -34,7 +34,6 @@ import com.nextcloud.talk.dagger.modules.DatabaseModule;
import com.nextcloud.talk.dagger.modules.RestModule;
import com.nextcloud.talk.jobs.PushRegistrationJob;
import com.nextcloud.talk.jobs.creator.MagicJobCreator;
import com.nextcloud.talk.utils.database.cache.CacheModule;
import com.nextcloud.talk.utils.database.user.UserModule;
import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;
@ -53,7 +52,6 @@ import autodagger.AutoInjector;
DatabaseModule.class,
RestModule.class,
UserModule.class,
CacheModule.class
}
)
@ -123,7 +121,6 @@ public class NextcloudTalkApplication extends MultiDexApplication {
.databaseModule(new DatabaseModule())
.restModule(new RestModule())
.userModule(new UserModule())
.cacheModule(new CacheModule())
.build();
}

View File

@ -146,6 +146,8 @@ public class AccountVerificationController extends BaseController {
new JobRequest.Builder(PushRegistrationJob.TAG).
setUpdateCurrent(true).startNow().build().schedule();
userUtils.disableAllUsersWithoutId(userEntity.getId());
if (userUtils.getUsers().size() == 1) {
getRouter().setRoot(RouterTransaction.with(new
BottomNavigationController(R.menu.menu_navigation))

View File

@ -48,19 +48,17 @@ import android.view.inputmethod.EditorInfo;
import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler;
import com.bluelinelabs.logansquare.LoganSquare;
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
import com.nextcloud.talk.R;
import com.nextcloud.talk.activities.CallActivity;
import com.nextcloud.talk.adapters.items.RoomItem;
import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.api.helpers.api.ApiHelper;
import com.nextcloud.talk.api.models.json.call.CallOverall;
import com.nextcloud.talk.api.models.json.rooms.Room;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.persistence.entities.UserEntity;
import com.nextcloud.talk.utils.bundle.BundleBuilder;
import com.nextcloud.talk.utils.database.cache.CacheUtils;
import com.nextcloud.talk.utils.database.user.UserUtils;
import java.util.ArrayList;
@ -84,16 +82,11 @@ public class CallsListController extends BaseController implements SearchView.On
public static final String TAG = "CallsListController";
private static final String KEY_FROM_RESTORE_CONTROLLER = "CallsListController.fromRestoreController";
private static final String KEY_FROM_RESTORE_VIEW = "CallsListController.fromRestoreView";
private static final String KEY_SEARCH_QUERY = "ContactsController.searchQuery";
@Inject
UserUtils userUtils;
@Inject
CacheUtils cacheUtils;
@Inject
NcApi ncApi;
@BindView(R.id.recycler_view)
@ -104,13 +97,9 @@ public class CallsListController extends BaseController implements SearchView.On
private UserEntity userEntity;
private Disposable roomsQueryDisposable;
private Disposable cacheQueryDisposable;
private FlexibleAdapter<RoomItem> adapter;
private List<RoomItem> roomItems = new ArrayList<>();
private boolean isFromRestoreView;
private boolean isFromRestoreController;
private MenuItem searchItem;
private SearchView searchView;
private String searchQuery;
@ -160,30 +149,20 @@ public class CallsListController extends BaseController implements SearchView.On
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
userEntity = userUtils.getCurrentUser();
if (adapter == null) {
adapter = new FlexibleAdapter<>(roomItems, getActivity(), false);
if (userEntity != null) {
fetchData();
}
}
adapter.addListener(onItemClickListener);
prepareViews();
if ((userEntity = userUtils.getCurrentUser()) != null) {
if (!adapter.hasSearchText()) {
if (!cacheUtils.cacheExistsForContext(TAG) || !isFromRestoreView) {
fetchData(true);
} else if (cacheUtils.cacheExistsForContext(TAG) && isFromRestoreController) {
fetchData(false);
}
}
} else {
// Fallback to login if we have no users
if (userEntity == null) {
if (getParentController() != null && getParentController().getRouter() != null) {
getParentController().getRouter().setRoot((RouterTransaction.with(new ServerSelectionController())
.pushChangeHandler(new HorizontalChangeHandler())
@ -192,6 +171,7 @@ public class CallsListController extends BaseController implements SearchView.On
}
}
private void initSearchView() {
if (getActivity() != null) {
SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
@ -259,84 +239,56 @@ public class CallsListController extends BaseController implements SearchView.On
}
}
private void fetchData(boolean forceNew) {
private void fetchData() {
dispose(null);
roomItems = new ArrayList<>();
if (forceNew) {
roomsQueryDisposable = ncApi.getRooms(ApiHelper.getCredentials(userEntity.getUsername(),
userEntity.getToken()), ApiHelper.getUrlForGetRooms(userEntity.getBaseUrl()))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(roomsOverall -> {
roomsQueryDisposable = ncApi.getRooms(ApiHelper.getCredentials(userEntity.getUsername(),
userEntity.getToken()), ApiHelper.getUrlForGetRooms(userEntity.getBaseUrl()))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(roomsOverall -> {
if (roomsOverall != null) {
for (int i = 0; i < roomsOverall.getOcs().getData().size(); i++) {
roomItems.add(new RoomItem(roomsOverall.getOcs().getData().get(i), userEntity));
}
adapter.updateDataSet(roomItems, true);
if (searchItem != null) {
searchItem.setVisible(roomItems.size() > 0);
}
cacheQueryDisposable = cacheUtils.createOrUpdateViewCache(
LoganSquare.serialize(roomsOverall.getOcs().getData()),
userEntity.getId(), TAG).subscribe(cacheEntity -> {
// do nothing
}, throwable -> dispose(cacheQueryDisposable),
() -> dispose(cacheQueryDisposable));
if (roomsOverall != null) {
for (int i = 0; i < roomsOverall.getOcs().getData().size(); i++) {
roomItems.add(new RoomItem(roomsOverall.getOcs().getData().get(i), userEntity));
}
}, throwable -> {
adapter.updateDataSet(roomItems, true);
if (searchItem != null) {
searchItem.setVisible(false);
searchItem.setVisible(roomItems.size() > 0);
}
}
}, throwable -> {
if (searchItem != null) {
searchItem.setVisible(false);
}
if (throwable instanceof HttpException) {
HttpException exception = (HttpException) throwable;
switch (exception.code()) {
case 401:
if (getParentController() != null &&
getParentController().getRouter() != null) {
getParentController().getRouter().setRoot((RouterTransaction.with
(new WebViewLoginController(userEntity.getBaseUrl(),
true))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler())));
}
break;
default:
break;
}
}
dispose(roomsQueryDisposable);
}, () -> {
dispose(roomsQueryDisposable);
if (swipeRefreshLayout != null) {
swipeRefreshLayout.setRefreshing(false);
}
});
} else {
cacheQueryDisposable = cacheUtils.getViewCache(userEntity.getId(), TAG)
.subscribe(o -> {
if (o != null) {
List<Room> rooms = LoganSquare.parseList(o.getValue(), Room.class);
for (Room room : rooms) {
roomItems.add(new RoomItem(room, userEntity));
}
adapter.updateDataSet(roomItems, true);
searchItem.setVisible(roomItems.size() > 0);
if (throwable instanceof HttpException) {
HttpException exception = (HttpException) throwable;
switch (exception.code()) {
case 401:
if (getParentController() != null &&
getParentController().getRouter() != null) {
getParentController().getRouter().pushController((RouterTransaction.with
(new WebViewLoginController(userEntity.getBaseUrl(),
true))
.pushChangeHandler(new VerticalChangeHandler())
.popChangeHandler(new VerticalChangeHandler())));
}
}, throwable -> {
if (searchItem != null) {
searchItem.setVisible(false);
}
dispose(cacheQueryDisposable);
},
() -> dispose(cacheQueryDisposable));
}
break;
default:
break;
}
}
dispose(roomsQueryDisposable);
}, () -> {
dispose(roomsQueryDisposable);
if (swipeRefreshLayout != null) {
swipeRefreshLayout.setRefreshing(false);
}
});
}
private void prepareViews() {
@ -351,7 +303,7 @@ public class CallsListController extends BaseController implements SearchView.On
layoutManager.getOrientation()
));
swipeRefreshLayout.setOnRefreshListener(() -> fetchData(true));
swipeRefreshLayout.setOnRefreshListener(this::fetchData);
swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);
}
@ -364,30 +316,12 @@ public class CallsListController extends BaseController implements SearchView.On
roomsQueryDisposable.dispose();
roomsQueryDisposable = null;
}
if (cacheQueryDisposable != null && !cacheQueryDisposable.isDisposed()) {
cacheQueryDisposable.dispose();
cacheQueryDisposable = null;
}
}
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(KEY_FROM_RESTORE_CONTROLLER, true);
}
@Override
public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
isFromRestoreController = savedInstanceState.getBoolean(KEY_FROM_RESTORE_CONTROLLER, false);
}
@Override
public void onSaveViewState(@NonNull View view, @NonNull Bundle outState) {
super.onSaveViewState(view, outState);
outState.putBoolean(KEY_FROM_RESTORE_VIEW, true);
if (searchView != null && !TextUtils.isEmpty(searchView.getQuery())) {
outState.putString(KEY_SEARCH_QUERY, searchView.getQuery().toString());
}
@ -396,7 +330,6 @@ public class CallsListController extends BaseController implements SearchView.On
@Override
public void onRestoreViewState(@NonNull View view, @NonNull Bundle savedViewState) {
super.onRestoreViewState(view, savedViewState);
isFromRestoreView = savedViewState.getBoolean(KEY_FROM_RESTORE_VIEW, false);
searchQuery = savedViewState.getString(KEY_SEARCH_QUERY, "");
}

View File

@ -46,19 +46,17 @@ import android.view.inputmethod.EditorInfo;
import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.bluelinelabs.logansquare.LoganSquare;
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
import com.nextcloud.talk.R;
import com.nextcloud.talk.adapters.items.UserItem;
import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.api.helpers.api.ApiHelper;
import com.nextcloud.talk.api.models.User;
import com.nextcloud.talk.api.models.json.sharees.Sharee;
import com.nextcloud.talk.api.models.json.sharees.SharesData;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.models.RetrofitBucket;
import com.nextcloud.talk.persistence.entities.UserEntity;
import com.nextcloud.talk.utils.database.cache.CacheUtils;
import com.nextcloud.talk.utils.database.user.UserUtils;
import java.util.ArrayList;
@ -82,16 +80,11 @@ public class ContactsController extends BaseController implements SearchView.OnQ
public static final String TAG = "ContactsController";
private static final String KEY_FROM_RESTORE_CONTROLLER = "ContactsController.fromRestoreController";
private static final String KEY_FROM_RESTORE_VIEW = "ContactsController.fromRestoreView";
private static final String KEY_SEARCH_QUERY = "ContactsController.searchQuery";
@Inject
UserUtils userUtils;
@Inject
CacheUtils cacheUtils;
@Inject
NcApi ncApi;
@BindView(R.id.recycler_view)
@ -106,9 +99,6 @@ public class ContactsController extends BaseController implements SearchView.OnQ
private FlexibleAdapter<UserItem> adapter;
private List<UserItem> contactItems = new ArrayList<>();
private boolean isFromRestoreController;
private boolean isFromRestoreView;
private MenuItem searchItem;
private SearchView searchView;
private String searchQuery;
@ -127,34 +117,31 @@ public class ContactsController extends BaseController implements SearchView.OnQ
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
userEntity = userUtils.getCurrentUser();
if (adapter == null) {
adapter = new FlexibleAdapter<>(contactItems, getActivity(), false);
if (userEntity != null) {
fetchData();
}
}
prepareViews();
if ((userEntity = userUtils.getCurrentUser()) != null) {
if (!adapter.hasSearchText()) {
if (!cacheUtils.cacheExistsForContext(TAG) || !isFromRestoreView) {
fetchData(true);
} else if (cacheUtils.cacheExistsForContext(TAG) && isFromRestoreController) {
fetchData(false);
}
}
} else {
// Fallback to login if we have no users
if (userEntity == null) {
if (getParentController().getRouter() != null) {
getParentController().getRouter().setRoot((RouterTransaction.with(new ServerSelectionController())
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler())));
}
}
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
}
private void initSearchView() {
@ -224,127 +211,77 @@ public class ContactsController extends BaseController implements SearchView.OnQ
}
}
private void fetchData(boolean forceNew) {
private void fetchData() {
dispose(null);
Set<Sharee> shareeHashSet = new HashSet<>();
contactItems = new ArrayList<>();
if (forceNew) {
RetrofitBucket retrofitBucket = ApiHelper.getRetrofitBucketForContactsSearch(userEntity.getBaseUrl(),
"");
contactsQueryDisposable = ncApi.getContactsWithSearchParam(
ApiHelper.getCredentials(userEntity.getUsername(), userEntity.getToken()),
retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(shareesOverall -> {
if (shareesOverall != null) {
RetrofitBucket retrofitBucket = ApiHelper.getRetrofitBucketForContactsSearch(userEntity.getBaseUrl(),
"");
contactsQueryDisposable = ncApi.getContactsWithSearchParam(
ApiHelper.getCredentials(userEntity.getUsername(), userEntity.getToken()),
retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(shareesOverall -> {
if (shareesOverall != null) {
if (shareesOverall.getOcs().getData().getUsers() != null) {
shareeHashSet.addAll(shareesOverall.getOcs().getData().getUsers());
}
if (shareesOverall.getOcs().getData().getExactUsers() != null &&
shareesOverall.getOcs().getData().getExactUsers().getExactSharees() != null) {
shareeHashSet.addAll(shareesOverall.getOcs().getData().
getExactUsers().getExactSharees());
}
User user;
for (Sharee sharee : shareeHashSet) {
if (!sharee.getValue().getShareWith().equals(userEntity.getUsername())) {
user = new User();
user.setName(sharee.getLabel());
user.setUserId(sharee.getValue().getShareWith());
contactItems.add(new UserItem(user, userEntity));
}
}
adapter.updateDataSet(contactItems, true);
searchItem.setVisible(contactItems.size() > 0);
cacheQueryDisposable = cacheUtils.createOrUpdateViewCache(
LoganSquare.serialize(shareesOverall.getOcs().getData()),
userEntity.getId(), TAG).subscribe(cacheEntity -> {
// do nothing
}, throwable -> dispose(cacheQueryDisposable),
() -> dispose(cacheQueryDisposable));
if (shareesOverall.getOcs().getData().getUsers() != null) {
shareeHashSet.addAll(shareesOverall.getOcs().getData().getUsers());
}
}, throwable -> {
if (searchItem != null) {
searchItem.setVisible(false);
if (shareesOverall.getOcs().getData().getExactUsers() != null &&
shareesOverall.getOcs().getData().getExactUsers().getExactSharees() != null) {
shareeHashSet.addAll(shareesOverall.getOcs().getData().
getExactUsers().getExactSharees());
}
if (throwable instanceof HttpException) {
HttpException exception = (HttpException) throwable;
switch (exception.code()) {
case 401:
if (getParentController() != null &&
getParentController().getRouter() != null) {
getParentController().getRouter().setRoot((RouterTransaction.with
(new WebViewLoginController(userEntity.getBaseUrl(),
true))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler())));
}
break;
default:
break;
User user;
for (Sharee sharee : shareeHashSet) {
if (!sharee.getValue().getShareWith().equals(userEntity.getUsername())) {
user = new User();
user.setName(sharee.getLabel());
user.setUserId(sharee.getValue().getShareWith());
contactItems.add(new UserItem(user, userEntity));
}
}
dispose(contactsQueryDisposable);
adapter.updateDataSet(contactItems, true);
searchItem.setVisible(contactItems.size() > 0);
}
, () -> {
swipeRefreshLayout.setRefreshing(false);
dispose(contactsQueryDisposable);
});
} else {
cacheQueryDisposable = cacheUtils.getViewCache(userEntity.getId(), TAG)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(o -> {
if (o != null) {
SharesData sharesData = LoganSquare.parse(o.getValue(), SharesData.class);
if (sharesData.getUsers() != null) {
shareeHashSet.addAll(sharesData.getUsers());
}
}, throwable -> {
if (searchItem != null) {
searchItem.setVisible(false);
}
if (sharesData.getExactUsers() != null && sharesData.getExactUsers()
.getExactSharees() != null) {
shareeHashSet.addAll(sharesData.getExactUsers().getExactSharees());
}
User user;
for (Sharee sharee : shareeHashSet) {
if (!sharee.getValue().getShareWith().equals(userEntity.getUsername())) {
user = new User();
user.setName(sharee.getLabel());
user.setUserId(sharee.getValue().getShareWith());
contactItems.add(new UserItem(user, userEntity));
if (throwable instanceof HttpException) {
HttpException exception = (HttpException) throwable;
switch (exception.code()) {
case 401:
if (getParentController() != null &&
getParentController().getRouter() != null) {
getParentController().getRouter().pushController((RouterTransaction.with
(new WebViewLoginController(userEntity.getBaseUrl(),
true))
.pushChangeHandler(new VerticalChangeHandler())
.popChangeHandler(new VerticalChangeHandler())));
}
}
adapter.updateDataSet(contactItems, true);
searchItem.setVisible(contactItems.size() > 0);
break;
default:
break;
}
}, throwable -> {
dispose(cacheQueryDisposable);
if (searchItem != null) {
searchItem.setVisible(false);
}
},
() -> {
dispose(cacheQueryDisposable);
});
}
}
dispose(contactsQueryDisposable);
}
, () -> {
swipeRefreshLayout.setRefreshing(false);
dispose(contactsQueryDisposable);
});
}
private void prepareViews() {
@ -358,7 +295,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ
layoutManager.getOrientation()
));
swipeRefreshLayout.setOnRefreshListener(() -> fetchData(true));
swipeRefreshLayout.setOnRefreshListener(this::fetchData);
swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);
}
@ -379,22 +316,9 @@ public class ContactsController extends BaseController implements SearchView.OnQ
}
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(KEY_FROM_RESTORE_CONTROLLER, true);
}
@Override
public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
isFromRestoreController = savedInstanceState.getBoolean(KEY_FROM_RESTORE_CONTROLLER, false);
}
@Override
public void onSaveViewState(@NonNull View view, @NonNull Bundle outState) {
super.onSaveViewState(view, outState);
outState.putBoolean(KEY_FROM_RESTORE_VIEW, true);
if (searchView != null && !TextUtils.isEmpty(searchView.getQuery())) {
outState.putString(KEY_SEARCH_QUERY, searchView.getQuery().toString());
}
@ -403,7 +327,6 @@ public class ContactsController extends BaseController implements SearchView.OnQ
@Override
public void onRestoreViewState(@NonNull View view, @NonNull Bundle savedViewState) {
super.onRestoreViewState(view, savedViewState);
isFromRestoreView = savedViewState.getBoolean(KEY_FROM_RESTORE_VIEW, false);
searchQuery = savedViewState.getString(KEY_SEARCH_QUERY, "");
}

View File

@ -25,6 +25,7 @@ import android.animation.AnimatorListenerAdapter;
import android.content.Intent;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
@ -37,6 +38,7 @@ import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.LazyHeaders;
import com.nextcloud.talk.BuildConfig;
import com.nextcloud.talk.R;
import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.api.helpers.api.ApiHelper;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController;
@ -66,6 +68,10 @@ import javax.inject.Inject;
import autodagger.AutoInjector;
import butterknife.BindView;
import cn.carbs.android.avatarimageview.library.AvatarImageView;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Credentials;
@AutoInjector(NextcloudTalkApplication.class)
public class SettingsController extends BaseController {
@ -97,7 +103,7 @@ public class SettingsController extends BaseController {
AvatarImageView avatarImageView;
@BindView(R.id.display_name_text)
TextView displayName;
TextView displayNameTextView;
@BindView(R.id.settings_remove_account)
MaterialStandardPreference removeAccountButton;
@ -123,12 +129,18 @@ public class SettingsController extends BaseController {
@Inject
AppPreferences appPreferences;
@Inject
NcApi ncApi;
@Inject
UserUtils userUtils;
private OnPreferenceValueChangedListener<String> proxyTypeChangeListener;
private OnPreferenceValueChangedListener<Boolean> proxyCredentialsChangeListener;
private Disposable profileQueryDisposable;
private Disposable dbQueryDisposable;
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_settings, container, false);
@ -138,6 +150,86 @@ public class SettingsController extends BaseController {
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
appPreferences.registerProxyTypeListener(proxyTypeChangeListener = new ProxyTypeChangeListener());
appPreferences.registerProxyCredentialsListener(proxyCredentialsChangeListener = new
ProxyCredentialsChangeListener());
List<String> listWithIntFields = new ArrayList<>();
listWithIntFields.add("proxy_port");
settingsScreen.setUserInputModule(new MagicUserInputModule(getActivity(), listWithIntFields));
settingsScreen.setVisibilityController(R.id.settings_proxy_use_credentials,
Arrays.asList(R.id.settings_proxy_username_edit, R.id.settings_proxy_password_edit),
true);
if (!TextUtils.isEmpty(getResources().getString(R.string.nc_gpl3_url))) {
licenceButton.setOnClickListener(view1 -> {
sourceCodeButton.setEnabled(false);
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getResources().
getString(R.string.nc_gpl3_url)));
startActivity(browserIntent);
sourceCodeButton.setEnabled(true);
});
} else {
licenceButton.setVisibility(View.GONE);
}
if (!TextUtils.isEmpty(getResources().getString(R.string.nc_privacy_url))) {
privacyButton.setOnClickListener(view12 -> {
sourceCodeButton.setEnabled(false);
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getResources().
getString(R.string.nc_privacy_url)));
startActivity(browserIntent);
sourceCodeButton.setEnabled(true);
});
} else {
privacyButton.setVisibility(View.GONE);
}
if (!TextUtils.isEmpty(getResources().getString(R.string.nc_source_code_url))) {
sourceCodeButton.setOnClickListener(view13 -> {
sourceCodeButton.setEnabled(false);
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getResources().
getString(R.string.nc_source_code_url)));
startActivity(browserIntent);
sourceCodeButton.setEnabled(true);
});
} else {
sourceCodeButton.setVisibility(View.GONE);
}
versionInfo.setSummary("v" + BuildConfig.VERSION_NAME);
UserEntity userEntity = userUtils.getCurrentUser();
if (userEntity != null) {
reauthorizeButton.setOnClickListener(view14 -> {
reauthorizeButton.setEnabled(false);
getParentController().getRouter().pushController(RouterTransaction.with(
new WebViewLoginController(userEntity.getBaseUrl(), true))
.pushChangeHandler(new VerticalChangeHandler())
.popChangeHandler(new VerticalChangeHandler()));
reauthorizeButton.setEnabled(true);
});
}
addAccountButton.setOnClickListener(view15 -> {
addAccountButton.setEnabled(false);
getParentController().getRouter().pushController(RouterTransaction.with(new
ServerSelectionController()).pushChangeHandler(new VerticalChangeHandler())
.popChangeHandler(new VerticalChangeHandler()));
addAccountButton.setEnabled(true);
});
switchAccountButton.setOnClickListener(view16 -> {
switchAccountButton.setEnabled(false);
getParentController().getRouter().pushController(RouterTransaction.with(new
SwitchAccountController()).pushChangeHandler(new VerticalChangeHandler())
.popChangeHandler(new VerticalChangeHandler()));
switchAccountButton.setEnabled(true);
});
}
@Override
@ -156,55 +248,14 @@ public class SettingsController extends BaseController {
hideProxyCredentials();
}
appPreferences.registerProxyTypeListener(proxyTypeChangeListener = new ProxyTypeChangeListener());
appPreferences.registerProxyCredentialsListener(proxyCredentialsChangeListener = new
ProxyCredentialsChangeListener());
List<String> listWithIntFields = new ArrayList<>();
listWithIntFields.add("proxy_port");
settingsScreen.setUserInputModule(new MagicUserInputModule(getActivity(), listWithIntFields));
settingsScreen.setVisibilityController(R.id.settings_proxy_use_credentials,
Arrays.asList(R.id.settings_proxy_username_edit, R.id.settings_proxy_password_edit),
true);
if (!TextUtils.isEmpty(getResources().getString(R.string.nc_gpl3_url))) {
licenceButton.setOnClickListener(view1 -> {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getResources().
getString(R.string.nc_gpl3_url)));
startActivity(browserIntent);
});
} else {
licenceButton.setVisibility(View.GONE);
}
if (!TextUtils.isEmpty(getResources().getString(R.string.nc_privacy_url))) {
privacyButton.setOnClickListener(view12 -> {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getResources().
getString(R.string.nc_privacy_url)));
startActivity(browserIntent);
});
} else {
privacyButton.setVisibility(View.GONE);
}
if (!TextUtils.isEmpty(getResources().getString(R.string.nc_source_code_url))) {
sourceCodeButton.setOnClickListener(view13 -> {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getResources().
getString(R.string.nc_source_code_url)));
startActivity(browserIntent);
});
} else {
sourceCodeButton.setVisibility(View.GONE);
}
versionInfo.setSummary("v" + BuildConfig.VERSION_NAME);
UserEntity userEntity = userUtils.getCurrentUser();
if (userEntity != null) {
// Awful hack
avatarImageView.setTextAndColorSeed(String.valueOf(userEntity.getDisplayName().
toUpperCase().charAt(0)), ColorUtils.colorSeed);
if (userEntity.getDisplayName() != null) {
avatarImageView.setTextAndColorSeed(String.valueOf(userEntity.getDisplayName().
toUpperCase().charAt(0)), ColorUtils.colorSeed);
displayNameTextView.setText(userEntity.getDisplayName());
}
GlideUrl glideUrl = new GlideUrl(ApiHelper.getUrlForAvatarWithName(userEntity.getBaseUrl(),
userEntity.getUsername()), new LazyHeaders.Builder()
@ -218,40 +269,58 @@ public class SettingsController extends BaseController {
.centerInside()
.into(avatarImageView);
displayName.setText(userEntity.getDisplayName());
profileQueryDisposable = ncApi.getUserProfile(Credentials.basic(userEntity.getUsername(),
userEntity.getToken()),
ApiHelper.getUrlForUserProfile(userEntity.getBaseUrl()))
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(userProfileOverall -> {
String displayName = null;
if (!TextUtils.isEmpty(userProfileOverall.getOcs().getData()
.getDisplayName())) {
displayName = userProfileOverall.getOcs().getData()
.getDisplayName();
} else if (!TextUtils.isEmpty(userProfileOverall.getOcs().getData()
.getDisplayNameAlt())) {
displayName = userProfileOverall.getOcs().getData()
.getDisplayNameAlt();
}
if (!TextUtils.isEmpty(displayName) && !displayName.equals(userEntity.getDisplayName())) {
dbQueryDisposable = userUtils.createOrUpdateUser(userEntity.getUsername(),
userEntity.getToken(),
userEntity.getBaseUrl(), displayName, null, true)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(userEntityResult -> {
displayNameTextView.setText(userEntityResult.getDisplayName());
},
throwable -> {
dispose(dbQueryDisposable);
}, () -> dispose(dbQueryDisposable));
}
}, throwable -> {
dispose(profileQueryDisposable);
}, () -> dispose(profileQueryDisposable));
}
if (userUtils.getUsers().size() <= 1) {
switchAccountButton.setVisibility(View.GONE);
}
reauthorizeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
getParentController().getRouter().pushController(RouterTransaction.with(
new WebViewLoginController(userEntity.getBaseUrl(), true))
.pushChangeHandler(new VerticalChangeHandler())
.popChangeHandler(new VerticalChangeHandler()));
}
});
addAccountButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
getParentController().getRouter().pushController(RouterTransaction.with(new
ServerSelectionController()).pushChangeHandler(new VerticalChangeHandler())
.popChangeHandler(new VerticalChangeHandler()));
}
});
if (SettingsMessageHolder.getInstance().getMessageType() != null) {
switch (SettingsMessageHolder.getInstance().getMessageType()) {
case ACCOUNT_UPDATED_NOT_ADDED:
messageText.setTextColor(getResources().getColor(R.color.colorPrimary));
messageText.setText(getResources().getString(R.string.nc_settings_account_updated));
messageView.setVisibility(View.VISIBLE);
break;
case WRONG_ACCOUNT:
messageText.setTextColor(getResources().getColor(R.color.darkRed));
messageText.setText(getResources().getString(R.string.nc_settings_wrong_account));
messageView.setVisibility(View.VISIBLE);
break;
@ -264,7 +333,7 @@ public class SettingsController extends BaseController {
messageView.animate()
.translationY(0)
.alpha(0.0f)
.setDuration(2000)
.setDuration(2500)
.setStartDelay(5000)
.setListener(new AnimatorListenerAdapter() {
@Override
@ -318,6 +387,23 @@ public class SettingsController extends BaseController {
settingsScreen.findViewById(R.id.settings_proxy_password_edit).setVisibility(View.GONE);
}
private void dispose(@Nullable Disposable disposable) {
if (disposable != null && !disposable.isDisposed()) {
disposable.dispose();
} else if (disposable == null) {
if (profileQueryDisposable != null && !profileQueryDisposable.isDisposed()) {
profileQueryDisposable.dispose();
profileQueryDisposable = null;
}
if (dbQueryDisposable != null && !dbQueryDisposable.isDisposed()) {
dbQueryDisposable.dispose();
dbQueryDisposable = null;
}
}
}
private class ProxyCredentialsChangeListener implements OnPreferenceValueChangedListener<Boolean> {
@Override
@ -355,4 +441,10 @@ public class SettingsController extends BaseController {
}
}
}
@Override
protected String getTitle() {
return getResources().getString(R.string.nc_app_name);
}
}

View File

@ -0,0 +1,158 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017 Mario Danic <mario@lovelyhq.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 com.nextcloud.talk.controllers;
import android.support.annotation.NonNull;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.nextcloud.talk.R;
import com.nextcloud.talk.adapters.items.UserItem;
import com.nextcloud.talk.api.models.User;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.persistence.entities.UserEntity;
import com.nextcloud.talk.utils.database.user.UserUtils;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import autodagger.AutoInjector;
import butterknife.BindView;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
@AutoInjector(NextcloudTalkApplication.class)
public class SwitchAccountController extends BaseController {
@Inject
UserUtils userUtils;
@BindView(R.id.recycler_view)
RecyclerView recyclerView;
@BindView(R.id.swipe_refresh_layout)
SwipeRefreshLayout swipeRefreshLayout;
private FlexibleAdapter<UserItem> adapter;
private List<UserItem> userItems = new ArrayList<>();
private FlexibleAdapter.OnItemClickListener onItemClickListener =
new FlexibleAdapter.OnItemClickListener() {
@Override
public boolean onItemClick(int position) {
if (userItems.size() > position) {
UserEntity userEntity = userItems.get(position).getEntity();
userUtils.createOrUpdateUser(userEntity.getUsername(),
userEntity.getToken(), userEntity.getBaseUrl(), null,
null, true)
.subscribe(new Observer<UserEntity>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(UserEntity userEntity) {
userUtils.disableAllUsersWithoutId(userEntity.getId());
getRouter().popCurrentController();
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
return true;
}
};
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_generic_rv, container, false);
}
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
swipeRefreshLayout.setEnabled(false);
if (adapter == null) {
adapter = new FlexibleAdapter<>(userItems, getActivity(), false);
UserEntity userEntity;
User user;
UserEntity currentUserEntity = userUtils.getCurrentUser();
for(Object userEntityObject : userUtils.getUsers()) {
userEntity = (UserEntity) userEntityObject;
if (!userEntity.equals(currentUserEntity)) {
user = new User();
user.setName(userEntity.getDisplayName());
user.setUserId(userEntity.getUsername());
userItems.add(new UserItem(user, userEntity));
}
}
adapter.addListener(onItemClickListener);
adapter.updateDataSet(userItems, false);
}
prepareViews();
}
private void prepareViews() {
LinearLayoutManager layoutManager = new SmoothScrollLinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
recyclerView.addItemDecoration(new DividerItemDecoration(
recyclerView.getContext(),
layoutManager.getOrientation()
));
swipeRefreshLayout.setEnabled(false);
}
@Override
protected String getTitle() {
return getResources().getString(R.string.nc_select_an_account);
}
}

View File

@ -238,7 +238,7 @@ public class WebViewLoginController extends BaseController {
userQueryDisposable = userUtils.createOrUpdateUser(loginData.getUsername(), loginData.getToken(),
baseUrl, null, null, true).
subscribe(userEntity -> {
if (!isPasswordUpdate && !userUtils.anyUserExists()) {
if (!isPasswordUpdate && finalSettingsMessageType == null) {
BundleBuilder bundleBuilder = new BundleBuilder(new Bundle());
bundleBuilder.putString(BundleKeys.KEY_USERNAME, userEntity.getUsername());
bundleBuilder.putString(BundleKeys.KEY_TOKEN, userEntity.getToken());
@ -265,7 +265,7 @@ public class WebViewLoginController extends BaseController {
LoginData loginData = new LoginData();
// format is xxx://login/server:xxx&user:xxx&password:xxx
// format is xxx://login/server1:xxx&user:xxx&password:xxx
String data = dataString.substring(prefix.length());
String[] values = data.split("&");

View File

@ -24,4 +24,5 @@ public class BundleKeys {
public static final String KEY_USERNAME = "KEY_USERNAME";
public static final String KEY_TOKEN = "KEY_TOKEN";
public static final String KEY_BASE_URL = "KEY_BASE_URL";
public static final String KEY_SETTINGS_MESSAGE = "KEY_SETTINGS_MESSAGE";
}

View File

@ -1,47 +0,0 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017 Mario Danic (mario@lovelyhq.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 com.nextcloud.talk.utils.database.cache;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.dagger.modules.DatabaseModule;
import javax.inject.Inject;
import autodagger.AutoInjector;
import dagger.Module;
import dagger.Provides;
import io.requery.Persistable;
import io.requery.reactivex.ReactiveEntityStore;
@Module(includes = DatabaseModule.class)
@AutoInjector(NextcloudTalkApplication.class)
public class CacheModule {
@Inject
public CacheModule() {
}
@Provides
public CacheUtils provideCacheUtils(ReactiveEntityStore<Persistable> dataStore) {
return new CacheUtils(dataStore);
}
}

View File

@ -1,72 +0,0 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017 Mario Danic (mario@lovelyhq.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 com.nextcloud.talk.utils.database.cache;
import com.nextcloud.talk.persistence.entities.Cache;
import com.nextcloud.talk.persistence.entities.CacheEntity;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import io.requery.Persistable;
import io.requery.query.Result;
import io.requery.reactivex.ReactiveEntityStore;
public class CacheUtils {
private ReactiveEntityStore<Persistable> dataStore;
CacheUtils(ReactiveEntityStore<Persistable> dataStore) {
this.dataStore = dataStore;
}
public boolean cacheExistsForContext(String context) {
return (dataStore.count(Cache.class).where(CacheEntity.KEY.eq(context)).limit(1).get().value() > 0);
}
public Observable<CacheEntity> getViewCache(Long userId, String context) {
return dataStore.select(CacheEntity.class).where(CacheEntity.KEY.eq(context).
and(CacheEntity.USER_ID.eq(userId))).limit(1).get().observable()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
}
public Observable<CacheEntity> createOrUpdateViewCache(String cache, Long userId, String context) {
Result findUserQueryResult = dataStore.select(CacheEntity.class).where(CacheEntity.KEY.eq(context).
and(CacheEntity.USER_ID.eq(userId))).limit(1).get();
CacheEntity cacheEntity = (CacheEntity) findUserQueryResult.firstOrNull();
if (cacheEntity == null) {
cacheEntity = new CacheEntity();
cacheEntity.setKey(context);
cacheEntity.setUserId(userId);
cacheEntity.setValue(cache);
} else {
cacheEntity.setValue(cache);
}
return dataStore.upsert(cacheEntity)
.toObservable()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
}
}

View File

@ -75,7 +75,7 @@ public class UserUtils {
}
private void disableAllUsersWithoutId(long userId) {
public void disableAllUsersWithoutId(long userId) {
Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.ID.notEqual(userId))
.and(UserEntity.CURRENT.eq(true)).get();
@ -93,6 +93,7 @@ public class UserUtils {
return findUserQueryResult.firstOrNull() != null;
}
public Observable<UserEntity> createOrUpdateUser(String username, String token, String serverUrl,
@Nullable String displayName,
@Nullable String pushConfigurationState,
@ -133,10 +134,6 @@ public class UserUtils {
if (currentUser != null) {
user.setCurrent(currentUser);
if (currentUser) {
disableAllUsersWithoutId(user.getId());
}
}
}

View File

@ -35,8 +35,7 @@
android:id="@+id/message_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/darkRed"/>
android:gravity="center"/>
</com.yarolegovich.mp.MaterialPreferenceCategory>
<com.yarolegovich.mp.MaterialPreferenceCategory

View File

@ -58,4 +58,6 @@
<string name="nc_get_source_code">Get source code</string>
<string name="nc_license_title">License</string>
<string name="nc_license_summary">GNU General Public License, Version 3</string>
<string name="nc_select_an_account">Select an account</string>
</resources>