diff --git a/.gitignore b/.gitignore index 7843a1d..e98b6d3 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,7 @@ gen/ *.apk *.ap_ *.class +.idea/ +.gradle/ +build/ +local.properties diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..9fc1d1e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,26 @@ +language: android +android: + components: + # Uncomment the lines below if you want to + # use the latest revision of Android SDK Tools + - platform-tools + - tools + + # The BuildTools version used by your project + - build-tools-21.0.0 + + # The SDK version used to compile your project + - android-21 + + # Additional components + # - extra-google-google_play_services + # - extra-google-m2repository + # - extra-android-m2repository + # - addon-google_apis-google-19 + + # Specify at least one system image, + # if you need to run emulator(s) during your tests + # - sys-img-armeabi-v7a-android-19 + # - sys-img-x86-android-17 + +script: ./gradlew build check diff --git a/AndroidManifest.xml b/AndroidManifest.xml deleted file mode 100644 index e621f87..0000000 --- a/AndroidManifest.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/README b/README deleted file mode 100644 index 5eb7710..0000000 --- a/README +++ /dev/null @@ -1,5 +0,0 @@ -Poche by Jonathan GAULUPEAU - -Google Androïd application to add post to Poche - -This application is released under GPL. diff --git a/README.md b/README.md new file mode 100644 index 0000000..5532a03 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# wallabag - Android App [![Build Status](https://travis-ci.org/wallabag/android-app.svg?branch=rss-feed)](https://travis-ci.org/wallabag/android-app) + +wallabag app for Android, originally written by Jonathan GAULUPEAU + +Android application to add post to wallabag + +This application is released under GPL. wallabag is released under the MIT licence. diff --git a/android-app.iml b/android-app.iml new file mode 100644 index 0000000..0bb6048 --- /dev/null +++ b/android-app.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/app.iml b/app/app.iml new file mode 100644 index 0000000..bd5df84 --- /dev/null +++ b/app/app.iml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..f565250 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,24 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 21 + buildToolsVersion '21' + + defaultConfig { + applicationId "fr.gaulupeau.apps.InThePoche" + minSdkVersion 8 + targetSdkVersion 21 + versionCode 9 + versionName "1.6" + } + buildTypes { + release { + runProguard false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile 'com.android.support:appcompat-v7:21.0.0' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..2d34300 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,16 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..9466ad0 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/assets/main.css b/app/src/main/assets/main.css new file mode 100755 index 0000000..40f485e --- /dev/null +++ b/app/src/main/assets/main.css @@ -0,0 +1,243 @@ +/* ========================================================================== + Sommaire + + 1 = Style Guide + 2 = Layout + 3 = Pictos + 4 = Messages + 5 = Article + 6 = Media queries + + ========================================================================== */ + +html { + min-height: 100%; +} + +body { + background: #EEE; +} + +/* ========================================================================== + 1 = Style Guide + ========================================================================== */ + +::selection { + color: #FFF; + background: #000; +} + +h2, h3, h4 { + font-family: 'PT Sans', sans-serif; + text-transform: uppercase; +} + +p, li { + color: #666; +} + +a { + color: #000; + font-weight: bold; +} + +a:hover, a:focus { + text-decoration: none; +} + +h2:after { + content: ""; + height: 4px; + width: 70px; + background: #000; + display: block; +} + +.links { + padding: 0; + margin: 0; +} + .links li { + list-style: none; + margin: 0; + padding: 0; + } + + +#links { + position: fixed; + top: 0; + width: 10em; + left: 0; + text-align: right; + background: #333; + padding-top: 9.5em; + height: 100%; + box-shadow:inset -4px 0 20px rgba(0,0,0,0.6); + z-index: 10; +} + +#main { + margin-left: 13em; + position: relative; + z-index: 10; + padding-right: 5%; + padding-bottom: 1em; +} + + #links a { + display: block; + padding: 0.5em 2em 0.5em 1em; + color: #FFF; + position: relative; + text-transform: uppercase; + text-decoration: none; + font-weight: normal; + font-family: 'PT Sans', sans-serif; + -webkit-transition: all 0.5s ease; + -moz-transition: all 0.5s ease; + -ms-transition: all 0.5s ease; + -o-transition: all 0.5s ease; + transition: all 0.5s ease; + } + + #links a:hover, #links a:focus { + background: #999; + color: #000; + } + + #links .current:after { + content: ""; + width: 0; + height: 0; + position: absolute; + border-style: solid; + border-width: 10px; + border-color: transparent #EEE transparent transparent; + right: 0; + top: 50%; + margin-top: -10px; + } + + #links li:last-child { + position: fixed; + bottom: 1em; + width: 10em; + } + + #links li:last-child a:before { + font-size: 1.2em; + position: relative; + top: 2px; + } + + + +/* ========================================================================== + 2 = Layout + ========================================================================== */ + +#content { + margin-top: 1em; + min-height: 30em; +} + +footer { + text-align: right; + position: relative; + bottom: 0; + right: 5em; + color: #999; + font-size: 0.8em; + font-style: italic; + z-index: 20; +} + +footer a { + color: #999; + font-weight: normal; +} + +/* ========================================================================== + 5 = Article + ========================================================================== */ + +header.mbm { + text-align: left; +} + +#article { + width: 70%; +/* margin-bottom: 3em; */ + text-align: justify; + word-wrap: break-word; +} + +#article .tags { + margin-bottom: 1em; +} + +#article i { + font-style: normal; +} + +blockquote { + border:1px solid #999; + background: #FFF; + padding: 1em; + margin: 0; +} + +#article h2, #article h3, #article h4 { + text-transform: none; +} + +#article h2:after { + content: none; +} + +/* ========================================================================== + 6 = Media Queries + ========================================================================== */ + + +@media screen { + body > header { + background: #333; + position: fixed; + top: 0; + width: 100%; + height: 3em; + z-index: 11; + } + #links li:last-child { + position: static; + width: auto; + } + #links li:last-child a:before { + content: none; + } + #links { + display: none; + width: 100%; + height: auto; + padding-top: 3em; + } + footer { + position: static; + margin-right: 3em; + } + #main { + margin-left: 1.5em; + padding-right: 1.5em; + position: static; + } + + #article { + width: 100%; + } + + #article h1 { + font-size: 1.2em; + } +} diff --git a/app/src/main/assets/ratatouille.css b/app/src/main/assets/ratatouille.css new file mode 100644 index 0000000..1901693 --- /dev/null +++ b/app/src/main/assets/ratatouille.css @@ -0,0 +1,155 @@ +/* + Ratatouille mini Framework css by Thomas LEBEAU + Base on KNACSS => www.KNACSS.com (2013-10) @author: Raphael Goetter, Alsacreations + and normalize.css +*/ + +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +body { + font-size: 1em; + line-height:1.5; + margin: 0; +} + +/* ========================================================================== + Mise en forme + ========================================================================== */ + +h1:first-child, +h2:first-child, +h3:first-child, +h4:first-child, +h5:first-child, +h6:first-child, +p:first-child, +ul:first-child, +ol:first-child, +dl:first-child{ + margin-top: 0; +} + +code, +kbd, +pre, +samp { + font-family: monospace, serif; +} + +pre { + white-space: pre-wrap; +} + + +.upper { + text-transform: uppercase; +} + +.bold { + font-weight: bold; +} + +.inner { + margin: 0 auto; + max-width: 61.25em;/*980px*/ +} + +table, img { + max-width: 100%; + height :auto; +} + +iframe { + max-width: 100%; +} + +.fl { + float: left; +} + +.fr { + float: right; +} + +table { + border-collapse: collapse; +} + +figure { + margin: 0; +} + +button, +input, +select, +textarea { + font-family: inherit; + font-size: 100%; + margin: 0; +} + +input[type="search"] { + -webkit-appearance: textfield; +} + +/* ========================================================================== + Mise en page + ========================================================================== */ + +.dib { + display: inline-block; + vertical-align: middle; +} + +.dnone { + display: none; +} + +.dtable { display:table } + + .dtable > * { display:table-row; } + + .dtable > * > * { display:table-cell; } + +.element-invisible { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +.small { + font-size:0.8em; +} + +.big { + font-size: 1.2em; +} + +/*Width*/ + +.w100 { width:100%; } +.w90 { width:90%; } +.w80 { width:80%; } +.w70 { width:70%; } +.w60 { width:60%; } +.w50 { width:50%; } +.w40 { width:40%; } +.w30 { width:30%; } +.w20 { width:20%; } +.w10 { width:10%; } + diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/Article.java b/app/src/main/java/fr/gaulupeau/apps/Poche/Article.java new file mode 100644 index 0000000..334a2b1 --- /dev/null +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/Article.java @@ -0,0 +1,35 @@ +package fr.gaulupeau.apps.Poche; + +import java.net.URL; + +public class Article { + public String url; + public String id; + public String title; + public String content; + public String archive; + + private URL m_url = null; + + public Article(String url, String id, String title, String content, String archive) { + super(); + this.url = url; + this.id = id; + this.title = title; + this.content = content; + this.archive = archive; + + try { + this.m_url = new URL(url); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public String getHostOfUrl() { + if (this.m_url != null) { + return m_url.getHost(); + } + return ""; + } +} diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/ArticlesSQLiteOpenHelper.java b/app/src/main/java/fr/gaulupeau/apps/Poche/ArticlesSQLiteOpenHelper.java new file mode 100644 index 0000000..7a9a261 --- /dev/null +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/ArticlesSQLiteOpenHelper.java @@ -0,0 +1,79 @@ +package fr.gaulupeau.apps.Poche; + +import android.content.Context; +import android.content.SharedPreferences; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import static fr.gaulupeau.apps.Poche.Helpers.PREFS_NAME; +import static fr.gaulupeau.apps.Poche.Helpers.zeroUpdate; + + +public class ArticlesSQLiteOpenHelper extends SQLiteOpenHelper { + + + public static final int VERSION = 1; + public static final String DB_NAME = "article_db.sqlite"; + public static String MY_ID = "my_id"; + public static String ARTICLE_TABLE = "article"; + public static String ARTICLE_DATE = "update_date"; + public static String ARTICLE_ID = "article_id"; + public static String ARTICLE_AUTHOR = "author"; + public static String ARTICLE_CONTENT = "content"; + public static String ARTICLE_TITLE = "title"; + public static String ARTICLE_URL = "url"; + public static String ARCHIVE = "archive"; + public static String ARTICLE_SYNC = "sync"; + public static String ARTICLE_READAT = "read_at"; + Context c; + + public ArticlesSQLiteOpenHelper(Context context) { + super(context, DB_NAME, null, VERSION); + c = context; + } + + @Override + public void onCreate(SQLiteDatabase db) { + createTables(db); + } + + + @Override + public void onOpen(SQLiteDatabase db) { + // TODO Auto-generated method stub + super.onOpen(db); + } + + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + db.delete(ARTICLE_TABLE, null, null); + SharedPreferences preferences = c.getSharedPreferences(PREFS_NAME, 0); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString("previous_update", zeroUpdate); + editor.commit(); + } + + protected void createTables(SQLiteDatabase db) { + db.execSQL( + "create table " + ARTICLE_TABLE + " (" + + MY_ID + " integer primary key autoincrement not null, " + + ARTICLE_AUTHOR + " text, " + + ARTICLE_DATE + " datetime, " + + ARTICLE_CONTENT + " text, " + + ARTICLE_TITLE + " text, " + + ARTICLE_URL + " text, " + + ARTICLE_ID + " integer, " + + ARCHIVE + " integer," + + ARTICLE_SYNC + " integer," + + ARTICLE_READAT + " integer," + + "UNIQUE (" + ARTICLE_URL + ")" + + ");" + ); + } + + public void truncateTables(SQLiteDatabase db) { + db.execSQL("DELETE FROM " + ARTICLE_TABLE + ";"); + } + +} diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/BaseActionBarActivity.java b/app/src/main/java/fr/gaulupeau/apps/Poche/BaseActionBarActivity.java new file mode 100644 index 0000000..c230a78 --- /dev/null +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/BaseActionBarActivity.java @@ -0,0 +1,37 @@ +package fr.gaulupeau.apps.Poche; + + +import android.annotation.TargetApi; +import android.os.Build; +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +import android.view.MenuItem; + +public class BaseActionBarActivity extends ActionBarActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addBackButtonToActionBar(); + } + + @TargetApi(11) + protected void addBackButtonToActionBar() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + try { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } catch (Exception e) { + // + } + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + this.finish(); + return true; + } + return super.onOptionsItemSelected(item); + } +} diff --git a/src/fr/gaulupeau/apps/Poche/Helpers.java b/app/src/main/java/fr/gaulupeau/apps/Poche/Helpers.java similarity index 75% rename from src/fr/gaulupeau/apps/Poche/Helpers.java rename to app/src/main/java/fr/gaulupeau/apps/Poche/Helpers.java index c799f3a..5a89160 100644 --- a/src/fr/gaulupeau/apps/Poche/Helpers.java +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/Helpers.java @@ -1,36 +1,32 @@ package fr.gaulupeau.apps.Poche; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; - import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; -public class Helpers { - - public static final String PREFS_NAME = "InThePoche"; - public final static String zeroUpdate = "2011-01-01 00:00:00"; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; - public static String InputStreamtoString(InputStream is) - { - String s = "",line=""; +public class Helpers { + + public static final String PREFS_NAME = "InThePoche"; + public final static String zeroUpdate = "2011-01-01 00:00:00"; + + public static String InputStreamtoString(InputStream is) { + String s = "", line = ""; BufferedReader rd = new BufferedReader(new InputStreamReader(is)); - try{ - for(; ; rd.readLine()) - { - if((line = rd.readLine())!=null) - { - s +=line; - }else - { + try { + for (; ; rd.readLine()) { + if ((line = rd.readLine()) != null) { + s += line; + } else { break; } } - }catch (IOException e) { + } catch (IOException e) { // TODO: handle exception e.printStackTrace(); } @@ -38,7 +34,7 @@ public class Helpers { } public static String getInputStreamFromUrl(String url) { - InputStream content = null; + InputStream content; String res = ""; try { HttpGet httpGet = new HttpGet(url); diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/ListArticles.java b/app/src/main/java/fr/gaulupeau/apps/Poche/ListArticles.java new file mode 100644 index 0000000..055b93a --- /dev/null +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/ListArticles.java @@ -0,0 +1,111 @@ +package fr.gaulupeau.apps.Poche; + +import android.content.Intent; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ListView; + +import java.util.ArrayList; + +import fr.gaulupeau.apps.InThePoche.R; + +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARCHIVE; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARTICLE_CONTENT; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARTICLE_DATE; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARTICLE_TABLE; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARTICLE_TITLE; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARTICLE_URL; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.MY_ID; + +public class ListArticles extends BaseActionBarActivity { + + private ArrayList
readArticlesInfo; + private SQLiteDatabase database; + + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.list); + setupDB(); + setupList(false); + } + + public void onDestroy() { + super.onDestroy(); + database.close(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.option_list, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.menuShowAll: + setupList(true); + return true; + case R.id.menuWipeDb: + ArticlesSQLiteOpenHelper helper = new ArticlesSQLiteOpenHelper(this); + helper.truncateTables(database); + setupList(false); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + public void setupDB() { + ArticlesSQLiteOpenHelper helper = new ArticlesSQLiteOpenHelper(this); + database = helper.getWritableDatabase(); + } + + public void setupList(Boolean showAll) { + ListView readList = (ListView) findViewById(R.id.liste_articles); + readArticlesInfo = new ArrayList
(); + String filter = null; + if (!showAll) { + filter = ARCHIVE + "=0"; + } + ReadingListAdapter ad = getAdapterQuery(filter, readArticlesInfo); + readList.setAdapter(ad); + + readList.setOnItemClickListener(new AdapterView.OnItemClickListener() { + + public void onItemClick(AdapterView parent, View view, int position, long id) { + Intent i = new Intent(getBaseContext(), ReadArticle.class); + i.putExtra("id", readArticlesInfo.get(position).id); + startActivity(i); + } + + }); + } + + public ReadingListAdapter getAdapterQuery(String filter, ArrayList
articleInfo) { + //Log.e("getAdapterQuery", "running query"); + //String url, String domain, String id, String title, String content + String[] getStrColumns = new String[]{ARTICLE_URL, MY_ID, ARTICLE_TITLE, ARTICLE_CONTENT, ARCHIVE}; + Cursor ac = database.query( + ARTICLE_TABLE, + getStrColumns, + filter, null, null, null, ARTICLE_DATE + " DESC"); + ac.moveToFirst(); + if (!ac.isAfterLast()) { + do { + Article tempArticle = new Article(ac.getString(0), ac.getString(1), ac.getString(2), ac.getString(3), ac.getString(4)); + articleInfo.add(tempArticle); + } while (ac.moveToNext()); + } + ac.close(); + return new ReadingListAdapter(getBaseContext(), articleInfo); + } + +} diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/Poche.java b/app/src/main/java/fr/gaulupeau/apps/Poche/Poche.java new file mode 100644 index 0000000..a4fa478 --- /dev/null +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/Poche.java @@ -0,0 +1,634 @@ +/** + * Android to Poche + * A simple app to make the full save bookmark to Poche + * web page available via the Share menu on Android tablets + * @author GAULUPEAU Jonathan + * August 2013 + */ + +package fr.gaulupeau.apps.Poche; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.sqlite.SQLiteConstraintException; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.provider.Browser; +import android.util.Base64; +import android.util.Patterns; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.Toast; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.X509TrustManager; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import fr.gaulupeau.apps.InThePoche.R; + +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARCHIVE; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARTICLE_CONTENT; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARTICLE_DATE; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARTICLE_SYNC; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARTICLE_TABLE; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARTICLE_TITLE; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARTICLE_URL; +import static fr.gaulupeau.apps.Poche.Helpers.PREFS_NAME; + + +/** + * Main activity class + */ +@TargetApi(Build.VERSION_CODES.FROYO) +public class Poche extends Activity { + private static SQLiteDatabase database; + Button btnGetPost; + Button btnSync; + Button btnSettings; + SharedPreferences settings; + static String apiUsername; + static String apiToken; + static String pocheUrl; + String action; + + + /** + * Called when the activity is first created. + * Will act differently depending on whether sharing or + * displaying information page. + */ + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Intent intent = getIntent(); + Bundle extras = intent.getExtras(); + action = intent.getAction(); + + getSettings(); + // Find out if Sharing or if app has been launched from icon + if (action.equals(Intent.ACTION_SEND) && !pocheUrl.equals("http://")) { + setContentView(R.layout.main); + findViewById(R.id.btnSync).setVisibility(View.GONE); + findViewById(R.id.btnGetPost).setVisibility(View.GONE); + findViewById(R.id.progressBar1).setVisibility(View.VISIBLE); + + + + final String extraText = extras.getString("android.intent.extra.TEXT"); + final String pageUrl; + + // Parsing string for urls. + Matcher matcher = Patterns.WEB_URL.matcher(extraText); + if (matcher.find()) { + pageUrl = matcher.group(); + } else { + showErrorMessage("Couldn't find a URL in share string:\n"+extraText); + return; + } + + + // Vérification de la connectivité Internet + final ConnectivityManager conMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + final NetworkInfo activeNetwork = conMgr.getActiveNetworkInfo(); + if (activeNetwork != null && activeNetwork.isConnected()) { + // Start to build the poche URL + Uri.Builder pocheSaveUrl = Uri.parse(pocheUrl).buildUpon(); + // Add the parameters from the call + pocheSaveUrl.appendQueryParameter("action", "add"); + byte[] data = null; + try { + data = pageUrl.getBytes("UTF-8"); + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + String base64 = Base64.encodeToString(data, Base64.DEFAULT); + pocheSaveUrl.appendQueryParameter("url", base64); + System.out.println("base64 : " + base64); + System.out.println("pageurl : " + pageUrl); + + // Load the constructed URL in the browser + Intent i = new Intent(Intent.ACTION_VIEW); + i.setData(pocheSaveUrl.build()); + i.putExtra(Browser.EXTRA_APPLICATION_ID, getPackageName()); + // If user has more then one browser installed give them a chance to + // select which one they want to use + + startActivity(i); + // That is all this app needs to do, so call finish() + this.finish(); + } else { + // Afficher alerte connectivité + showToast(getString(R.string.txtNetOffline)); + } + } else { + setContentView(R.layout.main); + checkAndHandleAfterUpdate(); + + btnSync = (Button) findViewById(R.id.btnSync); + btnSync.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + // Vérification de la connectivité Internet + final ConnectivityManager conMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + final NetworkInfo activeNetwork = conMgr.getActiveNetworkInfo(); + if (pocheUrl.equals("http://")) { + showToast(getString(R.string.txtConfigNotSet)); + } else if (activeNetwork != null && activeNetwork.isConnected()) { + // Exécution de la synchro en arrière-plan + findViewById(R.id.progressBar1).setVisibility(View.VISIBLE); + new Thread(new Runnable() { + @Override + public void run() { + //pushRead(); + parseRSS(); + runOnUiThread(new Runnable() { + @Override + public void run() { + findViewById(R.id.progressBar1).setVisibility(View.GONE); + } + }); + } + }).start(); + } else { + // Afficher alerte connectivité + showToast(getString(R.string.txtNetOffline)); + } + + } + }); + + btnGetPost = (Button) findViewById(R.id.btnGetPost); + //updateUnread(); + + btnGetPost.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(getBaseContext(), ListArticles.class)); + } + }); + + btnSettings = (Button) findViewById(R.id.btnSettings); + btnSettings.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + startActivity(new Intent(getBaseContext(), Settings.class)); + } + }); + } + } + + private void checkAndHandleAfterUpdate() { + SharedPreferences pref = getSharedPreferences(PREFS_NAME, 0); + + if (pref.getInt("update_checker", 0) < 9) { + // Wipe Database, because we now save HTML content instead of plain text + ArticlesSQLiteOpenHelper helper = new ArticlesSQLiteOpenHelper(this); + database = helper.getReadableDatabase(); + helper.truncateTables(database); + showToast("Update: Wiped Database. Please synchronize."); + } + + int versionCode; + try { + versionCode = getApplicationContext().getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), 0).versionCode; + } catch (Exception e) { + versionCode = 0; + } + + pref.edit().putInt("update_checker", versionCode).commit(); + } + + private void getSettings() { + settings = getSharedPreferences(PREFS_NAME, 0); + pocheUrl = settings.getString("pocheUrl", "http://"); + apiUsername = settings.getString("APIUsername", ""); + apiToken = settings.getString("APIToken", ""); + } + + @Override + protected void onResume() { + super.onResume(); + getSettings(); + if (!action.equals(Intent.ACTION_SEND)) { + updateUnread(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (database != null) { + database.close(); + } + } + + private void updateUnread() { + runOnUiThread(new Runnable() { + public void run() { + ArticlesSQLiteOpenHelper helper = new ArticlesSQLiteOpenHelper(getApplicationContext()); + database = helper.getReadableDatabase(); + int news = database.query(ARTICLE_TABLE, null, ARCHIVE + "=0", null, null, null, null).getCount(); + btnGetPost.setText(String.format(getString(R.string.btnGetPost), news)); + } + }); + } + + public void showToast(final String toast) { + runOnUiThread(new Runnable() { + public void run() { + Toast.makeText(Poche.this, toast, Toast.LENGTH_SHORT).show(); + } + }); + } + + private void showErrorMessage(final String message) { + runOnUiThread(new Runnable() { + @Override + public void run() { + AlertDialog.Builder messageBox = new AlertDialog.Builder(Poche.this); + messageBox.setMessage(message); + messageBox.setTitle(getString(R.string.error)); +// messageBox.setIconAttribute(android.R.attr.alertDialogIcon); + messageBox.setPositiveButton("OK", null); + messageBox.setCancelable(false); + messageBox.create().show(); + } + }); + } + +// public void pocheIt(String url){ +// String id ="req-001"; +// JSONRPC2Request reqOut = null; +// try{ +// reqOut = JSONRPC2Request.parse("{\"jsonrpc\":\"2.0\",\"method\":\"item.add\",\"id\":\"" + id + "\",\"params\":[{\"username\":\""+ apiUsername + "\",\"api_token\":\""+ apiToken +"\"}, \"" + url + "\", true]}"); +// System.err.println(reqOut.toString()); +// JSONRPC2Response response = sendRequest(reqOut); +// if (response.indicatesSuccess()) { +// showToast(getString(R.string.txtSyncDone)); +// } +// } catch (JSONRPC2ParseException e2) { +// e2.printStackTrace(); +// showToast(getString(R.string.txtSyncFailed)); +// } +// finish(); +// } + + +// public void pushRead(){ +// JSONRPC2Request reqOut = null; +// String filter = ARCHIVE + "=1 AND " + ARTICLE_SYNC + "=0"; +// String[] getStrColumns = new String[] {ARTICLE_ID}; +// Cursor ac = database.query( +// ARTICLE_TABLE, +// getStrColumns, +// filter, null, null, null, null); +// ac.moveToFirst(); +// if(!ac.isAfterLast()) { +// do { +// String article_id = ac.getString(0); +// String id ="req-001"; +// try{ +// reqOut = JSONRPC2Request.parse("{\"jsonrpc\":\"2.0\",\"method\":\"item.mark_as_read\",\"id\":\"" + id + "\",\"params\":[{\"username\":\""+ apiUsername + "\",\"api_token\":\""+ apiToken +"\"}, " + article_id + "]}"); +// System.err.println(reqOut.toString()); +// JSONRPC2Response response = sendRequest(reqOut); +// if (response.indicatesSuccess()) { +// ContentValues values = new ContentValues(); +// values.put(ARTICLE_SYNC, 1); +// database.update(ARTICLE_TABLE, values, ARTICLE_ID + "=" + article_id, null); +// } +// } catch (JSONRPC2ParseException e2) { +// e2.printStackTrace(); +// } +// } while (ac.moveToNext()); +// } +// ac.close(); +// +// } + + + public String cleanString(String s) { + + s = s.replace("é", "é"); + s = s.replace("è", "è"); + s = s.replace("ê", "ê"); + s = s.replace("ë", "ë"); + s = s.replace("à", "à"); + s = s.replace("ä", "ä"); + s = s.replace("â", "â"); + s = s.replace("ù", "ù"); + s = s.replace("û", "û"); + s = s.replace("ü", "ü"); + s = s.replace("ô", "ô"); + s = s.replace("ö", "ö"); + s = s.replace("î", "î"); + s = s.replace("ï", "ï"); + s = s.replace("ç", "ç"); + s = s.replace("&", "&"); + + // Replace multiple whitespaces with single space + s = s.replaceAll("\\s+", " "); + s = s.trim(); + + return s; + } + + + private void trustEveryone() { + try { + HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { + public boolean verify(String hostname, SSLSession session) { + return true; + } + }); + SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, new X509TrustManager[]{new X509TrustManager() { + public void checkClientTrusted(X509Certificate[] chain, + String authType) throws CertificateException { + } + + public void checkServerTrusted(X509Certificate[] chain, + String authType) throws CertificateException { + } + + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + }}, new SecureRandom()); + HttpsURLConnection.setDefaultSSLSocketFactory( + context.getSocketFactory()); + } catch (Exception e) { // should never happen + e.printStackTrace(); + } + } + + + public void parseRSS() { + + URL url; + try { + // Set the url (you will need to change this to your RSS URL + url = new URL(pocheUrl + "/?feed&type=home&user_id=" + apiUsername + "&token=" + apiToken); + if (pocheUrl.startsWith("https")) { + trustEveryone(); + } + + // Setup the connection + HttpURLConnection urlConnection; + urlConnection = (HttpURLConnection) url.openConnection(); + + if ((urlConnection != null) && (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK)) { + + // Retreive the XML from the URL + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = null; + + InputSource is; + + try { + is = new InputSource( + new InputStreamReader( + urlConnection.getInputStream())); + doc = db.parse(is); + doc.getDocumentElement().normalize(); + } catch (SAXException e) { + e.printStackTrace(); + + InputStream inputStream = url.openStream(); + int ch; + StringBuffer stringBuffer = new StringBuffer(); + while ((ch = inputStream.read()) != -1) { + stringBuffer.append((char) ch); + } + showErrorMessage("Got invalid response:\n\"" + stringBuffer.toString() + "\""); + } + + // This is the root node of each section you want to parse + NodeList itemLst = doc.getElementsByTagName("item"); + + // This sets up some arrays to hold the data parsed + arrays.PodcastTitle = new String[itemLst.getLength()]; + arrays.PodcastURL = new String[itemLst.getLength()]; + arrays.PodcastContent = new String[itemLst.getLength()]; + arrays.PodcastMedia = new String[itemLst.getLength()]; + arrays.PodcastDate = new String[itemLst.getLength()]; + + // Loop through the XML passing the data to the arrays + for (int i = 0; i < itemLst.getLength(); i++) { + + Node item = itemLst.item(i); + if (item.getNodeType() == Node.ELEMENT_NODE) { + Element ielem = (Element) item; + + // This section gets the elements from the XML + // that we want to use you will need to add + // and remove elements that you want / don't want + NodeList title = ielem.getElementsByTagName("title"); + NodeList link = ielem.getElementsByTagName("link"); + NodeList date = ielem.getElementsByTagName("pubDate"); + NodeList content = ielem + .getElementsByTagName("description"); + //NodeList media = ielem + // .getElementsByTagName("media:content"); + + // This is an attribute of an element so I create + // a string to make it easier to use + //String mediaurl = media.item(0).getAttributes() + // .getNamedItem("url").getNodeValue(); + + // This section adds an entry to the arrays with the + // data retrieved from above. I have surrounded each + // with try/catch just incase the element does not + // exist + try { + arrays.PodcastTitle[i] = cleanString(title.item(0).getChildNodes().item(0).getNodeValue()); + } catch (NullPointerException e) { + e.printStackTrace(); + arrays.PodcastTitle[i] = "Echec"; + } + try { + arrays.PodcastDate[i] = date.item(0).getChildNodes().item(0).getNodeValue(); + } catch (NullPointerException e) { + e.printStackTrace(); + arrays.PodcastDate[i] = null; + } + try { + arrays.PodcastURL[i] = link.item(0).getChildNodes() + .item(0).getNodeValue(); + } catch (NullPointerException e) { + e.printStackTrace(); + arrays.PodcastURL[i] = "Echec"; + } + try { + arrays.PodcastContent[i] = content.item(0) + .getChildNodes().item(0).getNodeValue(); + } catch (NullPointerException e) { + e.printStackTrace(); + arrays.PodcastContent[i] = "Echec"; + } + + ContentValues values = new ContentValues(); + values.put(ARTICLE_TITLE, arrays.PodcastTitle[i]); + values.put(ARTICLE_CONTENT, arrays.PodcastContent[i]); + //values.put(ARTICLE_ID, Html.fromHtml(article.getString("id")).toString()); + values.put(ARTICLE_URL, arrays.PodcastURL[i]); + values.put(ARTICLE_DATE, arrays.PodcastDate[i]); + values.put(ARCHIVE, 0); + values.put(ARTICLE_SYNC, 0); + try { + database.insertOrThrow(ARTICLE_TABLE, null, values); + } catch (SQLiteConstraintException e) { + continue; + } catch (SQLiteException e) { + database.execSQL("ALTER TABLE " + ARTICLE_TABLE + " ADD COLUMN " + ARTICLE_DATE + " datetime;"); + database.insertOrThrow(ARTICLE_TABLE, null, values); + } + } + } + + showToast(getString(R.string.txtSyncDone)); + } else { + // HTTP Connection not successful + if (urlConnection == null) { + showErrorMessage(getString(R.string.error_feed)); + } else { + showErrorMessage(getString(R.string.error_feed) + ":\n" + urlConnection.getResponseCode() + " " + urlConnection.getResponseMessage()); + } + } + updateUnread(); + } catch (Exception e) { + e.printStackTrace(); + } + + + } + +// public void fetchUnread(){ +// String id = "req-001"; +// JSONRPC2Request reqOut = null; +// try { +// // POCHE A LINK +// //reqOut = JSONRPC2Request.parse("{\"jsonrpc\":\"2.0\",\"method\":\"item.add\",\"id\":\"req-001\",\"params\":[{\"username\":\"poche\",\"api_token\":\"cPG2urVgA+ToMXY\"},\"http://cdetc.fr\",true]}"); +// // GET A LINK +// //reqOut = JSONRPC2Request.parse("{\"jsonrpc\":\"2.0\",\"method\":\"item.info\",\"id\":\"" + id + "\",\"params\":[{\"username\":\""+ apiUsername + "\",\"api_token\":\""+ apiToken +"\"}, 1]}"); +// // GET ALL UNREAD +// reqOut = JSONRPC2Request.parse("{\"jsonrpc\":\"2.0\",\"method\":\"item.list_unread\",\"id\":\"" + id + "\",\"params\":[{\"username\":\""+ apiUsername + "\",\"api_token\":\""+ apiToken +"\"}, null, null]}"); +// System.err.println(reqOut.toString()); +// } catch (JSONRPC2ParseException e2) { +// e2.printStackTrace(); +// } +// System.out.println(reqOut.toString()); +// URL url = null; +// try { +// final String rpcuser ="api_user"; +// final String rpcpassword = globalToken; +// +// Authenticator.setDefault(new Authenticator() { +// protected PasswordAuthentication getPasswordAuthentication() { +// return new PasswordAuthentication (rpcuser, rpcpassword.toCharArray()); +// }}); +// url = new URL(pocheUrl + "/jsonrpc.php"); +// } catch (MalformedURLException e1) { +// e1.printStackTrace(); +// } +// JSONRPC2Session session = new JSONRPC2Session(url); +// JSONRPC2Response response = null; +// try{ +// response = session.send(reqOut); +// } catch (JSONRPC2SessionException e) { +// +// System.err.println(e.getMessage()); +// } +// if (response.indicatesSuccess()){ +// JSONObject article = null; +// ContentValues values = new ContentValues(); +// try { +// JSONArray ret = new JSONArray(response.getResult().toString()); +// for (int i = 0; i < ret.length(); i++) { +// article = ret.getJSONObject(i); +// values.put(ARTICLE_TITLE, Html.fromHtml(article.getString("title")).toString()); +// values.put(ARTICLE_CONTENT, Html.fromHtml(article.getString("content")).toString()); +// values.put(ARTICLE_ID, Html.fromHtml(article.getString("id")).toString()); +// values.put(ARTICLE_URL, Html.fromHtml(article.getString("url")).toString()); +// values.put(ARCHIVE, 0); +// values.put(ARTICLE_SYNC, 0); +// try { +// database.insertOrThrow(ARTICLE_TABLE, null, values); +// } catch (SQLiteConstraintException e) { +// continue; +// } +// } +// } catch (JSONException e) { +// e.printStackTrace(); +// showToast(getString(R.string.txtSyncFailed)); +// } +// +// showToast(getString(R.string.txtSyncDone)); +// updateUnread(); +// }else{ +// System.out.println(response.getError().getMessage( )); +// showToast(getString(R.string.txtSyncFailed)); +// } +// } +// +// public JSONRPC2Response sendRequest(JSONRPC2Request reqOut){ +// URL url = null; +// try { +// final String rpcuser ="api_user"; +// final String rpcpassword = globalToken; +// +// Authenticator.setDefault(new Authenticator() { +// protected PasswordAuthentication getPasswordAuthentication() { +// return new PasswordAuthentication (rpcuser, rpcpassword.toCharArray()); +// }}); +// url = new URL(pocheUrl + "/jsonrpc.php"); +// } catch (MalformedURLException e1) { +// e1.printStackTrace(); +// } +// JSONRPC2Session session = new JSONRPC2Session(url); +// JSONRPC2Response response = null; +// try{ +// response = session.send(reqOut); +// } catch (JSONRPC2SessionException e) { +// +// System.err.println(e.getMessage()); +// } +// return response; +// } + +} + diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/ReadArticle.java b/app/src/main/java/fr/gaulupeau/apps/Poche/ReadArticle.java new file mode 100644 index 0000000..594ff2b --- /dev/null +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/ReadArticle.java @@ -0,0 +1,118 @@ +package fr.gaulupeau.apps.Poche; + +import android.content.ContentValues; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; +import android.webkit.WebView; +import android.widget.Button; +import android.widget.ScrollView; + +import java.net.URL; + +import fr.gaulupeau.apps.InThePoche.R; + +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARCHIVE; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARTICLE_AUTHOR; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARTICLE_CONTENT; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARTICLE_ID; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARTICLE_TABLE; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARTICLE_TITLE; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.ARTICLE_URL; +import static fr.gaulupeau.apps.Poche.ArticlesSQLiteOpenHelper.MY_ID; + +public class ReadArticle extends BaseActionBarActivity { + WebView webViewContent; + Button btnMarkRead; + SQLiteDatabase database; + String id = ""; + ScrollView view; + + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.article); + + view = (ScrollView) findViewById(R.id.scroll); + ArticlesSQLiteOpenHelper helper = new ArticlesSQLiteOpenHelper(getApplicationContext()); + database = helper.getWritableDatabase(); + String[] getStrColumns = new String[]{ARTICLE_URL, MY_ID, ARTICLE_TITLE, ARTICLE_CONTENT, ARCHIVE, ARTICLE_AUTHOR}; + Bundle data = getIntent().getExtras(); + if (data != null) { + id = data.getString("id"); + } + Cursor ac = database.query(ARTICLE_TABLE, getStrColumns, MY_ID + "=" + id, null, null, null, null); + ac.moveToFirst(); + + String titleText = ac.getString(2); + String originalUrlText = ac.getString(0); + String originalUrlDesc = originalUrlText; + String htmlContent = ac.getString(3); + + try { + URL originalUrl = new URL(originalUrlText); + originalUrlDesc = originalUrl.getHost(); + } catch (Exception e) { + // + } + + String htmlHeader = "\n" + + "\t\n" + + "\t\t\n" + + "\t\t\n" + + "\t\t\n" + + "\t\t\n" + + "\t\n" + + "\t\t
\n" + + "\t\t\t\n" + + "\t\t\t\t
\n" + + "\t\t\t\t\t
\n" + + "\t\t\t\t\t\t
\n" + + "\t\t\t\t\t\t\t

" + titleText + "

\n" + + "\t\t\t\t\t\t\t

Open Original: " + originalUrlDesc + "

\n" + + "\t\t\t\t\t\t
\n" + + "\t\t\t\t\t\t
"; + String htmlFooter = "
\n" + + "\t\t\t\t\t
\n" + + "\t\t\t\t
\n" + + "\t\t\t\n" + + "\t\t
\n" + + ""; + + + webViewContent = (WebView) findViewById(R.id.webViewContent); + webViewContent.loadDataWithBaseURL("file:///android_asset/", htmlHeader + htmlContent + htmlFooter, "text/html", "utf-8", null); + + btnMarkRead = (Button) findViewById(R.id.btnMarkRead); + btnMarkRead.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + ContentValues values = new ContentValues(); + values.put(ARCHIVE, 1); + database.update(ARTICLE_TABLE, values, MY_ID + "=" + id, null); + finish(); + } + }); + + + } + + @Override + protected void onStop() { + // TODO Auto-generated method stub + + ContentValues values = new ContentValues(); + values.put("read_at", view.getScrollY()); + database.update(ARTICLE_TABLE, values, ARTICLE_ID + "=" + id, null); + System.out.println(view.getScrollY()); + super.onStop(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + database.close(); + } +} diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/ReadingListAdapter.java b/app/src/main/java/fr/gaulupeau/apps/Poche/ReadingListAdapter.java new file mode 100644 index 0000000..039ffb5 --- /dev/null +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/ReadingListAdapter.java @@ -0,0 +1,51 @@ +package fr.gaulupeau.apps.Poche; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; + +import java.util.List; + +import fr.gaulupeau.apps.InThePoche.R; + +public class ReadingListAdapter extends BaseAdapter { + private Context context; + private List
listArticles; + + public ReadingListAdapter(Context context, List
listArticles) { + this.context = context; + this.listArticles = listArticles; + } + + + public int getCount() { + return listArticles.size(); + } + + public Object getItem(int position) { + return listArticles.get(position); + } + + public long getItemId(int position) { + return position; + } + + public View getView(int position, View convertView, ViewGroup parent) { + Article entry = listArticles.get(position); + if (convertView == null) { + LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + convertView = inflater.inflate(R.layout.article_list, parent, false); + } + TextView tvTitle = (TextView) convertView.findViewById(R.id.listitem_titre); + TextView tvHost = (TextView) convertView.findViewById(R.id.listitem_textview_url); + + tvTitle.setText(entry.title); + tvHost.setText(entry.getHostOfUrl()); + + return convertView; + } + +} diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/Settings.java b/app/src/main/java/fr/gaulupeau/apps/Poche/Settings.java new file mode 100644 index 0000000..2edd500 --- /dev/null +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/Settings.java @@ -0,0 +1,56 @@ +package fr.gaulupeau.apps.Poche; + +import android.content.SharedPreferences; +import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; + +import fr.gaulupeau.apps.InThePoche.R; + +import static fr.gaulupeau.apps.Poche.Helpers.PREFS_NAME; + +public class Settings extends BaseActionBarActivity { + Button btnDone; + EditText editPocheUrl; + EditText editAPIUsername; + EditText editAPIToken; + TextView textViewVersion; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.settings); + + SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); + String pocheUrl = settings.getString("pocheUrl", "http://"); + String apiUsername = settings.getString("APIUsername", ""); + String apiToken = settings.getString("APIToken", ""); + editPocheUrl = (EditText) findViewById(R.id.pocheUrl); + editPocheUrl.setText(pocheUrl); + editAPIUsername = (EditText) findViewById(R.id.APIUsername); + editAPIUsername.setText(apiUsername); + editAPIToken = (EditText) findViewById(R.id.APIToken); + editAPIToken.setText(apiToken); + btnDone = (Button) findViewById(R.id.btnDone); + btnDone.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); + SharedPreferences.Editor editor = settings.edit(); + editor.putString("pocheUrl", editPocheUrl.getText().toString()); + editor.putString("APIUsername", editAPIUsername.getText().toString()); + editor.putString("APIToken", editAPIToken.getText().toString()); + editor.commit(); + finish(); + } + }); + try { + textViewVersion = (TextView) findViewById(R.id.version); + textViewVersion.setText(getApplicationContext().getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), 0).versionName); + } catch (Exception e) { + // + } + } +} diff --git a/app/src/main/java/fr/gaulupeau/apps/Poche/arrays.java b/app/src/main/java/fr/gaulupeau/apps/Poche/arrays.java new file mode 100644 index 0000000..a993a45 --- /dev/null +++ b/app/src/main/java/fr/gaulupeau/apps/Poche/arrays.java @@ -0,0 +1,9 @@ +package fr.gaulupeau.apps.Poche; + +public class arrays { + public static String[] PodcastTitle; + public static String[] PodcastURL; + public static String[] PodcastContent; + public static String[] PodcastMedia; + public static String[] PodcastDate; +} diff --git a/app/src/main/res/drawable-hdpi/icon.png b/app/src/main/res/drawable-hdpi/icon.png new file mode 100755 index 0000000..c6d179d Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon.png differ diff --git a/app/src/main/res/drawable-mdpi/icon.png b/app/src/main/res/drawable-mdpi/icon.png new file mode 100755 index 0000000..8d2a8b6 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/icon.png differ diff --git a/app/src/main/res/drawable-mdpi/welcome.png b/app/src/main/res/drawable-mdpi/welcome.png new file mode 100755 index 0000000..8aeb2b3 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/welcome.png differ diff --git a/app/src/main/res/drawable-xhdpi/icon.png b/app/src/main/res/drawable-xhdpi/icon.png new file mode 100755 index 0000000..b3e9263 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/icon.png differ diff --git a/app/src/main/res/drawable-xxhdpi/icon.png b/app/src/main/res/drawable-xxhdpi/icon.png new file mode 100755 index 0000000..a6c2d0e Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/icon.png b/app/src/main/res/drawable-xxxhdpi/icon.png new file mode 100755 index 0000000..542dff6 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/icon.png differ diff --git a/app/src/main/res/layout/article.xml b/app/src/main/res/layout/article.xml new file mode 100644 index 0000000..479575b --- /dev/null +++ b/app/src/main/res/layout/article.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + +