Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e680271
Add self signed trust ssl.
ploufs Jul 29, 2025
161d75d
Add self signed trust ssl in setting screen
ploufs Jul 29, 2025
851ce4e
wizard connect add checkbox (self singed SSL)
ploufs Jul 29, 2025
21e65f5
Add settings to show article author and publication date in the list
ploufs Jul 31, 2025
d30dddb
Add preview image settings to article list
ploufs Aug 1, 2025
50e5f72
Update default value for article list preview picture height
ploufs Aug 1, 2025
83c6e92
Add setting to show divider between articles in the article list
ploufs Aug 1, 2025
4a1ced5
refactoring layout - Add published date display to article list
ploufs Aug 1, 2025
c6fd5b2
refactor layout - Replace EditText with TextInputEditText in dialog_a…
ploufs Aug 2, 2025
51109af
refactor ListAdapter - Display creation date if publication date is u…
ploufs Aug 2, 2025
cac612b
refactor ReadArticleActivity - Add display for article creation date …
ploufs Aug 3, 2025
3c1e31e
refactor sorting - Add creation date and estimated reading time sort …
ploufs Aug 3, 2025
d0a43f0
refactor CI workflow - Add steps to assemble and upload release APK
ploufs Aug 3, 2025
ebfcbb2
refactor CI workflow - Update to assemble and upload debug APK instea…
ploufs Aug 3, 2025
a58be3b
Update android.yml
ploufs Aug 3, 2025
2ab447c
new theme "DAY_NIGHT"
ploufs Aug 3, 2025
be143fe
Merge remote-tracking branch 'origin/master'
ploufs Aug 3, 2025
6a5773e
new theme "DAY_NIGHT_CONTRAST"
ploufs Aug 4, 2025
b38c62c
update texte
ploufs Aug 4, 2025
53918c1
Update gradle-wrapper-validation.yml
ploufs Aug 4, 2025
c93768f
Update gradle-wrapper-validation.yml
ploufs Aug 4, 2025
9cc2c64
Merge remote-tracking branch 'origin/master'
ploufs Aug 4, 2025
9f90421
Add delete button functionality to article view
ploufs Nov 16, 2025
b27a472
Merge branch 'wallabag:master' into master
ploufs Jan 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,10 @@ jobs:

