account database fix

This commit is contained in:
nuclearfog 2023-11-16 23:02:43 +01:00
parent 7edc7e9c1e
commit f913cebe9e
No known key found for this signature in database
GPG Key ID: 03488A185C476379
11 changed files with 225 additions and 189 deletions

View File

@ -229,8 +229,8 @@ public class Mastodon implements Connection {
Credentials credentials = getCredentials(hostname, bearer);
MastodonAccount account = new MastodonAccount(credentials, hostname, bearer, connection.getOauthConsumerToken(), connection.getOauthTokenSecret());
settings.setLogin(account, false);
//User user = showUser(credentials.getId());
//account.setUser(user); // todo add profile image and username to account
User user = showUser(credentials.getId());
account.setProfileImage(user.getProfileImageThumbnailUrl());
return account;
}
throw new MastodonException(response);

View File

@ -39,7 +39,7 @@ public class MastodonAccount implements Account {
id = credentials.getId();
timestamp = System.currentTimeMillis();
screenName = credentials.getUsername();
profileImage = ""; // todo implement this
profileImage = "";
}
@ -123,4 +123,11 @@ public class MastodonAccount implements Account {
Account account = (Account) obj;
return account.getId() == getId() && account.getHostname().equals(getHostname());
}
/**
*
*/
public void setProfileImage(String profileImage) {
this.profileImage = profileImage;
}
}

View File

@ -1,98 +0,0 @@
package org.nuclearfog.twidda.backend.async;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.backend.helper.update.UserUpdate;
import org.nuclearfog.twidda.database.AppDatabase;
import org.nuclearfog.twidda.model.Credentials;
import org.nuclearfog.twidda.model.User;
/**
* loader class for user credentials
*
* @author nuclearfog
* @see org.nuclearfog.twidda.ui.activities.ProfileEditor
*/
public class CredentialsAction extends AsyncExecutor<CredentialsAction.Param, CredentialsAction.Result> {
private Connection connection;
private AppDatabase db;
/**
*
*/
public CredentialsAction(Context context) {
db = new AppDatabase(context);
connection = ConnectionManager.getDefaultConnection(context);
}
@Override
protected Result doInBackground(@NonNull Param param) {
try {
if (param.mode == Param.UPDATE) {
if (param.update != null) {
User user = connection.updateCredentials(param.update);
db.saveUser(user);
param.update.close();
return new Result(Result.UPDATE, user, null, null);
}
} else if (param.mode == Param.LOAD) {
Credentials credentials = connection.getCredentials();
return new Result(Result.LOAD, null, credentials, null);
}
} catch (ConnectionException exception) {
return new Result(Result.ERROR, null, null, exception);
}
return null;
}
/**
*
*/
public static class Param {
public static final int LOAD = 1;
public static final int UPDATE = 2;
final int mode;
@Nullable
final UserUpdate update;
public Param(int mode, @Nullable UserUpdate update) {
this.mode = mode;
this.update = update;
}
}
/**
*
*/
public static class Result {
public static final int ERROR = -1;
public static final int LOAD = 10;
public static final int UPDATE = 20;
public final int mode;
@Nullable
public final User user;
@Nullable
public final Credentials credentials;
@Nullable
public final ConnectionException exception;
Result(int mode, @Nullable User user, @Nullable Credentials credentials, @Nullable ConnectionException exception) {
this.mode = mode;
this.user = user;
this.credentials = credentials;
this.exception = exception;
}
}
}

View File

@ -0,0 +1,66 @@
package org.nuclearfog.twidda.backend.async;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.config.GlobalSettings;
import org.nuclearfog.twidda.database.AppDatabase;
import org.nuclearfog.twidda.model.Credentials;
import org.nuclearfog.twidda.model.User;
/**
* Asyncloader used to load information about the current user
*
* @author nuclearfog
*/
public class CredentialsLoader extends AsyncExecutor<Void, CredentialsLoader.Result> {
private Connection connection;
private GlobalSettings settings;
private AppDatabase db;
public CredentialsLoader(Context context) {
db = new AppDatabase(context);
connection = ConnectionManager.getDefaultConnection(context);
settings = GlobalSettings.get(context);
}
@Override
protected Result doInBackground(@NonNull Void param) {
try {
Credentials credentials = connection.getCredentials();
User user = connection.showUser(settings.getLogin().getId());
db.updateCurrentLogin(user);
return new Result(user, credentials, null);
} catch (ConnectionException exception) {
return new Result(null, null, exception);
}
}
/**
*
*/
public static class Result {
@Nullable
public final User user;
@Nullable
public final Credentials credentials;
@Nullable
public final ConnectionException exception;
public Result(@Nullable User user, @Nullable Credentials credentials, @Nullable ConnectionException exception) {
this.exception = exception;
this.credentials = credentials;
this.user = user;
}
}
}

