mirror of https://github.com/nextcloud/android
New user info: viewModel, model, repository
split up code use data binding add groups Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
This commit is contained in:
parent
468899522e
commit
22d6979f7e
|
@ -191,4 +191,4 @@
|
|||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
</component>
|
||||
|
|
|
@ -244,6 +244,10 @@ android {
|
|||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
dataBinding {
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
@ -278,6 +282,8 @@ dependencies {
|
|||
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.15'
|
||||
implementation 'com.github.tobiaskaminsky:qrcodescanner:0.1.2.2' // 'com.github.blikoon:QRCodeScanner:0.1.2'
|
||||
implementation 'com.google.android:flexbox:1.1.0'
|
||||
implementation group: 'android.arch.lifecycle', name: 'extensions', version: '1.1.1'
|
||||
|
||||
implementation 'org.parceler:parceler-api:1.1.12'
|
||||
kapt 'org.parceler:parceler:1.1.12'
|
||||
implementation('com.github.bumptech.glide:glide:3.7.0') {
|
||||
|
@ -314,6 +320,7 @@ dependencies {
|
|||
testImplementation 'org.json:json:20190722'
|
||||
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0"
|
||||
testImplementation "androidx.arch.core:core-testing:2.0.1"
|
||||
testImplementation 'org.mockito:mockito-core:2.24.0'
|
||||
|
||||
// dependencies for instrumented tests
|
||||
// JUnit4 Rules
|
||||
|
@ -332,6 +339,7 @@ dependencies {
|
|||
//androidTestImplementation "com.android.support:support-annotations:${supportLibraryVersion}"
|
||||
androidTestImplementation 'tools.fastlane:screengrab:1.2.0'
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
|
||||
|
||||
// jacocoAnt "org.jacoco:org.jacoco.ant:${jacocoVersion}"
|
||||
// jacocoAgent "org.jacoco:org.jacoco.agent:${jacocoVersion}"
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="16" viewBox="0 0 16 16" width="16" version="1.1"><path d="m8 1c-3.86 0-7 3.15-7 7s3.15 7 7 7c3.86 0 7-3.15 7-7 0-3.86-3.15-7-7-7zm0 1.75c2.91 0 5.25 2.34 5.25 5.25 0 1.42-0.56 2.7-1.47 3.644l-3.78-3.644z"/></svg>
|
After Width: | Height: | Size: 261 B |
|
@ -5,4 +5,5 @@ NC_TEST_SERVER_PASSWORD=test
|
|||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
||||
android.debug.obsoleteApi=true
|
||||
android.databinding.enableV2=true
|
||||
|
||||
|
|
|
@ -119,7 +119,9 @@
|
|||
<meta-data android:name="android.app.searchable"
|
||||
android:resource="@xml/users_and_groups_searchable"/>
|
||||
</activity>
|
||||
<activity android:name=".ui.activity.ManageAccountsActivity" />
|
||||
<activity
|
||||
android:name=".ui.activity.ManageAccountsActivity"
|
||||
android:exported="true" />
|
||||
<activity android:name=".ui.activity.UserInfoActivity" />
|
||||
<activity android:name=".ui.activity.NotificationsActivity"/>
|
||||
<activity android:name=".ui.activity.ParticipateActivity" />
|
||||
|
|
|
@ -48,8 +48,11 @@ import com.owncloud.android.ui.activities.data.activities.RemoteActivitiesReposi
|
|||
import com.owncloud.android.ui.activities.data.files.FilesRepository;
|
||||
import com.owncloud.android.ui.activities.data.files.FilesServiceApiImpl;
|
||||
import com.owncloud.android.ui.activities.data.files.RemoteFilesRepository;
|
||||
import com.owncloud.android.ui.viewModel.UserInfoViewModel;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
|
@ -146,4 +149,15 @@ class AppModule {
|
|||
Handler uiHandler = new Handler();
|
||||
return new AsyncRunnerImpl(uiHandler, 4);
|
||||
}
|
||||
|
||||
@Provides
|
||||
public Executor executor() {
|
||||
return Executors.newCachedThreadPool();
|
||||
}
|
||||
|
||||
|
||||
@Provides
|
||||
public UserInfoViewModel userInfoViewModel() {
|
||||
return new UserInfoViewModel();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,8 +35,10 @@ import android.os.RemoteException;
|
|||
import android.provider.MediaStore;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
|
||||
import com.owncloud.android.lib.common.Quota;
|
||||
import com.owncloud.android.lib.common.network.WebdavEntry;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
|
@ -1083,7 +1085,7 @@ public class FileDataStorageManager {
|
|||
|
||||
|
||||
/**
|
||||
* Checks the existance of an stored {@link OCShare} matching the given remote id (not to be confused with
|
||||
* Checks the existence of an stored {@link OCShare} matching the given remote id (not to be confused with
|
||||
* the local id) in the current account.
|
||||
*
|
||||
* @param remoteId Remote of the share in the server.
|
||||
|
@ -1095,7 +1097,7 @@ public class FileDataStorageManager {
|
|||
|
||||
|
||||
/**
|
||||
* Checks the existance of an stored {@link OCShare} in the current account
|
||||
* Checks the existence of an stored {@link OCShare} in the current account
|
||||
* matching a given column and a value for that column
|
||||
*
|
||||
* @param key Name of the column to match.
|
||||
|
@ -2273,4 +2275,113 @@ public class FileDataStorageManager {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean userInfoExists(String accountName) {
|
||||
Cursor c = getUserInfoCursorForAccount(accountName);
|
||||
boolean exists = false;
|
||||
if (c != null) {
|
||||
exists = c.moveToFirst();
|
||||
c.close();
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
|
||||
private Cursor getUserInfoCursorForAccount(String accountName) {
|
||||
Cursor c = null;
|
||||
if (getContentResolver() != null) {
|
||||
c = getContentResolver()
|
||||
.query(ProviderTableMeta.CONTENT_URI_USERINFO,
|
||||
null,
|
||||
ProviderTableMeta.USERINFO_ACCOUNT + "=? ",
|
||||
new String[]{accountName}, null);
|
||||
} else {
|
||||
try {
|
||||
c = getContentProviderClient().query(
|
||||
ProviderTableMeta.CONTENT_URI_USERINFO,
|
||||
null,
|
||||
ProviderTableMeta.USERINFO_ACCOUNT + "=? ",
|
||||
new String[]{accountName}, null);
|
||||
} catch (RemoteException e) {
|
||||
Log_OC.e(TAG, "Couldn't determine userinfo existence, assuming non existence: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
public UserInfo saveUserInfo(UserInfo userInfo) {
|
||||
// Prepare userInfo data
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(ProviderTableMeta.USERINFO_ACCOUNT, userInfo.getAccount());
|
||||
cv.put(ProviderTableMeta.USERINFO_DISPLAYNAME, userInfo.getDisplayName());
|
||||
cv.put(ProviderTableMeta.USERINFO_EMAIL, userInfo.getEmail());
|
||||
cv.put(ProviderTableMeta.USERINFO_PHONE, userInfo.getPhone());
|
||||
cv.put(ProviderTableMeta.USERINFO_ADDRESS, userInfo.getAddress());
|
||||
cv.put(ProviderTableMeta.USERINFO_WEBSITE, userInfo.getWebsite());
|
||||
cv.put(ProviderTableMeta.USERINFO_TWITTER, userInfo.getTwitter());
|
||||
cv.put(ProviderTableMeta.USERINFO_GROUPS, TextUtils.join(",", userInfo.getGroups()));
|
||||
cv.put(ProviderTableMeta.USERINFO_QUOTA, new Gson().toJson(userInfo.getQuota()));
|
||||
|
||||
if (userInfoExists(account.name)) {
|
||||
if (getContentResolver() != null) {
|
||||
getContentResolver().update(ProviderTableMeta.CONTENT_URI_USERINFO, cv,
|
||||
ProviderTableMeta.CAPABILITIES_ACCOUNT_NAME + "=?",
|
||||
new String[]{account.name});
|
||||
} else {
|
||||
try {
|
||||
getContentProviderClient().update(ProviderTableMeta.CONTENT_URI_USERINFO,
|
||||
cv, ProviderTableMeta.CAPABILITIES_ACCOUNT_NAME + "=?",
|
||||
new String[]{account.name});
|
||||
} catch (RemoteException e) {
|
||||
Log_OC.e(TAG, FAILED_TO_INSERT_MSG + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (getContentResolver() != null) {
|
||||
getContentResolver().insert(ProviderTableMeta.CONTENT_URI_USERINFO, cv);
|
||||
} else {
|
||||
try {
|
||||
getContentProviderClient().insert(ProviderTableMeta.CONTENT_URI_USERINFO, cv);
|
||||
} catch (RemoteException e) {
|
||||
Log_OC.e(TAG, FAILED_TO_INSERT_MSG + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public UserInfo getUserInfo(String accountName) {
|
||||
UserInfo userInfo;
|
||||
Cursor c = getUserInfoCursorForAccount(accountName);
|
||||
|
||||
if (c.moveToFirst()) {
|
||||
userInfo = createUserInfoInstance(c);
|
||||
} else {
|
||||
userInfo = new UserInfo();
|
||||
}
|
||||
c.close();
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
private UserInfo createUserInfoInstance(Cursor c) {
|
||||
UserInfo userInfo = new UserInfo();
|
||||
|
||||
if (c != null) {
|
||||
userInfo.setDisplayName(c.getString(c.getColumnIndex(ProviderTableMeta.USERINFO_DISPLAYNAME)));
|
||||
userInfo.setEmail(c.getString(c.getColumnIndex(ProviderTableMeta.USERINFO_EMAIL)));
|
||||
userInfo.setPhone(c.getString(c.getColumnIndex(ProviderTableMeta.USERINFO_PHONE)));
|
||||
userInfo.setAddress(c.getString(c.getColumnIndex(ProviderTableMeta.USERINFO_ADDRESS)));
|
||||
userInfo.setWebsite(c.getString(c.getColumnIndex(ProviderTableMeta.USERINFO_WEBSITE)));
|
||||
userInfo.setTwitter(c.getString(c.getColumnIndex(ProviderTableMeta.USERINFO_TWITTER)));
|
||||
|
||||
String groups = c.getString(c.getColumnIndex(ProviderTableMeta.USERINFO_GROUPS));
|
||||
userInfo.setGroups(new ArrayList<>(Arrays.asList(groups.split(","))));
|
||||
|
||||
String quotaJson = c.getString(c.getColumnIndex(ProviderTableMeta.USERINFO_QUOTA));
|
||||
userInfo.setQuota(new Gson().fromJson(quotaJson, Quota.class));
|
||||
}
|
||||
|
||||
return userInfo;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
package com.owncloud.android.datamodel;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.owncloud.android.lib.common.Quota;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class UserInfo {
|
||||
public String account = "";
|
||||
public Boolean enabled;
|
||||
public String displayName;
|
||||
public String email;
|
||||
public String phone;
|
||||
public String address;
|
||||
public String website;
|
||||
public String twitter;
|
||||
@Getter @Setter public ArrayList<String> groups;
|
||||
public Quota quota;
|
||||
|
||||
@NonNull
|
||||
public String getAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
public void setAccount(@NonNull String account) {
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
public Boolean getEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(Boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getWebsite() {
|
||||
return website;
|
||||
}
|
||||
|
||||
public void setWebsite(String website) {
|
||||
this.website = website;
|
||||
}
|
||||
|
||||
public String getTwitter() {
|
||||
return twitter;
|
||||
}
|
||||
|
||||
public void setTwitter(String twitter) {
|
||||
this.twitter = twitter;
|
||||
}
|
||||
|
||||
public Quota getQuota() {
|
||||
return quota;
|
||||
}
|
||||
|
||||
public void setQuota(Quota quota) {
|
||||
this.quota = quota;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return TextUtils.isEmpty(phone) && TextUtils.isEmpty(email) && TextUtils.isEmpty(address) &&
|
||||
TextUtils.isEmpty(twitter) && TextUtils.isEmpty(website) && (groups == null || groups.size() == 0);
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ import com.owncloud.android.MainApp;
|
|||
*/
|
||||
public class ProviderMeta {
|
||||
public static final String DB_NAME = "filelist";
|
||||
public static final int DB_VERSION = 49;
|
||||
public static final int DB_VERSION = 50;
|
||||
|
||||
private ProviderMeta() {
|
||||
// No instance
|
||||
|
@ -47,6 +47,7 @@ public class ProviderMeta {
|
|||
public static final String ARBITRARY_DATA_TABLE_NAME = "arbitrary_data";
|
||||
public static final String VIRTUAL_TABLE_NAME = "virtual";
|
||||
public static final String FILESYSTEM_TABLE_NAME = "filesystem";
|
||||
public static final String USERINFO_TABLE_NAME = "userinfo";
|
||||
|
||||
private static final String CONTENT_PREFIX = "content://";
|
||||
|
||||
|
@ -71,6 +72,7 @@ public class ProviderMeta {
|
|||
public static final Uri CONTENT_URI_VIRTUAL = Uri.parse(CONTENT_PREFIX + MainApp.getAuthority() + "/virtual");
|
||||
public static final Uri CONTENT_URI_FILESYSTEM = Uri.parse(CONTENT_PREFIX
|
||||
+ MainApp.getAuthority() + "/filesystem");
|
||||
public static final Uri CONTENT_URI_USERINFO = Uri.parse(CONTENT_PREFIX + MainApp.getAuthority() + "/userinfo");
|
||||
|
||||
|
||||
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.owncloud.file";
|
||||
|
@ -238,7 +240,6 @@ public class ProviderMeta {
|
|||
public static final String ARBITRARY_DATA_KEY = "key";
|
||||
public static final String ARBITRARY_DATA_VALUE = "value";
|
||||
|
||||
|
||||
// Columns of virtual
|
||||
public static final String VIRTUAL_TYPE = "type";
|
||||
public static final String VIRTUAL_OCFILE_ID = "ocfile_id";
|
||||
|
@ -252,6 +253,17 @@ public class ProviderMeta {
|
|||
public static final String FILESYSTEM_SYNCED_FOLDER_ID = "syncedfolder_id";
|
||||
public static final String FILESYSTEM_CRC32 = "crc32";
|
||||
|
||||
// Columns of userinfo table
|
||||
public static final String USERINFO_ACCOUNT = "account";
|
||||
public static final String USERINFO_DISPLAYNAME = "displayname";
|
||||
public static final String USERINFO_EMAIL = "email";
|
||||
public static final String USERINFO_PHONE = "phone";
|
||||
public static final String USERINFO_ADDRESS = "address";
|
||||
public static final String USERINFO_WEBSITE = "website";
|
||||
public static final String USERINFO_TWITTER = "twitter";
|
||||
public static final String USERINFO_GROUPS = "groups";
|
||||
public static final String USERINFO_QUOTA = "quota";
|
||||
|
||||
private ProviderTableMeta() {
|
||||
// No instance
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ public class FileContentProvider extends ContentProvider {
|
|||
private static final int ARBITRARY_DATA = 9;
|
||||
private static final int VIRTUAL = 10;
|
||||
private static final int FILESYSTEM = 11;
|
||||
private static final int USERINFO = 12;
|
||||
private static final String TAG = FileContentProvider.class.getSimpleName();
|
||||
// todo avoid string concatenation and use string formatting instead later.
|
||||
private static final String ERROR = "ERROR ";
|
||||
|
@ -153,6 +154,9 @@ public class FileContentProvider extends ContentProvider {
|
|||
case FILESYSTEM:
|
||||
count = db.delete(ProviderTableMeta.FILESYSTEM_TABLE_NAME, where, whereArgs);
|
||||
break;
|
||||
case USERINFO:
|
||||
count = db.delete(ProviderTableMeta.USERINFO_TABLE_NAME, where, whereArgs);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(String.format(Locale.US, "Unknown uri: %s", uri.toString()));
|
||||
}
|
||||
|
@ -370,6 +374,16 @@ public class FileContentProvider extends ContentProvider {
|
|||
throw new SQLException("ERROR " + uri);
|
||||
}
|
||||
return insertedFilesystemUri;
|
||||
case USERINFO:
|
||||
Uri insertedUserInfoUri;
|
||||
long insertedUserInfoId = db.insert(ProviderTableMeta.USERINFO_TABLE_NAME, null, values);
|
||||
if (insertedUserInfoId > 0) {
|
||||
insertedUserInfoUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_USERINFO,
|
||||
insertedUserInfoId);
|
||||
} else {
|
||||
throw new SQLException("ERROR " + uri);
|
||||
}
|
||||
return insertedUserInfoUri;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown uri id: " + uri);
|
||||
}
|
||||
|
@ -432,6 +446,7 @@ public class FileContentProvider extends ContentProvider {
|
|||
mUriMatcher.addURI(authority, "arbitrary_data", ARBITRARY_DATA);
|
||||
mUriMatcher.addURI(authority, "virtual", VIRTUAL);
|
||||
mUriMatcher.addURI(authority, "filesystem", FILESYSTEM);
|
||||
mUriMatcher.addURI(authority, "userinfo", USERINFO);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -531,6 +546,12 @@ public class FileContentProvider extends ContentProvider {
|
|||
sqlQuery.appendWhere(ProviderTableMeta._ID + "=" + uri.getPathSegments().get(1));
|
||||
}
|
||||
break;
|
||||
case USERINFO:
|
||||
sqlQuery.setTables(ProviderTableMeta.USERINFO_TABLE_NAME);
|
||||
if (uri.getPathSegments().size() > SINGLE_PATH_SEGMENT) {
|
||||
sqlQuery.appendWhere(ProviderTableMeta._ID + "=" + uri.getPathSegments().get(1));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown uri id: " + uri);
|
||||
}
|
||||
|
@ -559,12 +580,15 @@ public class FileContentProvider extends ContentProvider {
|
|||
case VIRTUAL:
|
||||
order = ProviderTableMeta.VIRTUAL_TYPE;
|
||||
break;
|
||||
default: // Files
|
||||
order = ProviderTableMeta.FILE_DEFAULT_SORT_ORDER;
|
||||
break;
|
||||
case FILESYSTEM:
|
||||
order = ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH;
|
||||
break;
|
||||
case USERINFO:
|
||||
order = ProviderTableMeta.USERINFO_ACCOUNT;
|
||||
break;
|
||||
default: // Files
|
||||
order = ProviderTableMeta.FILE_DEFAULT_SORT_ORDER;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
order = sortOrder;
|
||||
|
@ -632,6 +656,8 @@ public class FileContentProvider extends ContentProvider {
|
|||
return db.update(ProviderTableMeta.ARBITRARY_DATA_TABLE_NAME, values, selection, selectionArgs);
|
||||
case FILESYSTEM:
|
||||
return db.update(ProviderTableMeta.FILESYSTEM_TABLE_NAME, values, selection, selectionArgs);
|
||||
case USERINFO:
|
||||
return db.update(ProviderTableMeta.USERINFO_TABLE_NAME, values, selection, selectionArgs);
|
||||
default:
|
||||
return db.update(ProviderTableMeta.FILE_TABLE_NAME, values, selection, selectionArgs);
|
||||
}
|
||||
|
@ -862,6 +888,22 @@ public class FileContentProvider extends ContentProvider {
|
|||
);
|
||||
}
|
||||
|
||||
private void createUserInfoTable(SQLiteDatabase db) {
|
||||
db.execSQL("CREATE TABLE IF NOT EXISTS " + ProviderTableMeta.USERINFO_TABLE_NAME + "("
|
||||
+ ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "
|
||||
+ ProviderTableMeta.USERINFO_ACCOUNT + TEXT
|
||||
+ ProviderTableMeta.USERINFO_DISPLAYNAME + TEXT
|
||||
+ ProviderTableMeta.USERINFO_EMAIL + TEXT
|
||||
+ ProviderTableMeta.USERINFO_PHONE + TEXT
|
||||
+ ProviderTableMeta.USERINFO_ADDRESS + TEXT
|
||||
+ ProviderTableMeta.USERINFO_WEBSITE + TEXT
|
||||
+ ProviderTableMeta.USERINFO_TWITTER + TEXT
|
||||
+ ProviderTableMeta.USERINFO_GROUPS + TEXT
|
||||
+ ProviderTableMeta.USERINFO_QUOTA + " TEXT); "
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Version 10 of database does not modify its scheme. It coincides with the upgrade of the
|
||||
* ownCloud account names structure to include in it the path to the server instance. Updating
|
||||
|
@ -992,6 +1034,7 @@ public class FileContentProvider extends ContentProvider {
|
|||
case ARBITRARY_DATA:
|
||||
case VIRTUAL:
|
||||
case FILESYSTEM:
|
||||
case USERINFO:
|
||||
String callingPackage = mContext.getPackageManager().getNameForUid(Binder.getCallingUid());
|
||||
return callingPackage == null || !callingPackage.equals(mContext.getPackageName());
|
||||
|
||||
|
@ -1037,6 +1080,9 @@ public class FileContentProvider extends ContentProvider {
|
|||
|
||||
// Create filesystem table
|
||||
createFileSystemTable(db);
|
||||
|
||||
// Create userInfo table
|
||||
createUserInfoTable(db);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2004,6 +2050,23 @@ public class FileContentProvider extends ContentProvider {
|
|||
if (!upgraded) {
|
||||
Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
|
||||
}
|
||||
|
||||
if (oldVersion < 50 && newVersion >= 50) {
|
||||
Log_OC.i(SQL, "Entering in the #50 add userinfo table");
|
||||
db.beginTransaction();
|
||||
try {
|
||||
createUserInfoTable(db);
|
||||
|
||||
upgraded = true;
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
if (!upgraded) {
|
||||
Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package com.owncloud.android.repository;
|
||||
|
||||
import android.accounts.Account;
|
||||
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
|
||||
class Invoker {
|
||||
public RemoteOperationResult invoke(Account account, RemoteOperation remoteOperation) {
|
||||
return remoteOperation.execute(account, MainApp.getAppContext());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package com.owncloud.android.repository;
|
||||
|
||||
import android.accounts.Account;
|
||||
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.lib.common.UserInfo;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.users.GetUserInfoRemoteOperation;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
public class UserInfoRepository {
|
||||
private final Executor executor;
|
||||
private FileDataStorageManager storageManager;
|
||||
MutableLiveData<com.owncloud.android.datamodel.UserInfo> test = new MutableLiveData<>();
|
||||
|
||||
public UserInfoRepository(Executor executor, FileDataStorageManager storageManager) {
|
||||
this.executor = executor;
|
||||
this.storageManager = storageManager;
|
||||
}
|
||||
|
||||
public LiveData<com.owncloud.android.datamodel.UserInfo> getUserInfo(Account account) {
|
||||
refreshUserInfo(account);
|
||||
|
||||
return test;
|
||||
}
|
||||
|
||||
private void refreshUserInfo(Account account) {
|
||||
executor.execute(() -> {
|
||||
// TODO load from server only if force refresh or older than 5min
|
||||
com.owncloud.android.datamodel.UserInfo oldUserInfo = storageManager.getUserInfo(account.name);
|
||||
|
||||
if (!oldUserInfo.isEmpty()) {
|
||||
test.postValue(oldUserInfo);
|
||||
}
|
||||
|
||||
Log_OC.d(this, "Start refresh user info");
|
||||
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
RemoteOperation getRemoteUserInfoOperation = new GetUserInfoRemoteOperation();
|
||||
|
||||
// TODO how to get client better
|
||||
Invoker invoker = new Invoker();
|
||||
RemoteOperationResult result = invoker.invoke(account, getRemoteUserInfoOperation);
|
||||
|
||||
if (result.isSuccess() && result.getData() != null) {
|
||||
Log_OC.d(this, "new refresh user info");
|
||||
|
||||
com.owncloud.android.datamodel.UserInfo userInfo = parseUserInfo((UserInfo) result.getData().get(0),
|
||||
account);
|
||||
test.postValue(userInfo);
|
||||
|
||||
storageManager.saveUserInfo(userInfo);
|
||||
}
|
||||
// TODO error handling if fetch fails
|
||||
});
|
||||
}
|
||||
|
||||
private com.owncloud.android.datamodel.UserInfo parseUserInfo(UserInfo remoteUserInfo, Account account) {
|
||||
com.owncloud.android.datamodel.UserInfo userInfo = new com.owncloud.android.datamodel.UserInfo();
|
||||
|
||||
userInfo.account = account.name;
|
||||
userInfo.displayName = remoteUserInfo.displayName;
|
||||
userInfo.email = remoteUserInfo.email;
|
||||
userInfo.phone = remoteUserInfo.phone;
|
||||
userInfo.address = remoteUserInfo.address;
|
||||
userInfo.website = remoteUserInfo.website;
|
||||
userInfo.twitter = remoteUserInfo.twitter;
|
||||
userInfo.groups = remoteUserInfo.groups;
|
||||
userInfo.quota = remoteUserInfo.quota;
|
||||
|
||||
return userInfo;
|
||||
}
|
||||
}
|
|
@ -89,6 +89,7 @@ import com.owncloud.android.ui.events.DummyDrawerEvent;
|
|||
import com.owncloud.android.ui.events.SearchEvent;
|
||||
import com.owncloud.android.ui.fragment.OCFileListFragment;
|
||||
import com.owncloud.android.ui.trashbin.TrashbinActivity;
|
||||
import com.owncloud.android.ui.viewModel.UserInfoViewModel;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
import com.owncloud.android.utils.DrawerMenuUtil;
|
||||
import com.owncloud.android.utils.FilesSyncHelper;
|
||||
|
@ -316,7 +317,7 @@ public abstract class DrawerActivity extends ToolbarActivity
|
|||
*/
|
||||
private void setupQuotaElement() {
|
||||
mQuotaView = (LinearLayout) findQuotaViewById(R.id.drawer_quota);
|
||||
mQuotaProgressBar = (ProgressBar) findQuotaViewById(R.id.drawer_quota_ProgressBar);
|
||||
mQuotaProgressBar = (ProgressBar) findQuotaViewById(R.id.drawer_quota_progressBar);
|
||||
mQuotaTextPercentage = (TextView) findQuotaViewById(R.id.drawer_quota_percentage);
|
||||
mQuotaTextLink = (TextView) findQuotaViewById(R.id.drawer_quota_link);
|
||||
ThemeUtils.colorProgressBar(mQuotaProgressBar, ThemeUtils.primaryColor(this));
|
||||
|
@ -477,7 +478,7 @@ public abstract class DrawerActivity extends ToolbarActivity
|
|||
case R.id.nav_logout:
|
||||
mCheckedMenuItem = -1;
|
||||
menuItem.setChecked(false);
|
||||
UserInfoActivity.openAccountRemovalConfirmationDialog(getAccount(), getSupportFragmentManager(), true);
|
||||
UserInfoViewModel.openAccountRemovalConfirmationDialog(getAccount(), getSupportFragmentManager(), true);
|
||||
break;
|
||||
case R.id.nav_recently_added:
|
||||
handleSearchEvents(new SearchEvent("%", SearchRemoteOperation.SearchType.CONTENT_TYPE_SEARCH,
|
||||
|
@ -985,9 +986,7 @@ public abstract class DrawerActivity extends ToolbarActivity
|
|||
final Quota quota = userInfo.getQuota();
|
||||
|
||||
if (quota != null) {
|
||||
final long used = quota.getUsed();
|
||||
final long total = quota.getTotal();
|
||||
final int relative = (int) Math.ceil(quota.getRelative());
|
||||
|
||||
final long quotaValue = quota.getQuota();
|
||||
|
||||
runOnUiThread(new Runnable() {
|
||||
|
@ -1000,7 +999,10 @@ public abstract class DrawerActivity extends ToolbarActivity
|
|||
* it is available and calculated (> 0) or
|
||||
* in case of legacy servers (==QUOTA_LIMIT_INFO_NOT_AVAILABLE)
|
||||
*/
|
||||
setQuotaInformation(used, total, relative, quotaValue);
|
||||
DisplayUtils.setQuotaInformation(mQuotaProgressBar, mQuotaTextPercentage,
|
||||
quota, DrawerActivity.this);
|
||||
updateQuotaLink();
|
||||
showQuota(true);
|
||||
} else {
|
||||
/*
|
||||
* quotaValue < 0 means special cases like
|
||||
|
|
|
@ -26,18 +26,11 @@
|
|||
package com.owncloud.android.ui.activity;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
|
@ -52,40 +45,32 @@ import android.widget.TextView;
|
|||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.animation.GlideAnimation;
|
||||
import com.bumptech.glide.request.target.SimpleTarget;
|
||||
import com.google.gson.Gson;
|
||||
import com.nextcloud.client.di.Injectable;
|
||||
import com.nextcloud.client.preferences.AppPreferences;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.ArbitraryDataProvider;
|
||||
import com.owncloud.android.datamodel.PushConfigurationState;
|
||||
import com.owncloud.android.lib.common.UserInfo;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.datamodel.UserInfo;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.users.GetUserInfoRemoteOperation;
|
||||
import com.owncloud.android.ui.events.TokenPushEvent;
|
||||
import com.owncloud.android.repository.UserInfoRepository;
|
||||
import com.owncloud.android.ui.adapter.UserInfoAdapter;
|
||||
import com.owncloud.android.ui.components.UserInfoDetailsItem;
|
||||
import com.owncloud.android.ui.viewModel.UserInfoViewModel;
|
||||
import com.owncloud.android.utils.DisplayUtils;
|
||||
import com.owncloud.android.utils.PushUtils;
|
||||
import com.owncloud.android.utils.ThemeUtils;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.ColorRes;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.graphics.drawable.DrawableCompat;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.BindString;
|
||||
import butterknife.BindView;
|
||||
|
@ -97,33 +82,52 @@ import butterknife.Unbinder;
|
|||
*/
|
||||
public class UserInfoActivity extends FileActivity implements Injectable {
|
||||
public static final String KEY_ACCOUNT = "ACCOUNT";
|
||||
public static final String KEY_DIRECT_REMOVE = "DIRECT_REMOVE";
|
||||
|
||||
private static final String TAG = UserInfoActivity.class.getSimpleName();
|
||||
private static final String KEY_USER_DATA = "USER_DATA";
|
||||
private static final String KEY_DIRECT_REMOVE = "DIRECT_REMOVE";
|
||||
|
||||
private static final int KEY_DELETE_CODE = 101;
|
||||
public static final int KEY_DELETE_CODE = 101;
|
||||
|
||||
@BindView(R.id.empty_list_view) protected LinearLayout emptyContentContainer;
|
||||
@BindView(R.id.empty_list_view_text) protected TextView emptyContentMessage;
|
||||
@BindView(R.id.empty_list_view_headline) protected TextView emptyContentHeadline;
|
||||
@BindView(R.id.empty_list_icon) protected ImageView emptyContentIcon;
|
||||
@BindView(R.id.user_info_view) protected LinearLayout userInfoView;
|
||||
@BindView(R.id.user_icon) protected ImageView avatar;
|
||||
@BindView(R.id.userinfo_username) protected TextView userName;
|
||||
@BindView(R.id.userinfo_username_full) protected TextView fullName;
|
||||
@BindView(R.id.user_info_list) protected RecyclerView mUserInfoList;
|
||||
@BindView(R.id.empty_list_progress) protected ProgressBar multiListProgressBar;
|
||||
@BindView(R.id.empty_list_view)
|
||||
protected LinearLayout emptyContentContainer;
|
||||
@BindView(R.id.empty_list_view_text)
|
||||
protected TextView emptyContentMessage;
|
||||
@BindView(R.id.empty_list_view_headline)
|
||||
protected TextView emptyContentHeadline;
|
||||
@BindView(R.id.empty_list_icon)
|
||||
protected ImageView emptyContentIcon;
|
||||
@BindView(R.id.user_info_view)
|
||||
protected LinearLayout userInfoView;
|
||||
@BindView(R.id.user_icon)
|
||||
protected ImageView avatar;
|
||||
@BindView(R.id.userinfo_username)
|
||||
protected TextView userName;
|
||||
@BindView(R.id.userinfo_username_full)
|
||||
protected TextView fullName;
|
||||
@BindView(R.id.user_info_list)
|
||||
protected RecyclerView mUserInfoList;
|
||||
@BindView(R.id.empty_list_progress)
|
||||
protected ProgressBar multiListProgressBar;
|
||||
@BindView(R.id.userinfo_quota)
|
||||
protected LinearLayout quotaView;
|
||||
@BindView(R.id.userinfo_quota_progressBar)
|
||||
protected ProgressBar quotaProgressBar;
|
||||
@BindView(R.id.userinfo_quota_percentage)
|
||||
protected TextView quotaPercentage;
|
||||
@BindView(R.id.quota_icon)
|
||||
protected ImageView quotaIcon;
|
||||
|
||||
@BindString(R.string.user_information_retrieval_error) protected String sorryMessage;
|
||||
@BindString(R.string.user_information_retrieval_error)
|
||||
protected String sorryMessage;
|
||||
|
||||
@Inject AppPreferences preferences;
|
||||
private float mCurrentAccountAvatarRadiusDimension;
|
||||
|
||||
private Unbinder unbinder;
|
||||
|
||||
private UserInfo userInfo;
|
||||
private Account account;
|
||||
private UserInfoAdapter adapter;
|
||||
private @ColorRes int primaryColor;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
|
@ -131,11 +135,20 @@ public class UserInfoActivity extends FileActivity implements Injectable {
|
|||
super.onCreate(savedInstanceState);
|
||||
Bundle bundle = getIntent().getExtras();
|
||||
|
||||
if (bundle == null) {
|
||||
throw new NullPointerException("Bundle may not be null");
|
||||
}
|
||||
|
||||
account = Parcels.unwrap(bundle.getParcelable(KEY_ACCOUNT));
|
||||
|
||||
if (savedInstanceState != null && savedInstanceState.containsKey(KEY_USER_DATA)) {
|
||||
userInfo = Parcels.unwrap(savedInstanceState.getParcelable(KEY_USER_DATA));
|
||||
}
|
||||
primaryColor = ThemeUtils.primaryColor(account, true, this);
|
||||
|
||||
UserInfoRepository userInfoRepository = new UserInfoRepository(Executors.newCachedThreadPool(),
|
||||
new FileDataStorageManager(account,
|
||||
getContentResolver()));
|
||||
|
||||
UserInfoViewModel viewModel = ViewModelProviders.of(this).get(UserInfoViewModel.class);
|
||||
viewModel.init(account, userInfoRepository, getUserAccountManager());
|
||||
|
||||
mCurrentAccountAvatarRadiusDimension = getResources().getDimension(R.dimen.nav_drawer_header_avatar_radius);
|
||||
|
||||
|
@ -146,19 +159,15 @@ public class UserInfoActivity extends FileActivity implements Injectable {
|
|||
onAccountSet(false);
|
||||
|
||||
boolean useBackgroundImage = URLUtil.isValidUrl(
|
||||
getStorageManager().getCapability(account.name).getServerBackground());
|
||||
getStorageManager().getCapability(account.name).getServerBackground());
|
||||
|
||||
setupToolbar(useBackgroundImage);
|
||||
updateActionBarTitleAndHomeButtonByString("");
|
||||
|
||||
mUserInfoList.setAdapter(new UserInfoAdapter(null, ThemeUtils.primaryColor(getAccount(), true, this)));
|
||||
adapter = new UserInfoAdapter(null);
|
||||
mUserInfoList.setAdapter(adapter);
|
||||
|
||||
if (userInfo != null) {
|
||||
populateUserInfoUi(userInfo);
|
||||
} else {
|
||||
setMultiListLoadingMessage();
|
||||
fetchAndSetData();
|
||||
}
|
||||
viewModel.getUserInfo().observe(this, this::populateUserInfoUi);
|
||||
|
||||
setHeaderImage();
|
||||
}
|
||||
|
@ -179,7 +188,7 @@ public class UserInfoActivity extends FileActivity implements Injectable {
|
|||
onBackPressed();
|
||||
break;
|
||||
case R.id.delete_account:
|
||||
openAccountRemovalConfirmationDialog(account, getSupportFragmentManager(), false);
|
||||
UserInfoViewModel.openAccountRemovalConfirmationDialog(account, getSupportFragmentManager(), false);
|
||||
break;
|
||||
default:
|
||||
retval = super.onOptionsItemSelected(item);
|
||||
|
@ -193,24 +202,11 @@ public class UserInfoActivity extends FileActivity implements Injectable {
|
|||
unbinder.unbind();
|
||||
}
|
||||
|
||||
private void setMultiListLoadingMessage() {
|
||||
if (emptyContentContainer != null) {
|
||||
emptyContentHeadline.setText(R.string.file_list_loading);
|
||||
emptyContentMessage.setText("");
|
||||
|
||||
emptyContentIcon.setVisibility(View.GONE);
|
||||
emptyContentMessage.setVisibility(View.GONE);
|
||||
multiListProgressBar.getIndeterminateDrawable().setColorFilter(ThemeUtils.primaryColor(this),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
multiListProgressBar.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private void setErrorMessageForMultiList(String headline, String message, @DrawableRes int errorResource) {
|
||||
private void setErrorMessageForMultiList(String headline, String message) {
|
||||
if (emptyContentContainer != null && emptyContentMessage != null) {
|
||||
emptyContentHeadline.setText(headline);
|
||||
emptyContentMessage.setText(message);
|
||||
emptyContentIcon.setImageResource(errorResource);
|
||||
emptyContentIcon.setImageResource(R.drawable.ic_user);
|
||||
|
||||
multiListProgressBar.setVisibility(View.GONE);
|
||||
emptyContentIcon.setVisibility(View.VISIBLE);
|
||||
|
@ -218,6 +214,7 @@ public class UserInfoActivity extends FileActivity implements Injectable {
|
|||
}
|
||||
}
|
||||
|
||||
// todo move to viewModel
|
||||
private void setHeaderImage() {
|
||||
if (getStorageManager().getCapability(account.name).getServerBackground() != null) {
|
||||
ViewGroup appBar = findViewById(R.id.appbar);
|
||||
|
@ -241,19 +238,19 @@ public class UserInfoActivity extends FileActivity implements Injectable {
|
|||
@Override
|
||||
public void onLoadFailed(Exception e, Drawable errorDrawable) {
|
||||
Drawable[] drawables = {new ColorDrawable(primaryColor),
|
||||
getResources().getDrawable(R.drawable.background)};
|
||||
getResources().getDrawable(R.drawable.background)};
|
||||
LayerDrawable layerDrawable = new LayerDrawable(drawables);
|
||||
backgroundImageView.setImageDrawable(layerDrawable);
|
||||
}
|
||||
};
|
||||
|
||||
Glide.with(this)
|
||||
.load(background)
|
||||
.centerCrop()
|
||||
.placeholder(R.drawable.background)
|
||||
.error(R.drawable.background)
|
||||
.crossFade()
|
||||
.into(target);
|
||||
.load(background)
|
||||
.centerCrop()
|
||||
.placeholder(R.drawable.background)
|
||||
.error(R.drawable.background)
|
||||
.crossFade()
|
||||
.into(target);
|
||||
} else {
|
||||
// plain color
|
||||
backgroundImageView.setImageDrawable(new ColorDrawable(primaryColor));
|
||||
|
@ -267,24 +264,18 @@ public class UserInfoActivity extends FileActivity implements Injectable {
|
|||
avatar.setTag(account.name);
|
||||
DisplayUtils.setAvatar(account, this, mCurrentAccountAvatarRadiusDimension, getResources(), avatar, this);
|
||||
|
||||
int tint = ThemeUtils.primaryColor(account, true, this);
|
||||
|
||||
if (!TextUtils.isEmpty(userInfo.getDisplayName())) {
|
||||
fullName.setText(userInfo.getDisplayName());
|
||||
}
|
||||
|
||||
if (userInfo.getPhone() == null && userInfo.getEmail() == null && userInfo.getAddress() == null
|
||||
&& userInfo.getTwitter() == null && userInfo.getWebsite() == null) {
|
||||
|
||||
if (userInfo == null || userInfo.isEmpty()) {
|
||||
setErrorMessageForMultiList(getString(R.string.userinfo_no_info_headline),
|
||||
getString(R.string.userinfo_no_info_text), R.drawable.ic_user);
|
||||
getString(R.string.userinfo_no_info_text));
|
||||
} else {
|
||||
if (!TextUtils.isEmpty(userInfo.getDisplayName())) {
|
||||
fullName.setText(userInfo.getDisplayName());
|
||||
}
|
||||
|
||||
emptyContentContainer.setVisibility(View.GONE);
|
||||
userInfoView.setVisibility(View.VISIBLE);
|
||||
|
||||
if (mUserInfoList.getAdapter() instanceof UserInfoAdapter) {
|
||||
mUserInfoList.setAdapter(new UserInfoAdapter(createUserInfoDetails(userInfo), tint));
|
||||
}
|
||||
adapter.setData(createUserInfoDetails(userInfo));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,9 +286,22 @@ public class UserInfoActivity extends FileActivity implements Injectable {
|
|||
addToListIfNeeded(result, R.drawable.ic_email, userInfo.getEmail(), R.string.user_info_email);
|
||||
addToListIfNeeded(result, R.drawable.ic_map_marker, userInfo.getAddress(), R.string.user_info_address);
|
||||
addToListIfNeeded(result, R.drawable.ic_web, DisplayUtils.beautifyURL(userInfo.getWebsite()),
|
||||
R.string.user_info_website);
|
||||
R.string.user_info_website);
|
||||
addToListIfNeeded(result, R.drawable.ic_twitter, DisplayUtils.beautifyTwitterHandle(userInfo.getTwitter()),
|
||||
R.string.user_info_twitter);
|
||||
R.string.user_info_twitter);
|
||||
addToListIfNeeded(result, R.drawable.ic_group, DisplayUtils.beautifyGroups(userInfo.getGroups()),
|
||||
R.string.user_info_groups);
|
||||
|
||||
long quotaValue = userInfo.getQuota().getQuota();
|
||||
if (quotaValue > 0 || quotaValue == GetUserInfoRemoteOperation.SPACE_UNLIMITED
|
||||
|| quotaValue == GetUserInfoRemoteOperation.QUOTA_LIMIT_INFO_NOT_AVAILABLE) {
|
||||
|
||||
DisplayUtils.setQuotaInformation(quotaProgressBar, quotaPercentage, userInfo.getQuota(), this);
|
||||
ThemeUtils.tintDrawable(quotaIcon.getDrawable(), primaryColor);
|
||||
quotaView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
quotaView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -305,206 +309,7 @@ public class UserInfoActivity extends FileActivity implements Injectable {
|
|||
private void addToListIfNeeded(List<UserInfoDetailsItem> info, @DrawableRes int icon, String text,
|
||||
@StringRes int contentDescriptionInt) {
|
||||
if (!TextUtils.isEmpty(text)) {
|
||||
info.add(new UserInfoDetailsItem(icon, text, getResources().getString(contentDescriptionInt)));
|
||||
}
|
||||
}
|
||||
|
||||
public static void openAccountRemovalConfirmationDialog(Account account, FragmentManager fragmentManager,
|
||||
boolean removeDirectly) {
|
||||
UserInfoActivity.AccountRemovalConfirmationDialog dialog =
|
||||
UserInfoActivity.AccountRemovalConfirmationDialog.newInstance(account, removeDirectly);
|
||||
dialog.show(fragmentManager, "dialog");
|
||||
}
|
||||
|
||||
public static class AccountRemovalConfirmationDialog extends DialogFragment {
|
||||
|
||||
private Account account;
|
||||
|
||||
public static UserInfoActivity.AccountRemovalConfirmationDialog newInstance(Account account,
|
||||
boolean removeDirectly) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(KEY_ACCOUNT, account);
|
||||
bundle.putBoolean(KEY_DIRECT_REMOVE, removeDirectly);
|
||||
|
||||
UserInfoActivity.AccountRemovalConfirmationDialog dialog = new
|
||||
UserInfoActivity.AccountRemovalConfirmationDialog();
|
||||
dialog.setArguments(bundle);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
account = getArguments().getParcelable(KEY_ACCOUNT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
int color = ThemeUtils.primaryAccentColor(getActivity());
|
||||
|
||||
AlertDialog alertDialog = (AlertDialog) getDialog();
|
||||
|
||||
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(color);
|
||||
alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(color);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final boolean removeDirectly = getArguments().getBoolean(KEY_DIRECT_REMOVE);
|
||||
return new AlertDialog.Builder(getActivity(), R.style.Theme_ownCloud_Dialog)
|
||||
.setTitle(R.string.delete_account)
|
||||
.setMessage(getResources().getString(R.string.delete_account_warning, account.name))
|
||||
.setIcon(R.drawable.ic_warning)
|
||||
.setPositiveButton(R.string.common_ok,
|
||||
(dialogInterface, i) -> {
|
||||
// remove contact backup job
|
||||
ContactsPreferenceActivity.cancelContactBackupJobForAccount(getActivity(), account);
|
||||
|
||||
ContentResolver contentResolver = getActivity().getContentResolver();
|
||||
|
||||
// disable daily backup
|
||||
ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(
|
||||
contentResolver);
|
||||
|
||||
arbitraryDataProvider.storeOrUpdateKeyValue(account.name,
|
||||
ContactsPreferenceActivity.PREFERENCE_CONTACTS_AUTOMATIC_BACKUP,
|
||||
"false");
|
||||
|
||||
String arbitraryDataPushString;
|
||||
|
||||
if (!TextUtils.isEmpty(arbitraryDataPushString = arbitraryDataProvider.getValue(
|
||||
account, PushUtils.KEY_PUSH)) &&
|
||||
!TextUtils.isEmpty(getResources().getString(R.string.push_server_url))) {
|
||||
Gson gson = new Gson();
|
||||
PushConfigurationState pushArbitraryData = gson.fromJson(arbitraryDataPushString,
|
||||
PushConfigurationState.class);
|
||||
pushArbitraryData.setShouldBeDeleted(true);
|
||||
arbitraryDataProvider.storeOrUpdateKeyValue(account.name, PushUtils.KEY_PUSH,
|
||||
gson.toJson(pushArbitraryData));
|
||||
EventBus.getDefault().post(new TokenPushEvent());
|
||||
}
|
||||
|
||||
|
||||
if (getActivity() != null && !removeDirectly) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(KEY_ACCOUNT, Parcels.wrap(account));
|
||||
Intent intent = new Intent();
|
||||
intent.putExtras(bundle);
|
||||
getActivity().setResult(KEY_DELETE_CODE, intent);
|
||||
getActivity().finish();
|
||||
} else {
|
||||
AccountManager am = (AccountManager) getActivity()
|
||||
.getSystemService(ACCOUNT_SERVICE);
|
||||
|
||||
am.removeAccount(account, null, null);
|
||||
|
||||
Intent start = new Intent(getActivity(), FileDisplayActivity.class);
|
||||
start.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivity(start);
|
||||
}
|
||||
|
||||
})
|
||||
.setNegativeButton(R.string.common_cancel, null)
|
||||
.create();
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchAndSetData() {
|
||||
Thread t = new Thread(() -> {
|
||||
RemoteOperation getRemoteUserInfoOperation = new GetUserInfoRemoteOperation();
|
||||
RemoteOperationResult result = getRemoteUserInfoOperation.execute(account, this);
|
||||
|
||||
if (result.isSuccess() && result.getData() != null) {
|
||||
userInfo = (UserInfo) result.getData().get(0);
|
||||
|
||||
runOnUiThread(() -> populateUserInfoUi(userInfo));
|
||||
|
||||
} else {
|
||||
// show error
|
||||
runOnUiThread(() -> setErrorMessageForMultiList(sorryMessage, result.getLogMessage(),
|
||||
R.drawable.ic_list_empty_error));
|
||||
Log_OC.d(TAG, result.getLogMessage());
|
||||
}
|
||||
});
|
||||
|
||||
t.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
if (userInfo != null) {
|
||||
outState.putParcelable(KEY_USER_DATA, Parcels.wrap(userInfo));
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.BACKGROUND)
|
||||
public void onMessageEvent(TokenPushEvent event) {
|
||||
PushUtils.pushRegistrationToServer(getUserAccountManager(), preferences.getPushToken());
|
||||
}
|
||||
|
||||
|
||||
protected class UserInfoDetailsItem {
|
||||
@DrawableRes public int icon;
|
||||
public String text;
|
||||
public String iconContentDescription;
|
||||
|
||||
public UserInfoDetailsItem(@DrawableRes int icon, String text, String iconContentDescription) {
|
||||
this.icon = icon;
|
||||
this.text = text;
|
||||
this.iconContentDescription = iconContentDescription;
|
||||
}
|
||||
}
|
||||
|
||||
protected class UserInfoAdapter extends RecyclerView.Adapter<UserInfoAdapter.ViewHolder> {
|
||||
protected List<UserInfoDetailsItem> mDisplayList;
|
||||
@ColorInt protected int mTintColor;
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
@BindView(R.id.icon) protected ImageView icon;
|
||||
@BindView(R.id.text) protected TextView text;
|
||||
|
||||
public ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
}
|
||||
}
|
||||
|
||||
public UserInfoAdapter(List<UserInfoDetailsItem> displayList, @ColorInt int tintColor) {
|
||||
mDisplayList = displayList == null ? new LinkedList<>() : displayList;
|
||||
mTintColor = tintColor;
|
||||
}
|
||||
|
||||
public void setData(List<UserInfoDetailsItem> displayList) {
|
||||
mDisplayList = displayList == null ? new LinkedList<>() : displayList;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||
View view = inflater.inflate(R.layout.user_info_details_table_item, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
UserInfoDetailsItem item = mDisplayList.get(position);
|
||||
holder.icon.setImageResource(item.icon);
|
||||
holder.text.setText(item.text);
|
||||
holder.icon.setContentDescription(item.iconContentDescription);
|
||||
DrawableCompat.setTint(holder.icon.getDrawable(), mTintColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mDisplayList.size();
|
||||
info.add(new UserInfoDetailsItem(icon, text, getResources().getString(contentDescriptionInt), primaryColor));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
package com.owncloud.android.ui.adapter;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.owncloud.android.databinding.UserInfoDetailsTableItemBinding;
|
||||
import com.owncloud.android.ui.components.UserInfoDetailsItem;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.databinding.BindingAdapter;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public class UserInfoAdapter extends RecyclerView.Adapter<UserInfoAdapter.ViewHolder> {
|
||||
private List<UserInfoDetailsItem> displayList;
|
||||
|
||||
public UserInfoAdapter(List<UserInfoDetailsItem> displayList) {
|
||||
this.displayList = displayList == null ? new LinkedList<>() : displayList;
|
||||
}
|
||||
|
||||
public void setData(List<UserInfoDetailsItem> displayList) {
|
||||
this.displayList = displayList == null ? new LinkedList<>() : displayList;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public UserInfoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||
UserInfoDetailsTableItemBinding binding = UserInfoDetailsTableItemBinding.inflate(layoutInflater, parent, false);
|
||||
|
||||
return new ViewHolder(binding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
UserInfoDetailsItem item = displayList.get(position);
|
||||
|
||||
holder.bind(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return displayList.size();
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private final UserInfoDetailsTableItemBinding binding;
|
||||
|
||||
public ViewHolder(UserInfoDetailsTableItemBinding binding) {
|
||||
super(binding.getRoot());
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
public void bind(UserInfoDetailsItem item) {
|
||||
binding.setUserInfoDetailsItem(item);
|
||||
binding.executePendingBindings();
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter({"android:src"})
|
||||
public static void setImageViewResource(ImageView imageView, int resource) {
|
||||
imageView.setImageResource(resource);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.owncloud.android.ui.components;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
|
||||
public class UserInfoDetailsItem {
|
||||
@DrawableRes
|
||||
private int icon;
|
||||
private String text;
|
||||
private String iconContentDescription;
|
||||
private int tintColor;
|
||||
|
||||
public UserInfoDetailsItem(@DrawableRes int icon, String text, String iconContentDescription, int tintColor) {
|
||||
this.icon = icon;
|
||||
this.text = text;
|
||||
this.iconContentDescription = iconContentDescription;
|
||||
this.tintColor = tintColor;
|
||||
}
|
||||
|
||||
public int getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public String getIconContentDescription() {
|
||||
return iconContentDescription;
|
||||
}
|
||||
|
||||
public int getTintColor() {
|
||||
return tintColor;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
package com.owncloud.android.ui.dialog;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.datamodel.ArbitraryDataProvider;
|
||||
import com.owncloud.android.datamodel.PushConfigurationState;
|
||||
import com.owncloud.android.ui.activity.ContactsPreferenceActivity;
|
||||
import com.owncloud.android.ui.activity.FileDisplayActivity;
|
||||
import com.owncloud.android.ui.activity.UserInfoActivity;
|
||||
import com.owncloud.android.ui.events.TokenPushEvent;
|
||||
import com.owncloud.android.utils.PushUtils;
|
||||
import com.owncloud.android.utils.ThemeUtils;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import static android.content.Context.ACCOUNT_SERVICE;
|
||||
|
||||
public class AccountRemovalConfirmationDialog extends DialogFragment {
|
||||
|
||||
private Account account;
|
||||
|
||||
public static AccountRemovalConfirmationDialog newInstance(Account account, boolean removeDirectly) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(UserInfoActivity.KEY_ACCOUNT, account);
|
||||
bundle.putBoolean(UserInfoActivity.KEY_DIRECT_REMOVE, removeDirectly);
|
||||
|
||||
AccountRemovalConfirmationDialog dialog = new AccountRemovalConfirmationDialog();
|
||||
dialog.setArguments(bundle);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
account = getArguments().getParcelable(UserInfoActivity.KEY_ACCOUNT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
int color = ThemeUtils.primaryAccentColor(getActivity());
|
||||
|
||||
AlertDialog alertDialog = (AlertDialog) getDialog();
|
||||
|
||||
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(color);
|
||||
alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(color);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final boolean removeDirectly = getArguments().getBoolean(UserInfoActivity.KEY_DIRECT_REMOVE);
|
||||
return new AlertDialog.Builder(getActivity(), R.style.Theme_ownCloud_Dialog)
|
||||
.setTitle(R.string.delete_account)
|
||||
.setMessage(getResources().getString(R.string.delete_account_warning, account.name))
|
||||
.setIcon(R.drawable.ic_warning)
|
||||
.setPositiveButton(R.string.common_ok,
|
||||
(dialogInterface, i) -> {
|
||||
// remove contact backup job
|
||||
ContactsPreferenceActivity.cancelContactBackupJobForAccount(getActivity(), account);
|
||||
|
||||
ContentResolver contentResolver = getActivity().getContentResolver();
|
||||
|
||||
// disable daily backup
|
||||
ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(
|
||||
contentResolver);
|
||||
|
||||
arbitraryDataProvider.storeOrUpdateKeyValue(account.name,
|
||||
ContactsPreferenceActivity.PREFERENCE_CONTACTS_AUTOMATIC_BACKUP,
|
||||
"false");
|
||||
|
||||
String arbitraryDataPushString;
|
||||
|
||||
if (!TextUtils.isEmpty(arbitraryDataPushString = arbitraryDataProvider.getValue(
|
||||
account, PushUtils.KEY_PUSH)) &&
|
||||
!TextUtils.isEmpty(getResources().getString(R.string.push_server_url))) {
|
||||
Gson gson = new Gson();
|
||||
PushConfigurationState pushArbitraryData = gson.fromJson(arbitraryDataPushString,
|
||||
PushConfigurationState.class);
|
||||
pushArbitraryData.setShouldBeDeleted(true);
|
||||
arbitraryDataProvider.storeOrUpdateKeyValue(account.name, PushUtils.KEY_PUSH,
|
||||
gson.toJson(pushArbitraryData));
|
||||
EventBus.getDefault().post(new TokenPushEvent());
|
||||
}
|
||||
|
||||
|
||||
if (getActivity() != null && !removeDirectly) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelable(UserInfoActivity.KEY_ACCOUNT, Parcels.wrap(account));
|
||||
Intent intent = new Intent();
|
||||
intent.putExtras(bundle);
|
||||
getActivity().setResult(UserInfoActivity.KEY_DELETE_CODE, intent);
|
||||
getActivity().finish();
|
||||
} else {
|
||||
AccountManager am = (AccountManager) getActivity().getSystemService(ACCOUNT_SERVICE);
|
||||
|
||||
if (am != null) {
|
||||
am.removeAccount(account, null, null);
|
||||
}
|
||||
|
||||
Intent start = new Intent(getActivity(), FileDisplayActivity.class);
|
||||
start.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivity(start);
|
||||
}
|
||||
|
||||
})
|
||||
.setNegativeButton(R.string.common_cancel, null)
|
||||
.create();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.owncloud.android.ui.viewModel;
|
||||
|
||||
import android.accounts.Account;
|
||||
|
||||
import com.nextcloud.client.account.UserAccountManager;
|
||||
import com.owncloud.android.datamodel.UserInfo;
|
||||
import com.owncloud.android.repository.UserInfoRepository;
|
||||
import com.owncloud.android.ui.dialog.AccountRemovalConfirmationDialog;
|
||||
import com.owncloud.android.ui.events.TokenPushEvent;
|
||||
import com.owncloud.android.utils.PushUtils;
|
||||
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
|
||||
public class UserInfoViewModel extends ViewModel {
|
||||
|
||||
|
||||
private Account account;
|
||||
private LiveData<UserInfo> userInfo;
|
||||
private UserAccountManager userAccountManager;
|
||||
|
||||
public void init(Account account, UserInfoRepository userInfoRepository, UserAccountManager userAccountManager) {
|
||||
if (this.account != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
userInfo = userInfoRepository.getUserInfo(account);
|
||||
this.userAccountManager = userAccountManager;
|
||||
|
||||
// TODO add here setHeader, registerPush, etc.
|
||||
}
|
||||
|
||||
public LiveData<UserInfo> getUserInfo() {
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
public static void openAccountRemovalConfirmationDialog(Account account, FragmentManager fragmentManager,
|
||||
boolean removeDirectly) {
|
||||
AccountRemovalConfirmationDialog.newInstance(account, removeDirectly).show(fragmentManager, "dialog");
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.BACKGROUND)
|
||||
public void onMessageEvent(TokenPushEvent event) {
|
||||
PushUtils.pushRegistrationToServer(userAccountManager, ""); // todo token?
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.owncloud.android.utils;
|
||||
|
||||
public class Converters {
|
||||
// @TypeConverter
|
||||
// public static ArrayList<String> fromString(String value) {
|
||||
// Type listType = new TypeToken<ArrayList<String>>() {
|
||||
// }.getType();
|
||||
//
|
||||
// return new Gson().fromJson(value, listType);
|
||||
// }
|
||||
//
|
||||
// @TypeConverter
|
||||
// public static String fromArrayList(ArrayList<String> list) {
|
||||
// Gson gson = new Gson();
|
||||
//
|
||||
// return gson.toJson(list);
|
||||
// }
|
||||
//
|
||||
// @TypeConverter
|
||||
// public static Quota quotaFromString(String value) {
|
||||
// Type listType = new TypeToken<Quota>() {
|
||||
// }.getType();
|
||||
//
|
||||
// return new Gson().fromJson(value, listType);
|
||||
// }
|
||||
//
|
||||
// @TypeConverter
|
||||
// public static String quotaToString(Quota quota) {
|
||||
// Gson gson = new Gson();
|
||||
//
|
||||
// return gson.toJson(quota);
|
||||
// }
|
||||
}
|
|
@ -44,6 +44,8 @@ import android.text.style.StyleSpan;
|
|||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.GenericRequestBuilder;
|
||||
import com.bumptech.glide.Glide;
|
||||
|
@ -61,7 +63,9 @@ import com.owncloud.android.datamodel.ArbitraryDataProvider;
|
|||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
|
||||
import com.owncloud.android.lib.common.OwnCloudAccount;
|
||||
import com.owncloud.android.lib.common.Quota;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.users.GetUserInfoRemoteOperation;
|
||||
import com.owncloud.android.ui.TextDrawable;
|
||||
import com.owncloud.android.ui.activity.FileDisplayActivity;
|
||||
import com.owncloud.android.ui.events.SearchEvent;
|
||||
|
@ -83,6 +87,7 @@ import java.math.BigDecimal;
|
|||
import java.net.IDN;
|
||||
import java.nio.charset.Charset;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
|
@ -239,6 +244,9 @@ public final class DisplayUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static String beautifyGroups(ArrayList<String> groups) {
|
||||
return TextUtils.join(", ", groups);
|
||||
}
|
||||
/**
|
||||
* Converts an internationalized domain name (IDN) in an URL to and from ASCII/Unicode.
|
||||
*
|
||||
|
@ -723,4 +731,30 @@ public final class DisplayUtils {
|
|||
DisplayUtils.showSnackMessage(activity, error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* configured the quota to be displayed
|
||||
*
|
||||
* @param quotaProgressBar progress bar
|
||||
* @param quotaTextPercentage text underneath progress bar
|
||||
* @param quota quota to use
|
||||
*/
|
||||
static public void setQuotaInformation(ProgressBar quotaProgressBar, TextView quotaTextPercentage,
|
||||
Quota quota, Activity activity) {
|
||||
final long used = quota.getUsed();
|
||||
final long total = quota.getTotal();
|
||||
final int relative = (int) Math.ceil(quota.getRelative());
|
||||
|
||||
if (GetUserInfoRemoteOperation.SPACE_UNLIMITED == quota.getQuota()) {
|
||||
quotaTextPercentage.setText(String.format(activity.getString(R.string.drawer_quota_unlimited),
|
||||
bytesToHumanReadable(used)));
|
||||
} else {
|
||||
quotaTextPercentage.setText(String.format(activity.getString(R.string.drawer_quota),
|
||||
bytesToHumanReadable(used), bytesToHumanReadable(total)));
|
||||
}
|
||||
|
||||
quotaProgressBar.setProgress(relative);
|
||||
|
||||
ThemeUtils.colorProgressBar(quotaProgressBar, getRelativeInfoColor(activity, relative));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="16"
|
||||
android:viewportWidth="16"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="m8,1c-3.86,0 -7,3.15 -7,7s3.15,7 7,7c3.86,0 7,-3.15 7,-7 0,-3.86 -3.15,-7 -7,-7zM8,2.75c2.91,0 5.25,2.34 5.25,5.25 0,1.42 -0.56,2.7 -1.47,3.644l-3.78,-3.644z" />
|
||||
</vector>
|
|
@ -54,7 +54,7 @@
|
|||
/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/drawer_quota_ProgressBar"
|
||||
android:id="@+id/drawer_quota_progressBar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
@ -18,34 +18,45 @@
|
|||
You should have received a copy of the GNU Affero General Public
|
||||
License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/standard_margin"
|
||||
android:layout_marginEnd="@dimen/standard_half_margin"
|
||||
android:layout_marginLeft="@dimen/standard_icon_list_horizontal_margin"
|
||||
android:layout_marginRight="@dimen/standard_half_margin"
|
||||
android:layout_marginStart="@dimen/standard_icon_list_horizontal_margin"
|
||||
android:layout_marginTop="@dimen/standard_margin"
|
||||
android:contentDescription="@string/account_icon"
|
||||
tools:src="@drawable/ic_phone" />
|
||||
<data>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
<variable
|
||||
name="UserInfoDetailsItem"
|
||||
type="com.owncloud.android.ui.components.UserInfoDetailsItem"/>
|
||||
</data>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_margin="@dimen/standard_margin"
|
||||
android:layout_toEndOf="@id/icon"
|
||||
android:layout_toRightOf="@id/icon"
|
||||
android:maxLines="3"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
tools:text="+49 123 456 789 12" />
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
</RelativeLayout>
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/standard_icon_list_horizontal_margin"
|
||||
android:layout_marginLeft="@dimen/standard_icon_list_horizontal_margin"
|
||||
android:layout_marginTop="@dimen/standard_margin"
|
||||
android:layout_marginEnd="@dimen/standard_half_margin"
|
||||
android:layout_marginRight="@dimen/standard_half_margin"
|
||||
android:layout_marginBottom="@dimen/standard_margin"
|
||||
android:contentDescription="@string/account_icon"
|
||||
android:src="@{UserInfoDetailsItem.icon}"
|
||||
android:tint="@{UserInfoDetailsItem.tintColor}"
|
||||
tools:src="@drawable/ic_phone"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/standard_margin"
|
||||
android:text="@{UserInfoDetailsItem.text}"
|
||||
android:contentDescription="@{UserInfoDetailsItem.iconContentDescription"
|
||||
android:maxLines="3"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
tools:text="+49 123 456 789 12"/>
|
||||
|
||||
</LinearLayout>
|
||||
</layout>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<include
|
||||
layout="@layout/toolbar_user_information"/>
|
||||
|
@ -32,8 +32,8 @@
|
|||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentTop="true"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
|
@ -62,6 +62,55 @@
|
|||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/quota_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/standard_icon_list_horizontal_margin"
|
||||
android:layout_marginLeft="@dimen/standard_icon_list_horizontal_margin"
|
||||
android:layout_marginTop="@dimen/standard_margin"
|
||||
android:layout_marginEnd="@dimen/standard_half_margin"
|
||||
android:layout_marginRight="@dimen/standard_half_margin"
|
||||
android:layout_marginBottom="@dimen/standard_margin"
|
||||
android:contentDescription="@string/account_icon"
|
||||
android:src="@drawable/ic_quota" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/userinfo_quota"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="@color/white"
|
||||
android:clickable="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@dimen/standard_padding"
|
||||
android:paddingTop="@dimen/standard_half_padding"
|
||||
android:paddingRight="@dimen/standard_padding"
|
||||
android:paddingBottom="@dimen/standard_half_padding"
|
||||
android:visibility="gone">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/userinfo_quota_progressBar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="false"
|
||||
android:indeterminateOnly="false"
|
||||
android:text="@string/drawer_quota" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/userinfo_quota_percentage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawablePadding="@dimen/alternate_half_padding"
|
||||
android:text="@string/drawer_quota" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
|
|
@ -596,6 +596,7 @@
|
|||
<string name="user_info_address">Address</string>
|
||||
<string name="user_info_website">Website</string>
|
||||
<string name="user_info_twitter">Twitter</string>
|
||||
<string name="user_info_groups">Groups</string>
|
||||
|
||||
<string name="user_information_retrieval_error">Error retrieving user information</string>
|
||||
|
||||
|
@ -826,6 +827,7 @@
|
|||
<string name="no_pdf_app_available">No App available to handle PDF</string>
|
||||
<string name="share_via_link_hide_download">Hide download</string>
|
||||
<string name="unread_comments">Unread comments exist</string>
|
||||
<string name="user_info_quota">Quota</string>
|
||||
<string name="richdocuments_failed_to_load_document">Failed to load document!</string>
|
||||
<string name="create_new_document">Create new document</string>
|
||||
<string name="create_new_spreadsheet">Create new spreadsheet</string>
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
package com.owncloud.android.repository;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.lib.common.UserInfo;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.resources.users.GetUserInfoRemoteOperation;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class UserInfoRepositoryTest {
|
||||
|
||||
@Mock
|
||||
private Executor executor;
|
||||
@Mock
|
||||
private Context context;
|
||||
@Mock
|
||||
private Invoker invoker;
|
||||
@Mock
|
||||
private FileDataStorageManager storageManager;
|
||||
|
||||
@Test
|
||||
public void getUserInfo() {
|
||||
// init
|
||||
Account accountMock = mock(Account.class);
|
||||
// when(accountMock.name).thenReturn("accountName");
|
||||
|
||||
RemoteOperationResult remoteOperationResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.OK);
|
||||
|
||||
UserInfo userInfoMock = new UserInfo();
|
||||
userInfoMock.displayName = "displayName";
|
||||
|
||||
// LiveData userInfoResult = mock(LiveData.class);
|
||||
// when(userInfoDao.load(any())).thenReturn(userInfoResult);
|
||||
|
||||
remoteOperationResult.setData(new ArrayList<>(singletonList(userInfoMock)));
|
||||
when(invoker.invoke(any(), any())).thenReturn(remoteOperationResult);
|
||||
|
||||
UserInfoRepository sut = new UserInfoRepository(executor, storageManager);
|
||||
|
||||
// test
|
||||
LiveData<com.owncloud.android.datamodel.UserInfo> userInfo = sut.getUserInfo(accountMock);
|
||||
|
||||
// verify result
|
||||
assertTrue(userInfo != null);
|
||||
|
||||
// verify local dao call
|
||||
ArgumentCaptor<com.owncloud.android.datamodel.UserInfo> userInfoArgumentCaptor = ArgumentCaptor.forClass(com.owncloud.android.datamodel.UserInfo.class);
|
||||
// TODO re-enable verify(userInfoDao).save(userInfoArgumentCaptor.capture());
|
||||
|
||||
assertThat(userInfoArgumentCaptor.getValue().getDisplayName(), is("displayName"));
|
||||
// verify(userInfoDao).load("accountName");
|
||||
|
||||
// verify remote lib call
|
||||
ArgumentCaptor<Account> accountArgumentCaptor = ArgumentCaptor.forClass(Account.class);
|
||||
ArgumentCaptor<RemoteOperation> remoteOperationArgumentCaptor = ArgumentCaptor.forClass(RemoteOperation.class);
|
||||
verify(invoker.invoke(accountArgumentCaptor.capture(), remoteOperationArgumentCaptor.capture()));
|
||||
|
||||
assertSame(accountArgumentCaptor.getValue(), accountMock);
|
||||
assertThat(remoteOperationArgumentCaptor.getValue(), is(instanceOf(GetUserInfoRemoteOperation.class)));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue