diff --git a/app/src/main/java/com/readrops/app/activities/AccountTypeListActivity.java b/app/src/main/java/com/readrops/app/activities/AccountTypeListActivity.java index d9c26f8f..b48b7968 100644 --- a/app/src/main/java/com/readrops/app/activities/AccountTypeListActivity.java +++ b/app/src/main/java/com/readrops/app/activities/AccountTypeListActivity.java @@ -70,6 +70,7 @@ public class AccountTypeListActivity extends AppCompatActivity { accountTypes.add(Account.AccountType.LOCAL); accountTypes.add(Account.AccountType.NEXTCLOUD_NEWS); + accountTypes.add(Account.AccountType.FRESHRSS); return accountTypes; } diff --git a/app/src/main/java/com/readrops/app/activities/AddAccountActivity.java b/app/src/main/java/com/readrops/app/activities/AddAccountActivity.java index b1017d04..d2374352 100644 --- a/app/src/main/java/com/readrops/app/activities/AddAccountActivity.java +++ b/app/src/main/java/com/readrops/app/activities/AddAccountActivity.java @@ -49,15 +49,23 @@ public class AddAccountActivity extends AppCompatActivity { accountToEdit = getIntent().getParcelableExtra(EDIT_ACCOUNT); - if (accountToEdit != null) { - editAccount = true; - fillFields(); - } else { - binding.providerImage.setImageResource(accountType.getIconRes()); - binding.providerName.setText(accountType.getName()); + try { + if (accountToEdit != null) { + viewModel.setAccountType(accountToEdit.getAccountType()); + editAccount = true; + fillFields(); + } else { + viewModel.setAccountType(accountType); - binding.addAccountName.setText(accountType.getName()); + binding.providerImage.setImageResource(accountType.getIconRes()); + binding.providerName.setText(accountType.getName()); + binding.addAccountName.setText(accountType.getName()); + } + } catch (Exception e) { + // TODO : see how to handle this exception + e.printStackTrace(); } + } public void createAccount(View view) { diff --git a/app/src/main/java/com/readrops/app/database/entities/Account.java b/app/src/main/java/com/readrops/app/database/entities/Account.java index ea086380..9ef30b34 100644 --- a/app/src/main/java/com/readrops/app/database/entities/Account.java +++ b/app/src/main/java/com/readrops/app/database/entities/Account.java @@ -37,6 +37,8 @@ public class Account implements Parcelable { @ColumnInfo(name = "current_account") private boolean currentAccount; + private String token; + @Ignore private String login; @@ -157,6 +159,14 @@ public class Account implements Parcelable { return accountType.name() + "_password_" + id; } + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + @Override public int describeContents() { return 0; diff --git a/app/src/main/java/com/readrops/app/repositories/FreshRSSRepository.java b/app/src/main/java/com/readrops/app/repositories/FreshRSSRepository.java new file mode 100644 index 00000000..2ec4b0c1 --- /dev/null +++ b/app/src/main/java/com/readrops/app/repositories/FreshRSSRepository.java @@ -0,0 +1,81 @@ +package com.readrops.app.repositories; + +import android.app.Application; + +import com.readrops.app.database.entities.Account; +import com.readrops.app.database.entities.Feed; +import com.readrops.app.database.entities.Folder; +import com.readrops.app.utils.FeedInsertionResult; +import com.readrops.app.utils.ParsingResult; +import com.readrops.readropslibrary.services.freshrss.FreshRSSAPI; +import com.readrops.readropslibrary.services.freshrss.FreshRSSCredentials; +import com.readrops.readropslibrary.services.freshrss.FreshRSSService; + +import java.util.List; + +import io.reactivex.Completable; +import io.reactivex.Observable; +import io.reactivex.Single; + +public class FreshRSSRepository extends ARepository { + + public FreshRSSRepository(Application application) { + super(application); + } + + @Override + public Single login(Account account, boolean insert) { + FreshRSSAPI api = new FreshRSSAPI(new FreshRSSCredentials(null, account.getUrl())); + + return api.login(account.getLogin(), account.getPassword()) + .flatMap(token -> { + account.setToken(token); + api.buildAPI(new FreshRSSCredentials(token, account.getUrl()), FreshRSSService.class, FreshRSSService.END_POINT); + + return api.getUserInfo(); + }) + .flatMap(userInfo -> { + account.setDisplayedName(userInfo.getUserName()); + + if (insert) + account.setId((int) database.accountDao().insert(account)); + + return Single.just(true); + }); + } + + @Override + public Observable sync(List feeds, Account account) { + return null; + } + + @Override + public Single> addFeeds(List results, Account account) { + return null; + } + + @Override + public Completable updateFeed(Feed feed, Account account) { + return null; + } + + @Override + public Completable deleteFeed(Feed feed, Account account) { + return null; + } + + @Override + public Completable addFolder(Folder folder, Account account) { + return null; + } + + @Override + public Completable updateFolder(Folder folder, Account account) { + return null; + } + + @Override + public Completable deleteFolder(Folder folder, Account account) { + return null; + } +} diff --git a/app/src/main/java/com/readrops/app/repositories/NextNewsRepository.java b/app/src/main/java/com/readrops/app/repositories/NextNewsRepository.java index 044e3f91..66b90441 100644 --- a/app/src/main/java/com/readrops/app/repositories/NextNewsRepository.java +++ b/app/src/main/java/com/readrops/app/repositories/NextNewsRepository.java @@ -46,7 +46,7 @@ public class NextNewsRepository extends ARepository { @Override public Single login(Account account, boolean insert) { return Single.create(emitter -> { - NextNewsAPI newsAPI = new NextNewsAPI(account.toCredentials()); + NextNewsAPI newsAPI = new NextNewsAPI(account.toNextNewsCredentials()); NextNewsUser user = newsAPI.login(); if (user != null) { @@ -65,7 +65,7 @@ public class NextNewsRepository extends ARepository { public Observable sync(List feeds, Account account) { return Observable.create(emitter -> { try { - NextNewsAPI newsAPI = new NextNewsAPI(account.toCredentials()); + NextNewsAPI newsAPI = new NextNewsAPI(account.toNextNewsCredentials()); long lastModified = LocalDateTime.now().toDateTime().getMillis(); NextNewsAPI.SyncType syncType; @@ -117,7 +117,7 @@ public class NextNewsRepository extends ARepository { public Single> addFeeds(List results, Account account) { return Single.create(emitter -> { List feedInsertionResults = new ArrayList<>(); - NextNewsAPI newsAPI = new NextNewsAPI(account.toCredentials()); + NextNewsAPI newsAPI = new NextNewsAPI(account.toNextNewsCredentials()); for (ParsingResult result : results) { FeedInsertionResult insertionResult = new FeedInsertionResult(); @@ -154,7 +154,7 @@ public class NextNewsRepository extends ARepository { @Override public Completable updateFeed(Feed feed, Account account) { return Completable.create(emitter -> { - NextNewsAPI api = new NextNewsAPI(account.toCredentials()); + NextNewsAPI api = new NextNewsAPI(account.toNextNewsCredentials()); Folder folder = feed.getFolderId() == null ? null : database.folderDao().select(feed.getFolderId()); @@ -185,7 +185,7 @@ public class NextNewsRepository extends ARepository { @Override public Completable deleteFeed(Feed feed, Account account) { return Completable.create(emitter -> { - NextNewsAPI api = new NextNewsAPI(account.toCredentials()); + NextNewsAPI api = new NextNewsAPI(account.toNextNewsCredentials()); try { if (api.deleteFeed(feed.getRemoteId())) { @@ -204,7 +204,7 @@ public class NextNewsRepository extends ARepository { @Override public Completable addFolder(Folder folder, Account account) { return Completable.create(emitter -> { - NextNewsAPI api = new NextNewsAPI(account.toCredentials()); + NextNewsAPI api = new NextNewsAPI(account.toNextNewsCredentials()); try { NextNewsFolders folders = api.createFolder(new NextNewsFolder(folder.getRemoteId(), folder.getName())); @@ -224,7 +224,7 @@ public class NextNewsRepository extends ARepository { @Override public Completable updateFolder(Folder folder, Account account) { return Completable.create(emitter -> { - NextNewsAPI api = new NextNewsAPI(account.toCredentials()); + NextNewsAPI api = new NextNewsAPI(account.toNextNewsCredentials()); try { if (api.renameFolder(new NextNewsFolder(folder.getRemoteId(), folder.getName()))) { @@ -244,7 +244,7 @@ public class NextNewsRepository extends ARepository { @Override public Completable deleteFolder(Folder folder, Account account) { return Completable.create(emitter -> { - NextNewsAPI api = new NextNewsAPI(account.toCredentials()); + NextNewsAPI api = new NextNewsAPI(account.toNextNewsCredentials()); try { if (api.deleteFolder(new NextNewsFolder(folder.getRemoteId(), folder.getName()))) { diff --git a/app/src/main/java/com/readrops/app/viewmodels/AccountViewModel.java b/app/src/main/java/com/readrops/app/viewmodels/AccountViewModel.java index 742527e7..9ea95e44 100644 --- a/app/src/main/java/com/readrops/app/viewmodels/AccountViewModel.java +++ b/app/src/main/java/com/readrops/app/viewmodels/AccountViewModel.java @@ -8,6 +8,7 @@ import androidx.lifecycle.AndroidViewModel; import com.readrops.app.database.Database; import com.readrops.app.database.entities.Account; import com.readrops.app.repositories.ARepository; +import com.readrops.app.repositories.FreshRSSRepository; import com.readrops.app.repositories.NextNewsRepository; import io.reactivex.Completable; @@ -21,10 +22,22 @@ public class AccountViewModel extends AndroidViewModel { public AccountViewModel(@NonNull Application application) { super(application); - repository = new NextNewsRepository(application); database = Database.getInstance(application); } + public void setAccountType(Account.AccountType accountType) throws Exception { + switch (accountType) { + case NEXTCLOUD_NEWS: + repository = new NextNewsRepository(getApplication()); + break; + case FRESHRSS: + repository = new FreshRSSRepository(getApplication()); + break; + default: + throw new Exception("unknown account type"); + } + } + public Single login(Account account, boolean insert) { return repository.login(account, insert); } diff --git a/app/src/main/java/com/readrops/app/viewmodels/MainViewModel.java b/app/src/main/java/com/readrops/app/viewmodels/MainViewModel.java index 6bd7ac33..a1e9bdbe 100644 --- a/app/src/main/java/com/readrops/app/viewmodels/MainViewModel.java +++ b/app/src/main/java/com/readrops/app/viewmodels/MainViewModel.java @@ -17,6 +17,7 @@ import com.readrops.app.database.entities.Feed; import com.readrops.app.database.entities.Folder; import com.readrops.app.database.pojo.ItemWithFeed; import com.readrops.app.repositories.ARepository; +import com.readrops.app.repositories.FreshRSSRepository; import com.readrops.app.repositories.LocalFeedRepository; import com.readrops.app.repositories.NextNewsRepository; @@ -67,6 +68,9 @@ public class MainViewModel extends AndroidViewModel { case NEXTCLOUD_NEWS: repository = new NextNewsRepository(getApplication()); break; + case FRESHRSS: + repository = new FreshRSSRepository(getApplication()); + break; } } diff --git a/readropslibrary/build.gradle b/readropslibrary/build.gradle index f50ca439..668f6104 100644 --- a/readropslibrary/build.gradle +++ b/readropslibrary/build.gradle @@ -21,7 +21,10 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } - + compileOptions { + sourceCompatibility = '1.8' + targetCompatibility = '1.8' + } } dependencies { @@ -35,6 +38,7 @@ dependencies { implementation 'com.squareup.retrofit2:retrofit:2.4.0' implementation 'com.squareup.retrofit2:converter-gson:2.4.0' implementation 'com.squareup.retrofit2:converter-simplexml:2.4.0' + implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0' implementation 'com.squareup.okhttp3:logging-interceptor:3.14.1' diff --git a/readropslibrary/src/main/java/com/readrops/readropslibrary/services/API.java b/readropslibrary/src/main/java/com/readrops/readropslibrary/services/API.java index 2bae7d2b..aadedb7b 100644 --- a/readropslibrary/src/main/java/com/readrops/readropslibrary/services/API.java +++ b/readropslibrary/src/main/java/com/readrops/readropslibrary/services/API.java @@ -1,15 +1,16 @@ -package com.readrops.readropslibrary; +package com.readrops.readropslibrary.services; import androidx.annotation.NonNull; -import com.readrops.readropslibrary.services.nextcloudnews.Credentials; import com.readrops.readropslibrary.utils.HttpManager; import retrofit2.Retrofit; +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; import retrofit2.converter.gson.GsonConverterFactory; /** * Abstraction level for services APIs + * * @param an API service interface */ public abstract class API { @@ -17,13 +18,14 @@ public abstract class API { protected T api; public API(Credentials credentials, @NonNull Class clazz, @NonNull String endPoint) { - api = createAPI(credentials, clazz, endPoint); + buildAPI(credentials, clazz, endPoint); } protected Retrofit getConfiguredRetrofitInstance(@NonNull HttpManager httpManager, @NonNull String endPoint) { return new Retrofit.Builder() .baseUrl(httpManager.getCredentials().getUrl() + endPoint) .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .client(httpManager.getOkHttpClient()) .build(); } @@ -34,4 +36,8 @@ public abstract class API { return retrofit.create(clazz); } + + public void buildAPI(@NonNull Credentials credentials, @NonNull Class clazz, @NonNull String endPoint) { + api = createAPI(credentials, clazz, endPoint); + } } diff --git a/readropslibrary/src/main/java/com/readrops/readropslibrary/services/freshrss/FreshRSSAPI.java b/readropslibrary/src/main/java/com/readrops/readropslibrary/services/freshrss/FreshRSSAPI.java new file mode 100644 index 00000000..f85e5884 --- /dev/null +++ b/readropslibrary/src/main/java/com/readrops/readropslibrary/services/freshrss/FreshRSSAPI.java @@ -0,0 +1,38 @@ +package com.readrops.readropslibrary.services.freshrss; + +import com.readrops.readropslibrary.services.API; +import com.readrops.readropslibrary.services.freshrss.json.FreshRSSUserInfo; + +import java.io.StringReader; +import java.util.Properties; + +import io.reactivex.Single; +import okhttp3.MultipartBody; +import okhttp3.RequestBody; + +public class FreshRSSAPI extends API { + + public FreshRSSAPI(FreshRSSCredentials credentials) { + super(credentials, FreshRSSService.class, FreshRSSService.END_POINT); + } + + public Single login(String login, String password) { + RequestBody requestBody = new MultipartBody.Builder() + .setType(MultipartBody.FORM) + .addFormDataPart("Email", login) + .addFormDataPart("Passwd", password) + .build(); + + return api.login(requestBody) + .flatMap(response -> { + Properties properties = new Properties(); + properties.load(new StringReader(response.string())); + + return Single.just(properties.getProperty("Auth")); + }); + } + + public Single getUserInfo() { + return api.getUserInfo(); + } +} diff --git a/readropslibrary/src/main/java/com/readrops/readropslibrary/services/freshrss/FreshRSSCredentials.java b/readropslibrary/src/main/java/com/readrops/readropslibrary/services/freshrss/FreshRSSCredentials.java new file mode 100644 index 00000000..e05b1522 --- /dev/null +++ b/readropslibrary/src/main/java/com/readrops/readropslibrary/services/freshrss/FreshRSSCredentials.java @@ -0,0 +1,13 @@ +package com.readrops.readropslibrary.services.freshrss; + +import com.readrops.readropslibrary.services.Credentials; + +public class FreshRSSCredentials extends Credentials { + + private static final String AUTH_PREFIX = "GoogleLogin auth="; + + public FreshRSSCredentials(String token, String url) { + super(token != null ? AUTH_PREFIX + token : null, url); + + } +} diff --git a/readropslibrary/src/main/java/com/readrops/readropslibrary/services/freshrss/FreshRSSService.java b/readropslibrary/src/main/java/com/readrops/readropslibrary/services/freshrss/FreshRSSService.java new file mode 100644 index 00000000..77931124 --- /dev/null +++ b/readropslibrary/src/main/java/com/readrops/readropslibrary/services/freshrss/FreshRSSService.java @@ -0,0 +1,22 @@ +package com.readrops.readropslibrary.services.freshrss; + +import com.readrops.readropslibrary.services.freshrss.json.FreshRSSUserInfo; + +import io.reactivex.Single; +import okhttp3.RequestBody; +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.POST; + +public interface FreshRSSService { + + String END_POINT = "/api/greader.php/"; + + @POST("accounts/ClientLogin") + Single login(@Body RequestBody body); + + @GET("reader/api/0/user-info") + Single getUserInfo(); + +} diff --git a/readropslibrary/src/main/java/com/readrops/readropslibrary/services/freshrss/json/FreshRSSUserInfo.java b/readropslibrary/src/main/java/com/readrops/readropslibrary/services/freshrss/json/FreshRSSUserInfo.java new file mode 100644 index 00000000..a2277e7d --- /dev/null +++ b/readropslibrary/src/main/java/com/readrops/readropslibrary/services/freshrss/json/FreshRSSUserInfo.java @@ -0,0 +1,46 @@ + +package com.readrops.readropslibrary.services.freshrss.json; + +public class FreshRSSUserInfo { + + private String userEmail; + + private String userId; + + private String userName; + + private String userProfileId; + + public String getUserEmail() { + return userEmail; + } + + public void setUserEmail(String userEmail) { + this.userEmail = userEmail; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getUserProfileId() { + return userProfileId; + } + + public void setUserProfileId(String userProfileId) { + this.userProfileId = userProfileId; + } + +} diff --git a/readropslibrary/src/main/java/com/readrops/readropslibrary/utils/HttpBuilder.java b/readropslibrary/src/main/java/com/readrops/readropslibrary/utils/HttpBuilder.java index 2df9793c..e905d318 100644 --- a/readropslibrary/src/main/java/com/readrops/readropslibrary/utils/HttpBuilder.java +++ b/readropslibrary/src/main/java/com/readrops/readropslibrary/utils/HttpBuilder.java @@ -1,7 +1,8 @@ package com.readrops.readropslibrary.utils; +import java.util.concurrent.TimeUnit; + import okhttp3.OkHttpClient; -import okhttp3.logging.HttpLoggingInterceptor; public final class HttpBuilder { @@ -15,6 +16,8 @@ public final class HttpBuilder { } private static OkHttpClient.Builder createOkHttpBuilder() { - return new OkHttpClient.Builder(); + return new OkHttpClient.Builder() + .callTimeout(30, TimeUnit.SECONDS) + .readTimeout(1, TimeUnit.HOURS); } } diff --git a/readropslibrary/src/main/java/com/readrops/readropslibrary/utils/HttpManager.java b/readropslibrary/src/main/java/com/readrops/readropslibrary/utils/HttpManager.java index 83cc0697..45575c51 100644 --- a/readropslibrary/src/main/java/com/readrops/readropslibrary/utils/HttpManager.java +++ b/readropslibrary/src/main/java/com/readrops/readropslibrary/utils/HttpManager.java @@ -1,9 +1,8 @@ package com.readrops.readropslibrary.utils; -import com.readrops.readropslibrary.services.nextcloudnews.Credentials; +import com.readrops.readropslibrary.services.Credentials; import java.io.IOException; -import java.util.concurrent.TimeUnit; import okhttp3.Interceptor; import okhttp3.OkHttpClient; @@ -18,11 +17,15 @@ public class HttpManager { public HttpManager(final Credentials credentials) { this.credentials = credentials; - okHttpClient = HttpBuilder.getBuilder() - .callTimeout(30, TimeUnit.SECONDS) - .readTimeout(1, TimeUnit.HOURS) - .addInterceptor(new AuthInterceptor()) - .build(); + if (credentials.getAuthorization() != null) { + okHttpClient = HttpBuilder.getBuilder() + .addInterceptor(new AuthInterceptor()) + .build(); + } else { + okHttpClient = HttpBuilder.getBuilder() + .build(); + } + } public OkHttpClient getOkHttpClient() { @@ -36,7 +39,7 @@ public class HttpManager { public class AuthInterceptor implements Interceptor { public AuthInterceptor() { - + // empty constructor } @Override @@ -48,7 +51,7 @@ public class HttpManager { // So preventively, I delete the first added header // TODO : find why AuthInterceptor is called twice request = request.newBuilder().removeHeader("Authorization") - .addHeader("Authorization", credentials.getBase64()) + .addHeader("Authorization", credentials.getAuthorization()) .build(); return chain.proceed(request);