View File

@ -0,0 +1,62 @@
package org.nuclearfog.twidda.backend.async;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.backend.helper.update.UserUpdate;
import org.nuclearfog.twidda.database.AppDatabase;
import org.nuclearfog.twidda.model.User;
/**
* Async updater class used to update current user information and profile settings
*
* @author nuclearfog
* @see org.nuclearfog.twidda.ui.activities.ProfileEditor
*/
public class CredentialsUpdater extends AsyncExecutor<UserUpdate, CredentialsUpdater.Result> {
private Connection connection;
private AppDatabase db;
/**
*
*/
public CredentialsUpdater(Context context) {
db = new AppDatabase(context);
connection = ConnectionManager.getDefaultConnection(context);
}
@Override
protected Result doInBackground(@NonNull UserUpdate param) {
try {
User user = connection.updateCredentials(param);
db.saveUser(user);
param.close();
return new Result(user, null);
} catch (ConnectionException exception) {
return new Result(null, exception);
}
}
/**
*
*/
public static class Result {
@Nullable
public final User user;
@Nullable
public final ConnectionException exception;
Result(@Nullable User user, @Nullable ConnectionException exception) {
this.user = user;
this.exception = exception;
}
}
}

View File

@ -528,7 +528,7 @@ public class AppDatabase {
String[] accountArgs = {Long.toString(account.getId()), account.getHostname()};
db.delete(AccountTable.TABLE, ACCOUNT_SELECTION, accountArgs);
// insert/update login
ContentValues column = new ContentValues(9);
ContentValues column = new ContentValues(11);
column.put(AccountTable.ID, account.getId());
column.put(AccountTable.DATE, account.getTimestamp());
column.put(AccountTable.HOSTNAME, account.getHostname());
@ -538,10 +538,28 @@ public class AppDatabase {
column.put(AccountTable.ACCESS_TOKEN, account.getOauthToken());
column.put(AccountTable.TOKEN_SECRET, account.getOauthSecret());
column.put(AccountTable.BEARER, account.getBearerToken());
column.put(AccountTable.IMAGE, account.getProfileImageUrl());
column.put(AccountTable.USERNAME, account.getScreenname());
db.insertWithOnConflict(AccountTable.TABLE, "", column, SQLiteDatabase.CONFLICT_REPLACE);
if (account.getUser() != null) {
saveUser(account.getUser(), db, SQLiteDatabase.CONFLICT_IGNORE);
}
adapter.commit();
}
}
/**
* update existing login
*
* @param user user information to update
*/
public void updateCurrentLogin(User user) {
synchronized (adapter) {
SQLiteDatabase db = adapter.getDbWrite();
// delete login entry if exists
String[] accountArgs = {Long.toString(user.getId()), settings.getLogin().getHostname()};
// update login columns
ContentValues column = new ContentValues(2);
column.put(AccountTable.IMAGE, user.getProfileImageThumbnailUrl());
column.put(AccountTable.USERNAME, user.getScreenname());
db.update(AccountTable.TABLE, column, ACCOUNT_SELECTION, accountArgs);
adapter.commit();
}
}
@ -788,11 +806,6 @@ public class AppDatabase {
if (cursor.moveToFirst()) {
do {
DatabaseAccount account = new DatabaseAccount(cursor);
DatabaseUser user = getUser(account.getId());
if (user != null) {
user.setAccountInformation(account);
//account.addUser(user);
}
result.add(account);
} while (cursor.moveToNext());
}

View File

@ -43,10 +43,6 @@ public interface Account extends Serializable {
*/
String getConsumerToken();
default User getUser() {
return null;
}
/**
* @return API secret key associated with an account
*/

View File

@ -38,15 +38,12 @@ import com.squareup.picasso.Transformation;
import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.backend.async.AsyncExecutor.AsyncCallback;
import org.nuclearfog.twidda.backend.async.UserLoader;
import org.nuclearfog.twidda.backend.async.UserLoader.Param;
import org.nuclearfog.twidda.backend.async.UserLoader.Result;
import org.nuclearfog.twidda.backend.async.CredentialsLoader;
import org.nuclearfog.twidda.backend.image.PicassoBuilder;
import org.nuclearfog.twidda.backend.utils.AppStyles;
import org.nuclearfog.twidda.backend.utils.EmojiUtils;
import org.nuclearfog.twidda.backend.utils.StringUtils;
import org.nuclearfog.twidda.config.GlobalSettings;
import org.nuclearfog.twidda.model.Account;
import org.nuclearfog.twidda.model.User;
import org.nuclearfog.twidda.ui.adapter.viewpager.HomeAdapter;
import org.nuclearfog.twidda.ui.dialogs.ProgressDialog;
@ -63,7 +60,7 @@ import jp.wasabeef.picasso.transformations.RoundedCornersTransformation;
* @author nuclearfog
*/
public class MainActivity extends AppCompatActivity implements ActivityResultCallback<ActivityResult>, OnTabSelectedListener,
OnQueryTextListener, OnNavigationItemSelectedListener, OnClickListener, AsyncCallback<Result> {
OnQueryTextListener, OnNavigationItemSelectedListener, OnClickListener, AsyncCallback<CredentialsLoader.Result> {
/**
* Bundle key used to select page
@ -90,7 +87,7 @@ public class MainActivity extends AppCompatActivity implements ActivityResultCal
private HomeAdapter adapter;
private GlobalSettings settings;
private Picasso picasso;
private UserLoader userLoader;
private CredentialsLoader credentialsLoader;
private Dialog loadingCircle;
private DrawerLayout drawerLayout;
@ -130,7 +127,7 @@ public class MainActivity extends AppCompatActivity implements ActivityResultCal
followerCount = header.findViewById(R.id.navigation_profile_follower);
followingCount = header.findViewById(R.id.navigation_profile_following);
userLoader = new UserLoader(this);
credentialsLoader = new CredentialsLoader(this);
loadingCircle = new ProgressDialog(this, null);
settings = GlobalSettings.get(this);
picasso = PicassoBuilder.get(this);
@ -186,8 +183,7 @@ public class MainActivity extends AppCompatActivity implements ActivityResultCal
}
// load user information
if (settings.isLoggedIn() && currentUser == null) {
Param param = new Param(Param.DATABASE, settings.getLogin().getId());
userLoader.execute(param, this);
credentialsLoader.execute(null, this);
}
}
@ -247,25 +243,14 @@ public class MainActivity extends AppCompatActivity implements ActivityResultCal
// login process successful, set user information
case LoginActivity.RETURN_LOGIN_SUCCESSFUL:
setCurrentUser(null); // remove old user content
if (data != null) {
Serializable serializable = data.getSerializableExtra(LoginActivity.RETURN_ACCOUNT);
if (serializable instanceof Account) {
setCurrentUser(((Account) serializable).getUser());
}
}
credentialsLoader.execute(null, this);
loginIntent = null;
break;
// new account selected
case AccountActivity.RETURN_ACCOUNT_CHANGED:
setCurrentUser(null); // remove old user content
if (data != null) {
Serializable serializedAccount = data.getSerializableExtra(AccountActivity.RETURN_ACCOUNT);
if (serializedAccount instanceof Account) {
Account account = (Account) serializedAccount;
setCurrentUser(account.getUser());
}
}
credentialsLoader.execute(null, this);
// reset tab pages
adapter = new HomeAdapter(this);
viewPager.setAdapter(adapter);
@ -459,7 +444,7 @@ public class MainActivity extends AppCompatActivity implements ActivityResultCal
@Override
public void onResult(@NonNull Result result) {
public void onResult(CredentialsLoader.Result result) {
setCurrentUser(result.user);
}

View File

@ -31,7 +31,8 @@ import com.squareup.picasso.Transformation;
import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.backend.async.AsyncExecutor.AsyncCallback;
import org.nuclearfog.twidda.backend.async.CredentialsAction;
import org.nuclearfog.twidda.backend.async.CredentialsLoader;
import org.nuclearfog.twidda.backend.async.CredentialsUpdater;
import org.nuclearfog.twidda.backend.helper.MediaStatus;
import org.nuclearfog.twidda.backend.helper.update.UserUpdate;
import org.nuclearfog.twidda.backend.image.PicassoBuilder;
@ -56,7 +57,7 @@ import jp.wasabeef.picasso.transformations.RoundedCornersTransformation;
*
* @author nuclearfog
*/
public class ProfileEditor extends MediaActivity implements OnClickListener, AsyncCallback<CredentialsAction.Result>, OnConfirmListener, TextWatcher, Callback {
public class ProfileEditor extends MediaActivity implements OnClickListener, OnConfirmListener, TextWatcher, Callback {
/**
* key to preload user data
@ -69,7 +70,8 @@ public class ProfileEditor extends MediaActivity implements OnClickListener, Asy
*/
public static final int RETURN_PROFILE_UPDATED = 0xF5C0E570;
private CredentialsAction credentialAction;
private CredentialsUpdater credentialUpdater;
private CredentialsLoader credentialsLoader;
private GlobalSettings settings;
private Picasso picasso;
@ -89,6 +91,9 @@ public class ProfileEditor extends MediaActivity implements OnClickListener, Asy
private UserUpdate userUpdate = new UserUpdate();
private boolean changed = false;
private AsyncCallback<CredentialsLoader.Result> credentialsLoaderCallback = this::onCredentialsLoaderResult;
private AsyncCallback<CredentialsUpdater.Result> credentialsUpdateCallback = this::onCredentialsUpdateResult;
@Override
protected void attachBaseContext(Context newBase) {
@ -119,7 +124,8 @@ public class ProfileEditor extends MediaActivity implements OnClickListener, Asy
prefDialog = new StatusPreferenceDialog(this, userUpdate);
progressDialog = new ProgressDialog(this, null);
confirmDialog = new ConfirmDialog(this, this);
credentialAction = new CredentialsAction(this);
credentialUpdater = new CredentialsUpdater(this);
credentialsLoader = new CredentialsLoader(this);
settings = GlobalSettings.get(this);
picasso = PicassoBuilder.get(this);
@ -167,8 +173,7 @@ public class ProfileEditor extends MediaActivity implements OnClickListener, Asy
protected void onStart() {
super.onStart();
if (credentials == null) {
CredentialsAction.Param param = new CredentialsAction.Param(CredentialsAction.Param.LOAD, null);
credentialAction.execute(param, this);
credentialsLoader.execute(null, credentialsLoaderCallback);
}
}
@ -176,7 +181,8 @@ public class ProfileEditor extends MediaActivity implements OnClickListener, Asy
@Override
protected void onDestroy() {
progressDialog.dismiss();
credentialAction.cancel();
credentialUpdater.cancel();
credentialsLoader.cancel();
super.onDestroy();
}
@ -282,25 +288,6 @@ public class ProfileEditor extends MediaActivity implements OnClickListener, Asy
}
@Override
public void onResult(@NonNull CredentialsAction.Result result) {
if (result.mode == CredentialsAction.Result.UPDATE) {
Intent data = new Intent();
data.putExtra(KEY_USER, result.user);
Toast.makeText(getApplicationContext(), R.string.info_profile_updated, Toast.LENGTH_SHORT).show();
setResult(RETURN_PROFILE_UPDATED, data);
finish();
} else if (result.mode == CredentialsAction.Result.LOAD) {
credentials = result.credentials;
setCredentials();
} else if (result.mode == CredentialsAction.Result.ERROR) {
String message = ErrorUtils.getErrorMessage(this, result.exception);
confirmDialog.show(ConfirmDialog.PROFILE_EDITOR_ERROR, message);
progressDialog.dismiss();
}
}
@Override
public void onSuccess() {
// set toolbar background
@ -318,7 +305,7 @@ public class ProfileEditor extends MediaActivity implements OnClickListener, Asy
* update user information
*/
private void updateUser() {
if (credentialAction.isIdle()) {
if (credentialUpdater.isIdle()) {
String username = this.username.getText().toString();
String userLoc = profileLocation.getText().toString();
String userBio = userDescription.getText().toString();
@ -329,8 +316,7 @@ public class ProfileEditor extends MediaActivity implements OnClickListener, Asy
userUpdate.setProfile(username, userBio, userLoc);
userUpdate.setPrivacy(privacy.isChecked());
if (userUpdate.prepare(getContentResolver())) {
CredentialsAction.Param param = new CredentialsAction.Param(CredentialsAction.Param.UPDATE, userUpdate);
credentialAction.execute(param, this);
credentialUpdater.execute(userUpdate, credentialsUpdateCallback);
progressDialog.show();
} else {
Toast.makeText(getApplicationContext(), R.string.error_media_init, Toast.LENGTH_SHORT).show();
@ -377,4 +363,35 @@ public class ProfileEditor extends MediaActivity implements OnClickListener, Asy
userUpdate.setContentSensitive(credentials.isSensitive());
}
}
/**
*
*/
private void onCredentialsLoaderResult(CredentialsLoader.Result result) {
if (result.credentials != null) {
credentials = result.credentials;
setCredentials();
} else if (result.exception != null) {
String message = ErrorUtils.getErrorMessage(this, result.exception);
confirmDialog.show(ConfirmDialog.PROFILE_EDITOR_ERROR, message);
}
progressDialog.dismiss();
}
/**
*
*/
private void onCredentialsUpdateResult(CredentialsUpdater.Result result) {
if (result.user != null) {
Intent data = new Intent();
data.putExtra(KEY_USER, result.user);
Toast.makeText(getApplicationContext(), R.string.info_profile_updated, Toast.LENGTH_SHORT).show();
setResult(RETURN_PROFILE_UPDATED, data);
finish();
} else {
String message = ErrorUtils.getErrorMessage(this, result.exception);
confirmDialog.show(ConfirmDialog.PROFILE_EDITOR_ERROR, message);
}
progressDialog.dismiss();
}
}

View File

@ -42,7 +42,7 @@ public class AccountHolder extends ViewHolder implements OnClickListener {
private ImageView profile;
private ImageButton remove;
private TextView username, screenname, date;
private TextView screenname, date;
private Drawable placeholder;
private OnHolderClickListener listener;
@ -58,7 +58,6 @@ public class AccountHolder extends ViewHolder implements OnClickListener {
CardView background = (CardView) itemView;
ViewGroup container = itemView.findViewById(R.id.item_account_container);
username = itemView.findViewById(R.id.item_account_username);
screenname = itemView.findViewById(R.id.item_account_screenname);
date = itemView.findViewById(R.id.item_account_date);
remove = itemView.findViewById(R.id.item_account_remove);
@ -92,24 +91,15 @@ public class AccountHolder extends ViewHolder implements OnClickListener {
*/
public void setContent(Account account) {
date.setText(StringUtils.formatCreationTime(itemView.getResources(), account.getTimestamp()));
User user = account.getUser();
if (user != null) {
// set profile information
username.setText(user.getUsername());
screenname.setText(user.getScreenname());
// set profile image
String profileImageUrl = user.getProfileImageThumbnailUrl();
if (settings.imagesEnabled() && !profileImageUrl.isEmpty()) {
Transformation roundCorner = new RoundedCornersTransformation(2, 0);
picasso.load(profileImageUrl).resize(IMG_SIZE, IMG_SIZE).centerCrop().placeholder(placeholder).transform(roundCorner).error(R.drawable.no_image).into(profile);
} else {
profile.setImageDrawable(placeholder);
}
// set profile information
screenname.setText(account.getScreenname());
// set profile image
String profileImageUrl = account.getProfileImageUrl();
if (settings.imagesEnabled() && !profileImageUrl.isEmpty()) {
Transformation roundCorner = new RoundedCornersTransformation(2, 0);
picasso.load(profileImageUrl).resize(IMG_SIZE, IMG_SIZE).centerCrop().placeholder(placeholder).transform(roundCorner).error(R.drawable.no_image).into(profile);
} else {
profile.setImageResource(0);
username.setText(R.string.account_user_unnamed);
screenname.setText(R.string.account_user_id_prefix);
screenname.append(Long.toString(account.getId()));
profile.setImageDrawable(placeholder);
}
switch (account.getConfiguration()) {
case MASTODON:

View File

@ -160,10 +160,8 @@ public class AccountFragment extends ListFragment implements OnAccountClickListe
if (settings.pushEnabled()) {
PushSubscription.subscripe(context);
}
if (result.account.getUser() != null) {
String message = getString(R.string.info_account_selected, result.account.getUser().getScreenname());
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
String message = getString(R.string.info_account_selected, result.account.getScreenname());
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
// set result to the parent activity
Activity activity = getActivity();