- name: Build
run: ./gradlew build
- name: Assemble Debug APK
run: ./gradlew assembleDebug
- name: Upload Debug APK
uses: actions/upload-artifact@v4
with:
name: app-debug-apk
path: app/build/outputs/apk/debug/*.apk
4 changes: 2 additions & 2 deletions .github/workflows/gradle-wrapper-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ jobs:
name: "Validation"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: gradle/wrapper-validation-action@v1
- uses: actions/checkout@v4
- uses: gradle/actions/wrapper-validation@v4
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ dependencies {
implementation 'com.google.android.material:material:1.12.0'
implementation 'org.greenrobot:eventbus:3.3.1'
implementation 'org.greenrobot:greendao:3.3.0'
implementation 'com.github.bumptech.glide:okhttp3-integration:4.16.0'
annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.3.1'
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
implementation 'com.squareup.okhttp3:okhttp-urlconnection:4.12.0'
Expand Down
60 changes: 60 additions & 0 deletions app/src/main/java/fr/gaulupeau/apps/Poche/data/ListAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import android.app.Activity;
import android.content.Context;
import android.net.Uri;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuInflater;
Expand All @@ -14,8 +16,12 @@
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;

import fr.gaulupeau.apps.InThePoche.BuildConfig;
import fr.gaulupeau.apps.InThePoche.R;
import fr.gaulupeau.apps.Poche.data.dao.entities.Article;
import fr.gaulupeau.apps.Poche.ui.ArticleActionsHelper;
Expand All @@ -24,6 +30,8 @@
import static fr.gaulupeau.apps.Poche.data.ListTypes.LIST_TYPE_FAVORITES;
import static fr.gaulupeau.apps.Poche.data.ListTypes.LIST_TYPE_UNREAD;

import com.bumptech.glide.Glide;

public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ViewHolder> {

public interface OnItemClickListener {
Expand Down Expand Up @@ -83,6 +91,8 @@ public class ViewHolder extends RecyclerView.ViewHolder
ImageView favourite;
ImageView read;
TextView readingTime;
ImageView previewPicture;
TextView publishedAt;

ViewHolder(View itemView, OnItemClickListener listener) {
super(itemView);
Expand All @@ -93,6 +103,9 @@ public class ViewHolder extends RecyclerView.ViewHolder
favourite = itemView.findViewById(R.id.favourite);
read = itemView.findViewById(R.id.read);
readingTime = itemView.findViewById(R.id.estimatedReadingTime);
previewPicture = itemView.findViewById(R.id.previewPicture);
publishedAt= itemView.findViewById(R.id.publishedAt);


itemView.setOnClickListener(this);
itemView.setOnCreateContextMenuListener(this);
Expand All @@ -104,6 +117,31 @@ void bind(Article article) {
title.setText(article.getTitle());
url.setText(article.getDomain());

previewPicture.setVisibility(View.GONE);
if(settings.getArticleListShowPreviewPicture()) {
// set picture height from settings
if (settings.getArticleListPreviewPictureHeight() > 0) {
previewPicture.getLayoutParams().height = settings.getArticleListPreviewPictureHeight();
}

previewPicture.setVisibility(View.GONE);
if (article.getPreviewPictureURL() != null && !article.getPreviewPictureURL().isEmpty()) {
previewPicture.setVisibility(View.VISIBLE);
Glide
.with(context)
.load(article.getPreviewPictureURL())
.centerCrop()
.into(previewPicture);
}
}

// show author if available in url TextView
if(settings.getArticleListShowAuthor()) {
if (article.getAuthors() != null && !article.getAuthors().isEmpty()) {
url.setText(url.getText() + " (" + article.getAuthors() + ")");
}
}

boolean showFavourite = false;
boolean showRead = false;
switch (listType) {
Expand All @@ -125,6 +163,28 @@ void bind(Article article) {
read.setVisibility(showRead ? View.VISIBLE : View.GONE);
readingTime.setText(context.getString(R.string.listItem_estimatedReadingTime,
article.getEstimatedReadingTime(settings.getReadingSpeed())));

// show date article in readingTime if active in settings
publishedAt.setVisibility(View.GONE);
if(settings.getArticleListShowPublishedAt()) {
java.util.Date displayDate=null;
if (article.getPublishedAt() != null) {
displayDate=article.getPublishedAt();
}
else if(article.getCreationDate()!=null){
displayDate=article.getCreationDate();
}

if(displayDate!=null) {
publishedAt.setVisibility(View.VISIBLE);
var stringBuilder = new StringBuilder();
stringBuilder.append(android.text.format.DateFormat.getDateFormat(context).format(displayDate));
stringBuilder.append(' ');
stringBuilder.append(android.text.format.DateFormat.getTimeFormat(context).format(displayDate));
publishedAt.setText(stringBuilder.toString());
}
}

}

@Override
Expand Down
52 changes: 50 additions & 2 deletions app/src/main/java/fr/gaulupeau/apps/Poche/data/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,54 @@ public void setStringSet(int keyResourceID, Set<String> values) {
setStringSet(context.getString(keyResourceID), values);
}

public boolean getSelfSignedTrust(){
return getBoolean(R.string.pref_key_connection_selfsignedtrust,false);
}

public void setSelfSignedTrust(boolean selfSignedTrust){
setBoolean(R.string.pref_key_connection_selfsignedtrust,selfSignedTrust);
}

public boolean getArticleListShowPreviewPicture(){
return getBoolean(R.string.pref_key_ui_articleList_showPreviewPicture,false);
}

public void setArticleListShowPreviewPicture(boolean articleListShowPreviewPicture){
setBoolean(R.string.pref_key_ui_articleList_showPreviewPicture,articleListShowPreviewPicture);
}

public int getArticleListPreviewPictureHeight(){
return getInt(R.string.pref_key_ui_articleList_previewPictureHeight,500);
}

public void setArticleListPreviewPictureHeight(int articleListPreviewPictureHeight){
setInt(R.string.pref_key_ui_articleList_previewPictureHeight,articleListPreviewPictureHeight);
}

public boolean getArticleListShowAuthor(){
return getBoolean(R.string.pref_key_ui_articleList_showAuthor,false);
}

public void setArticleListShowAuthor(boolean articleListShowAuthor){
setBoolean(R.string.pref_key_ui_articleList_showAuthor,articleListShowAuthor);
}

public boolean getArticleListShowPublishedAt(){
return getBoolean(R.string.pref_key_ui_articleList_showPublishedAt,false);
}

public void setArticleListShowPublishedAt(boolean articleListPublishedAt){
setBoolean(R.string.pref_key_ui_articleList_showPublishedAt,articleListPublishedAt);
}

public boolean getArticleListShowDivider() {
return getBoolean(R.string.pref_key_ui_articleList_showDivider,false);
}

public void setArticleListShowDivider(boolean articleListShowDivider) {
setBoolean(R.string.pref_key_ui_articleList_showDivider,articleListShowDivider);
}

public String getUrl() {
return getString(R.string.pref_key_connection_url);
}
Expand Down Expand Up @@ -401,9 +449,9 @@ public Sortable.SortOrder getListSortOrder() {
String sortOrderParam = getString(R.string.pref_key_ui_lists_sortOrder);

Sortable.SortOrder sortOrder = null;
if(sortOrderParam != null) {
if(sortOrderParam != null && !sortOrderParam.isEmpty()) {
try {
sortOrder = Sortable.SortOrder.valueOf(sortOrderParam);
sortOrder = Sortable.SortOrder.valueOf(sortOrderParam);
} catch(IllegalArgumentException ignored) {}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package fr.gaulupeau.apps.Poche.network;

import javax.net.ssl.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class SelfSignedTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// Optionnel : implémenter selon tes besoins
}

@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
if (chain == null || chain.length == 0) throw new IllegalArgumentException("Empty or null certificate chain");
X509Certificate cert = chain[0];
// Vérifie si le certificat est auto-signé
if (isSelfSigned(cert)) {
return;
}
// accepter le certificat s'il est valide
cert.checkValidity();
}

@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}

// Vérifie si le certificat est auto-signé
private boolean isSelfSigned(X509Certificate cert) {
try {
// Un certificat est auto-signé si l’émetteur et le sujet sont identiques et si la signature est valide avec sa propre clé publique
cert.verify(cert.getPublicKey());
return cert.getSubjectX500Principal().equals(cert.getIssuerX500Principal());
} catch (Exception e) {
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,24 @@
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;

import com.facebook.stetho.okhttp3.StethoInterceptor;

import org.conscrypt.Conscrypt;

import java.io.IOException;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.security.KeyManagementException;
import java.security.Security;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import fr.gaulupeau.apps.InThePoche.BuildConfig;
import fr.gaulupeau.apps.Poche.App;
import fr.gaulupeau.apps.Poche.data.Settings;
Expand Down Expand Up @@ -160,6 +168,23 @@ private static OkHttpClient.Builder getClientBuilder(boolean addCookieManager) {
b.addNetworkInterceptor(new StethoInterceptor());
}

if(App.getSettings().getSelfSignedTrust()) {
// validate ssl
try {
TrustManager[] trustManagers = new TrustManager[]{new SelfSignedTrustManager()};
SSLContext sslContext = SSLContext.getInstance("TLS");

sslContext.init(null, trustManagers, new java.security.SecureRandom());

SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

b.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustManagers[0]);
b.hostnameVerifier((hostname, session) -> true);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

return b;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,13 +236,19 @@ private QueryBuilder<Article> getQueryBuilder() {

switch (sortOrder) {
case ASC:
case CreationDateASC:
qb.orderAsc(ArticleDao.Properties.CreationDate, ArticleDao.Properties.ArticleId);
break;

case DESC:
case CreationDateDESC:
qb.orderDesc(ArticleDao.Properties.CreationDate, ArticleDao.Properties.ArticleId);
break;

case EstimatedReadingTimeASC:
qb.orderAsc(ArticleDao.Properties.EstimatedReadingTime, ArticleDao.Properties.ArticleId);
break;
case EstimatedReadingTimeDESC:
qb.orderDesc(ArticleDao.Properties.EstimatedReadingTime, ArticleDao.Properties.ArticleId);
break;
default:
throw new IllegalStateException("Sort order not implemented: " + sortOrder);
}
Expand Down
Loading