Add create account activity with login flow

This commit is contained in:
Shinokuni 2019-05-18 13:57:01 +02:00
parent 945da48807
commit 572f1f7c45
19 changed files with 515 additions and 43 deletions

View File

@ -16,12 +16,7 @@
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
tools:ignore="GoogleAppIndexingWarning">
<activity
android:name=".activities.ManageFeedsActivity"
android:parentActivityName=".activities.MainActivity"></activity>
<activity
android:name=".activities.MainActivity"
android:theme="@style/AppTheme.NoActionBar">
<activity android:name=".activities.AddAccountActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -29,13 +24,20 @@
</intent-filter>
</activity>
<activity
android:name=".activities.ItemActivity"
android:parentActivityName=".activities.MainActivity"
android:theme="@style/AppTheme.NoActionBar"></activity>
<activity android:name=".activities.AddFeedActivity"
android:parentActivityName=".activities.MainActivity">
android:name=".activities.ManageFeedsActivity"
android:parentActivityName=".activities.MainActivity" />
<activity
android:name=".activities.MainActivity"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name=".activities.ItemActivity"
android:parentActivityName=".activities.MainActivity"
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".activities.AddFeedActivity"
android:parentActivityName=".activities.MainActivity" />
</application>
</manifest>

View File

@ -0,0 +1,135 @@
package com.readrops.app.activities;
import android.content.Intent;
import android.os.Bundle;
import android.util.Patterns;
import android.view.View;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.ViewModelProviders;
import com.readrops.app.R;
import com.readrops.app.database.entities.Account;
import com.readrops.app.databinding.ActivityAddAccountBinding;
import com.readrops.app.utils.SharedPreferencesManager;
import com.readrops.app.viewmodels.AccountViewModel;
import io.reactivex.SingleObserver;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
public class AddAccountActivity extends AppCompatActivity {
private ActivityAddAccountBinding binding;
private AccountViewModel viewModel;
private Account.AccountType accountType;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_add_account);
viewModel = ViewModelProviders.of(this).get(AccountViewModel.class);
accountType = Account.AccountType.NEXTCLOUD_NEWS;
binding.addAccountSkip.setOnClickListener(v -> {
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
finish();
});
binding.addAccountName.setText(accountType.name().replace("_", " "));
}
public void createAccount(View view) {
if (fieldsAreValid()) {
String url = binding.addAccountUrl.getText().toString().trim();
String name = binding.addAccountName.getText().toString().trim();
String login = binding.addAccountLogin.getText().toString().trim();
String password = binding.addAccountPassword.getText().toString().trim();
Account account = new Account(url, name, accountType);
account.setLogin(login);
account.setPassword(password);
viewModel.login(account)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<Boolean>() {
@Override
public void onSubscribe(Disposable d) {
binding.addAccountLoading.setVisibility(View.VISIBLE);
binding.addAccountValidate.setEnabled(false);
}
@Override
public void onSuccess(Boolean success) {
binding.addAccountLoading.setVisibility(View.GONE);
if (success) {
saveLoginPassword(account);
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.putExtra("account", account);
startActivity(intent);
finish();
} else
Toast.makeText(AddAccountActivity.this, "Impossible to login",
Toast.LENGTH_SHORT).show();
}
@Override
public void onError(Throwable e) {
binding.addAccountLoading.setVisibility(View.GONE);
binding.addAccountValidate.setEnabled(true);
Toast.makeText(AddAccountActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
private boolean fieldsAreValid() {
boolean valid = true;
if (binding.addAccountUrl.getText().toString().trim().isEmpty()) {
binding.addAccountUrl.setError(getString(R.string.empty_field));
valid = false;
} else if (!Patterns.WEB_URL.matcher(binding.addAccountUrl.getText().toString().trim()).matches()) {
binding.addAccountUrl.setError(getString(R.string.wrong_url));
valid = false;
}
if (binding.addAccountName.getText().toString().trim().isEmpty()) {
binding.addAccountName.setError(getString(R.string.empty_field));
valid = false;
}
if (binding.addAccountLogin.getText().toString().trim().isEmpty()) {
binding.addAccountLogin.setError(getString(R.string.empty_field));
valid = false;
}
if (binding.addAccountPassword.getText().toString().trim().isEmpty()) {
binding.addAccountPassword.setError(getString(R.string.empty_field));
valid = false;
}
return valid;
}
private void saveLoginPassword(Account account) {
SharedPreferencesManager.writeValue(this, account.getLoginKey(), account.getLogin());
SharedPreferencesManager.writeValue(this, account.getPasswordKey(), account.getPassword());
account.setLogin(null);
account.setPassword(null);
}
}

View File

@ -1,16 +1,8 @@
package com.readrops.app.activities;
import android.annotation.SuppressLint;
import androidx.lifecycle.ViewModelProviders;
import android.content.Intent;
import androidx.annotation.NonNull;
import com.google.android.material.textfield.TextInputEditText;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.ItemTouchHelper;
import android.util.Patterns;
import android.view.MenuItem;
import android.view.MotionEvent;
@ -20,13 +12,21 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.textfield.TextInputEditText;
import com.mikepenz.fastadapter.FastAdapter;
import com.mikepenz.fastadapter.adapters.ItemAdapter;
import com.readrops.app.R;
import com.readrops.app.database.entities.Feed;
import com.readrops.app.utils.FeedInsertionResult;
import com.readrops.app.utils.Utils;
import com.readrops.app.utils.ParsingResult;
import com.readrops.app.utils.Utils;
import com.readrops.app.viewmodels.AddFeedsViewModel;
import java.util.ArrayList;
@ -166,10 +166,10 @@ public class AddFeedActivity extends AppCompatActivity implements View.OnClickLi
String url = feedInput.getText().toString().trim();
if (url.isEmpty()) {
feedInput.setError(getString(R.string.add_feed_empty_field));
feedInput.setError(getString(R.string.empty_field));
return false;
} else if (!Patterns.WEB_URL.matcher(url).matches()) {
feedInput.setError(getString(R.string.add_feed_wrong_url));
feedInput.setError(getString(R.string.wrong_url));
return false;
} else
return true;

View File

@ -113,8 +113,6 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
adapter.submitList(itemWithFeeds);
});
viewModel.getAccounts().observe(this, accounts -> account = accounts.get(0));
refreshLayout = findViewById(R.id.swipe_refresh_layout);
refreshLayout.setOnRefreshListener(this);
@ -125,10 +123,17 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
feedCount = 0;
initRecyclerView();
account = getIntent().getParcelableExtra("account");
if (account != null) {
refreshLayout.setRefreshing(true);
onRefresh();
} else {
viewModel.getCurrentAccount().observe(this, account1 -> account = account1);
}
drawer = new DrawerBuilder()
.withActivity(this)
.withToolbar(toolbar)
.withShowDrawerOnFirstLaunch(true)
.withOnDrawerItemClickListener((view, position, drawerItem) -> {
handleDrawerClick(drawerItem);
return true;
@ -437,6 +442,12 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
}
private void sync(List<Feed> feeds) {
if (account.getLogin() == null)
account.setLogin(SharedPreferencesManager.readString(this, account.getLoginKey()));
if (account.getPassword() == null)
account.setPassword(SharedPreferencesManager.readString(this, account.getPasswordKey()));
viewModel.sync(feeds, account)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

View File

@ -48,11 +48,6 @@ public abstract class Database extends RoomDatabase {
Folder folder = new Folder("reserved");
new Thread(() -> database.folderDao().insert(folder)).start();
Account account = new Account("", "Nextcloud News",
Account.AccountType.NEXTCLOUD_NEWS);
new Thread(() -> database.accountDao().insert(account)).start();
}
@Override

View File

@ -15,6 +15,9 @@ public interface AccountDao {
@Query("Select * from Account")
LiveData<List<Account>> selectAll();
@Query("Select * from Account Where current_account = 1")
LiveData<Account> selectCurrentAccount();
@Query("Select * from Account Where id = :id")
Account selectById(int id);

View File

@ -1,12 +1,15 @@
package com.readrops.app.database.entities;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
@Entity
public class Account {
public class Account implements Parcelable {
@PrimaryKey(autoGenerate = true)
private int id;
@ -16,6 +19,9 @@ public class Account {
@ColumnInfo(name = "account_name")
private String accountName;
@ColumnInfo(name = "displayed_name")
private String displayedName;
@ColumnInfo(name = "account_type")
private AccountType accountType;
@ -41,6 +47,30 @@ public class Account {
this.accountType = accountType;
}
protected Account(Parcel in) {
id = in.readInt();
url = in.readString();
accountName = in.readString();
accountType = getAccountTypeFromCode(in.readInt());
displayedName = in.readString();
lastModified = in.readLong();
currentAccount = in.readByte() != 0;
login = in.readString();
password = in.readString();
}
public static final Creator<Account> CREATOR = new Creator<Account>() {
@Override
public Account createFromParcel(Parcel in) {
return new Account(in);
}
@Override
public Account[] newArray(int size) {
return new Account[size];
}
};
public int getId() {
return id;
}
@ -65,6 +95,14 @@ public class Account {
this.accountName = accountName;
}
public String getDisplayedName() {
return displayedName;
}
public void setDisplayedName(String displayedName) {
this.displayedName = displayedName;
}
public AccountType getAccountType() {
return accountType;
}
@ -105,6 +143,32 @@ public class Account {
this.password = password;
}
public String getLoginKey() {
return accountType.name() + "_login_" + id ;
}
public String getPasswordKey() {
return accountType.name() + "_password_" + id;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(url);
dest.writeString(accountName);
dest.writeInt(accountType.code);
dest.writeString(displayedName);
dest.writeLong(lastModified);
dest.writeByte((byte) (currentAccount ? 1 : 0));
dest.writeString(login);
dest.writeString(password);
}
public enum AccountType {
LOCAL(0),
NEXTCLOUD_NEWS(1),
@ -121,4 +185,17 @@ public class Account {
this.code = code;
}
}
public static AccountType getAccountTypeFromCode(int code) {
if (code == AccountType.LOCAL.getCode())
return AccountType.LOCAL;
else if (code == AccountType.NEXTCLOUD_NEWS.getCode())
return AccountType.NEXTCLOUD_NEWS;
else if (code == AccountType.FEEDLY.getCode())
return AccountType.FEEDLY;
else if (code == AccountType.FRESHRSS.getCode())
return AccountType.FRESHRSS;
return null;
}
}

View File

@ -36,6 +36,8 @@ public abstract class ARepository {
this.database = Database.getInstance(application);
}
public abstract Single<Boolean> login(Account account);
public abstract Observable<Feed> sync(List<Feed> feeds, Account account);
public abstract Single<List<FeedInsertionResult>> addFeeds(List<ParsingResult> results);

View File

@ -49,6 +49,11 @@ public class LocalFeedRepository extends ARepository {
}
@Override
public Single<Boolean> login(Account account) {
return null;
}
@Override
public Observable<Feed> sync(@Nullable List<Feed> feeds, Account account) {
return Observable.create(emitter -> {

View File

@ -20,7 +20,7 @@ import com.readrops.readropslibrary.services.nextcloudnews.SyncResult;
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsFeed;
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsFolder;
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsItem;
import com.readrops.readropslibrary.utils.LibUtils;
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsUser;
import org.joda.time.LocalDateTime;
@ -42,6 +42,27 @@ public class NextNewsRepository extends ARepository {
super(application);
}
@Override
public Single<Boolean> login(Account account) {
return Single.create(emitter -> {
NextNewsAPI newsAPI = new NextNewsAPI();
Credentials credentials = new Credentials(account.getLogin(), account.getPassword(),
account.getUrl());
NextNewsUser user = newsAPI.login(credentials);
if (user != null) {
account.setDisplayedName(user.getDisplayName());
account.setCurrentAccount(true);
database.accountDao().insert(account);
emitter.onSuccess(true);
} else
emitter.onSuccess(false);
});
}
@Override
public Observable<Feed> sync(List<Feed> feeds, Account account) {
return Observable.create(emitter -> {
@ -63,7 +84,8 @@ public class NextNewsRepository extends ARepository {
syncData.setUnreadItems(database.itemDao().getUnreadChanges());
}
Credentials credentials = new Credentials("", LibUtils.NEXTCLOUD_PASSWORD, account.getUrl());
Credentials credentials = new Credentials(account.getLogin(), account.getPassword(),
account.getUrl());
SyncResult syncResult = newsAPI.sync(credentials, syncType, syncData);
if (!syncResult.isError()) {

View File

@ -12,13 +12,17 @@ public final class SharedPreferencesManager {
}
public static void writeValue(Context context, SharedPrefKey key, Object value) {
writeValue(context, key.toString(), value);
}
public static void writeValue(Context context, String key, Object value) {
SharedPreferences sharedPref = getSharedPreferences(context);
SharedPreferences.Editor editor = sharedPref.edit();
if (value instanceof Boolean)
editor.putBoolean(key.toString(), (Boolean) value);
editor.putBoolean(key, (Boolean) value);
else if (value instanceof String)
editor.putString(key.toString(), (String) value);
editor.putString(key, (String) value);
editor.apply();
}
@ -34,6 +38,10 @@ public final class SharedPreferencesManager {
}
public static String readString(Context context, SharedPrefKey key) {
return readString(context, key.toString());
}
public static String readString(Context context, String key) {
SharedPreferences sharedPreferences = getSharedPreferences(context);
return sharedPreferences.getString(key.toString(), null);
}

View File

@ -0,0 +1,27 @@
package com.readrops.app.viewmodels;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import com.readrops.app.database.entities.Account;
import com.readrops.app.repositories.ARepository;
import com.readrops.app.repositories.NextNewsRepository;
import io.reactivex.Single;
public class AccountViewModel extends AndroidViewModel {
private ARepository repository;
public AccountViewModel(@NonNull Application application) {
super(application);
repository = new NextNewsRepository(application);
}
public Single<Boolean> login(Account account) {
return repository.login(account);
}
}

View File

@ -130,8 +130,8 @@ public class MainViewModel extends AndroidViewModel {
});
}
public LiveData<List<Account>> getAccounts() {
return db.accountDao().selectAll();
public LiveData<Account> getCurrentAccount() {
return db.accountDao().selectCurrentAccount();
}
public Completable setItemReadState(int itemId, boolean read, boolean readChanged) {

View File

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".activities.AddAccountActivity">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/provider_image"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginTop="60dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/provider_name"
style="@style/TextAppearance.AppCompat.Large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/nextcloud_news"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/provider_image" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="52dp"
android:padding="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/provider_name">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/add_account_url_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/account_url">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/add_account_url"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/add_account_name_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/add_account_url_layout"
android:layout_marginTop="12dp"
android:hint="@string/account_name">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/add_account_name"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/add_account_login_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/add_account_name_layout"
android:layout_marginTop="12dp"
android:hint="@string/login">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/add_account_login"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/add_account_password_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/add_account_login_layout"
android:layout_marginTop="12dp"
android:hint="@string/password">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/add_account_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/add_account_validate"
style="@style/GenericButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/add_account_password_layout"
android:layout_marginTop="12dp"
android:onClick="createAccount"
android:text="@string/validate" />
<ProgressBar
android:id="@+id/add_account_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/add_account_validate"
android:layout_centerInParent="true"
android:visibility="gone"
tools:visibility="visible" />
<TextView
android:id="@+id/add_account_skip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/add_account_loading"
android:layout_centerInParent="true"
android:layout_marginTop="8dp"
android:text="Skip" />
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@ -11,8 +11,8 @@
<string name="add_feed_title">Ajouter un flux</string>
<string name="feed_url">Adresse du flux</string>
<string name="validate">Valider</string>
<string name="add_feed_empty_field">Le champ ne peut pas être vide</string>
<string name="add_feed_wrong_url">La valeur n\'est pas une adresse web valide</string>
<string name="empty_field">Le champ ne peut pas être vide</string>
<string name="wrong_url">La valeur n\'est pas une adresse web valide</string>
<string name="add_feed_no_result">Aucune adresse de flux trouvée</string>
<string name="add_feed_connexion_error">Erreur de connexion au site</string>
<string name="add_feed_unknownhost_error">Site inconnu</string>
@ -50,5 +50,9 @@
<string name="unread">Marquer comme non lu</string>
<string name="read">Marquer comme lu</string>
<string name="select_all">Tout sélectionner</string>
<string name="account_url">Url du compte</string>
<string name="account_name">Nom du compte</string>
<string name="login">Identifiant</string>
<string name="password">Mot de passe</string>
</resources>

View File

@ -12,8 +12,8 @@
<string name="add_feed_title">Add feed</string>
<string name="feed_url">Feed url</string>
<string name="validate">Validate</string>
<string name="add_feed_empty_field">Field can\'t be empty</string>
<string name="add_feed_wrong_url">Input is not a valid URL</string>
<string name="empty_field">Field can\'t be empty</string>
<string name="wrong_url">Input is not a valid URL</string>
<string name="add_feed_no_result">No feed url found</string>
<string name="add_feed_connexion_error">Connection error</string>
<string name="add_feed_unknownhost_error">Unknown host</string>
@ -52,4 +52,9 @@
<string name="unread">Mark as non read</string>
<string name="read">Mark as read</string>
<string name="select_all">Select all</string>
<string name="account_url">Account url</string>
<string name="account_name">Account name</string>
<string name="login">Login</string>
<string name="password">Password</string>
<string name="nextcloud_news" translatable="false">Nextcloud News</string>
</resources>

View File

@ -8,6 +8,7 @@ import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsFeeds;
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsFolders;
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsItemIds;
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsItems;
import com.readrops.readropslibrary.services.nextcloudnews.json.NextNewsUser;
import com.readrops.readropslibrary.utils.HttpManager;
import java.io.IOException;
@ -34,6 +35,20 @@ public class NextNewsAPI {
.build();
}
public NextNewsUser login(Credentials credentials) throws IOException {
HttpManager httpManager = new HttpManager(credentials);
Retrofit retrofit = getConfiguredRetrofitInstance(httpManager);
api = retrofit.create(NextNewsService.class);
Response<NextNewsUser> response = api.getUser().execute();
if (!response.isSuccessful())
return null;
return response.body();
}
public SyncResult sync(@NonNull Credentials credentials, @NonNull SyncType syncType, @Nullable SyncData data) throws IOException {
HttpManager httpManager = new HttpManager(credentials);
Retrofit retrofit = getConfiguredRetrofitInstance(httpManager);

View File

@ -10,10 +10,46 @@ public class NextNewsUser {
private Avatar avatar;
public NextNewsUser() {
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public long getLastLoginTimestamp() {
return lastLoginTimestamp;
}
public void setLastLoginTimestamp(long lastLoginTimestamp) {
this.lastLoginTimestamp = lastLoginTimestamp;
}
public Avatar getAvatar() {
return avatar;
}
public void setAvatar(Avatar avatar) {
this.avatar = avatar;
}
public class Avatar {
private String data;
private String mime;
}
}

View File

@ -5,8 +5,6 @@ import java.util.Scanner;
public final class LibUtils {
public static final String NEXTCLOUD_PASSWORD = "";
public static final String RSS_DEFAULT_CONTENT_TYPE = "application/rss+xml";
public static final String RSS_TEXT_CONTENT_TYPE = "text/xml";
public static final String RSS_APPLICATION_CONTENT_TYPE = "application/xml";