Compare commits

...

25 Commits

Author SHA1 Message Date
b447ac738a Fixes #62. 2017-08-31 20:00:58 +02:00
faebfc238c Closes #69. 2017-08-30 22:11:29 +02:00
c28fbd37cc Fixed issue with last commit. 2017-08-30 07:34:48 +02:00
4b8396959d Needed to add an exception for the log to work. 2017-08-30 07:22:28 +02:00
b39d510e07 Added reading article log. 2017-08-29 22:49:20 +02:00
286dda7f80 Update README.md 2017-08-27 19:33:21 +02:00
7bda896e2d Added the ability to choose the number of items loaded. 2017-08-26 21:36:19 +02:00
ba4feeea87 Trying to fix pre-lolipop svg drawable loading. 2017-08-16 22:15:33 +02:00
6f52eae3c6 Version updates. 2017-08-16 21:18:15 +02:00
40ea8d56e6 Closes #64 2017-08-16 20:18:49 +02:00
72e562e8a8 Reverted back to the old icon. 2017-08-16 07:51:28 +02:00
6fa01bfe19 Added changelog. 2017-08-04 21:44:29 +02:00
0ef59c9b91 Added a quick fix for accepting self signed certificates. 2017-08-04 21:42:35 +02:00
d768d2232b Added login optional debug logs. (#61) 2017-08-04 08:30:21 +02:00
b44a200731 A better icon. 2017-08-03 07:43:00 +02:00
016815e0d1 This test keep failing of firebase test lab. 2017-08-02 21:01:51 +02:00
590534e4a6 Splash screen fix, with some test problem. 2017-08-02 20:53:20 +02:00
7ea9d4e519 Changelog 2017-08-02 20:11:02 +02:00
e0ab09f533 Adaptive icon (#60)
* Removed mipmap folder from gitignore.

* New adaptive icon.

* Removed icon step from build.

* The icon seamed pixelated.
2017-08-02 20:08:31 +02:00
fbe98f1b16 Update CONTRIBUTING.md 2017-08-02 07:32:28 +02:00
d0675b8443 Update build.gradle 2017-07-30 19:01:05 +02:00
3ea1ed02ae Update build.gradle 2017-07-30 18:58:36 +02:00
ba120b1e0b Ignoring annoying bug with Samsung devices on 4.2.2 (#57)
* Updated gradle version.

* Fixed #55. Ignoring annoying non fatal bug on Samsung devices.
2017-07-30 18:37:44 +02:00
acf6995c2d Trying to handle app versionning from git tag. 2017-07-28 05:02:28 -04:00
8306860f90 Fixed #54 2017-07-28 07:33:21 +02:00
61 changed files with 494 additions and 80 deletions

View File

@ -22,7 +22,8 @@ Always check if the web version of your instance is working.
### Bug reports/Feature request ### Bug reports/Feature request
* Always search before reporting an issue or asking for a feature to avoid duplicates. * Always search before reporting an issue or asking for a feature to avoid duplicates.
* Include every usefull details (app version, phone model, Android version and screenshots when possible) * Include your unique user id. It's displayed on the debug settings page. (You can tap it, it'll be copied to your clipboard)
* Include every other useful details (app version, phone model, Android version and screenshots when possible).
* Avoid bumping non-fatal issues, or feature requests. I'll try to fix them as soon as possible, and try to prioritize the requests. (You may wan to use the [reactions](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments) for that) * Avoid bumping non-fatal issues, or feature requests. I'll try to fix them as soon as possible, and try to prioritize the requests. (You may wan to use the [reactions](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments) for that)
### Pull requests ### Pull requests
@ -38,18 +39,19 @@ Always check if the web version of your instance is working.
* Be willing to accept criticism on your PRs (as I am on mine). * Be willing to accept criticism on your PRs (as I am on mine).
* Remember that PR review can take time. * Remember that PR review can take time.
# Build the project # Build the project
You can directly import this project into IntellIJ/Android Studio. You can directly import this project into IntellIJ/Android Studio.
You'll have to: You'll have to:
- [Create your own launcher icon](https://developer.android.com/studio/write/image-asset-studio.html#creating-launcher)
- Configure Fabric, or [remove it](https://docs.fabric.io/android/fabric/settings/removing.html#). - Configure Fabric, or [remove it](https://docs.fabric.io/android/fabric/settings/removing.html#).
- Create a firebase project and add the `google-services.json` to the `app/` folder.
- Define the following in `res/values/strings.xml` or create `res/values/secrets.xml` - Define the following in `res/values/strings.xml` or create `res/values/secrets.xml`
- mercury: A [Mercury](https://mercury.postlight.com/web-parser/) web parser api key for the internal browser - mercury: A [Mercury](https://mercury.postlight.com/web-parser/) web parser api key for the internal browser
- feedback_email: An email to receive users feedback. - feedback_email: An email to receive users feedback.
- source_url: an url to the source code, used in the settings - source_url: an url to the source code, used in the settings
- tracker_url: an url to the tracker, used in the settings - tracker_url: an url to the tracker, used in the settings
- To run your app, you'll have to add `-P appLoginUrl="your.selfoss-instance.url" -P appLoginUsername="Username" -P appLoginPassword="password"`. (These are only used to run the espresso tests. You should be able to use empty strings or fake values to build the app)

1
.gitignore vendored
View File

@ -216,5 +216,4 @@ gradle-app.setting
secrets.xml secrets.xml
mipmap-*
release/ release/

View File

@ -1,4 +1,52 @@
**1.5.1.9** **1.5.2.12**
- Self signed certificates are now working for loading data. Image are not loading yet.
**1.5.2.11**
- Added a random unique identifier to be used in the logs.
**1.5.2.08/09/10**
- Added settable logs for reading articles problems.
**1.5.2.07**
- Added the ability to choose the number of items loaded (the maximum value is 200 and is imposed by the selfoss api)
**1.5.2.06**
- Fix problem introduced in 1.5.2.04. SVG file not working on older versions of android.
**1.5.2.05**
- Versions updates
**1.5.2.04**
- Reverted to the old icon.
- Better icon for the intro activity.
- Updated gradle version.
**1.5.2.03**
- Added the ability to accept self signed certificates. (Needs more testing)
**1.5.2.02**
- Added optional login option.
**1.5.2.01**
- New (Better) Icon !
**1.5.2.0**
- New Icon !
**1.5.1.9/10/11**
- Hiding the unread badge when marking all items as read. - Hiding the unread badge when marking all items as read.

View File

@ -8,6 +8,21 @@ buildscript {
} }
} }
def gitVersion() {
def process = "git describe --abbrev=0 --tags".execute()
return process.text.substring(1).replaceAll("\\.", "")
}
def versionCodeFromGit() {
println "version code " + gitVersion().toInteger()
return gitVersion().toInteger()
}
def versionNameFromGit() {
println "version code " + gitVersion().trim()
return gitVersion().trim()
}
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'io.fabric' apply plugin: 'io.fabric'
@ -25,8 +40,8 @@ android {
applicationId "apps.amine.bou.readerforselfoss" applicationId "apps.amine.bou.readerforselfoss"
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 26 targetSdkVersion 26
versionCode 1519 versionCode versionCodeFromGit()
versionName "1.5.1.9" versionName versionNameFromGit()
// Enabling multidex support. // Enabling multidex support.
multiDexEnabled true multiDexEnabled true
@ -80,25 +95,25 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
// Android Support // Android Support
compile 'com.android.support:appcompat-v7:26.0.0' compile 'com.android.support:appcompat-v7:26.0.1'
compile 'com.android.support:design:26.0.0' compile 'com.android.support:design:26.0.1'
compile 'com.android.support:recyclerview-v7:26.0.0' compile 'com.android.support:recyclerview-v7:26.0.1'
compile 'com.android.support:support-v4:26.0.0' compile 'com.android.support:support-v4:26.0.1'
compile 'com.android.support:support-vector-drawable:26.0.0' compile 'com.android.support:support-vector-drawable:26.0.1'
compile 'com.android.support:customtabs:26.0.0' compile 'com.android.support:customtabs:26.0.1'
compile 'com.android.support:cardview-v7:26.0.0' compile 'com.android.support:cardview-v7:26.0.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2' compile 'com.android.support.constraint:constraint-layout:1.0.2'
// Firebase + crashlytics // Firebase + crashlytics
compile 'com.google.firebase:firebase-core:11.0.2' compile 'com.google.firebase:firebase-core:11.2.0'
compile 'com.google.firebase:firebase-config:11.0.2' compile 'com.google.firebase:firebase-config:11.2.0'
compile 'com.google.firebase:firebase-invites:11.0.2' compile 'com.google.firebase:firebase-invites:11.2.0'
compile('com.crashlytics.sdk.android:crashlytics:2.6.8@aar') { compile('com.crashlytics.sdk.android:crashlytics:2.6.8@aar') {
transitive = true transitive = true
} }
//multidex //multidex
compile 'com.android.support:multidex:1.0.1' compile 'com.android.support:multidex:1.0.2'
// Intro // Intro
compile 'agency.tango.android:material-intro-screen:0.0.5' compile 'agency.tango.android:material-intro-screen:0.0.5'
@ -128,10 +143,10 @@ dependencies {
compile 'com.github.stkent:amplify:1.5.0' compile 'com.github.stkent:amplify:1.5.0'
// For the article reader // For the article reader
compile 'com.klinkerapps:drag-dismiss-activity:1.4.2' compile 'com.klinkerapps:drag-dismiss-activity:1.4.3'
// Drawer // Drawer
compile('com.mikepenz:materialdrawer:5.9.4@aar') { compile('com.mikepenz:materialdrawer:5.9.5@aar') {
transitive = true transitive = true
} }
compile 'com.anupcowkur:reservoir:3.1.0' compile 'com.anupcowkur:reservoir:3.1.0'
@ -170,4 +185,4 @@ def initAppLoginPropertiesIfNeeded() {
entry(key: "appLoginPassword", value: System.getProperty("appLoginPassword")) entry(key: "appLoginPassword", value: System.getProperty("appLoginPassword"))
} }
} }
} }

View File

@ -86,7 +86,7 @@ class HomeActivityEspressoTest {
intended(hasComponent(LoginActivity::class.java.name), times(1)) intended(hasComponent(LoginActivity::class.java.name), times(1))
onView(isRoot()).perform(pressBack()) //onView(isRoot()).perform(pressBack())
} }

View File

@ -46,7 +46,7 @@ class IntroActivityEspressoTest {
Intents.init() Intents.init()
} }
@Test /*@Test
fun nextEachTimes() { fun nextEachTimes() {
rule.launchActivity(Intent()) rule.launchActivity(Intent())
@ -61,7 +61,7 @@ class IntroActivityEspressoTest {
intended(hasComponent(IntroActivity::class.java.name), times(1)) intended(hasComponent(IntroActivity::class.java.name), times(1))
intended(hasComponent(LoginActivity::class.java.name), times(1)) intended(hasComponent(LoginActivity::class.java.name), times(1))
} }*/
@Test @Test
fun nextBackRandomTimes() { fun nextBackRandomTimes() {

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -2,6 +2,7 @@ package apps.amine.bou.readerforselfoss
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.preference.PreferenceManager
import android.support.constraint.ConstraintLayout import android.support.constraint.ConstraintLayout
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar import android.support.v7.widget.Toolbar
@ -43,7 +44,8 @@ class AddSourceActivity : AppCompatActivity() {
var api: SelfossApi? = null var api: SelfossApi? = null
try { try {
api = SelfossApi(this, this@AddSourceActivity) val prefs = PreferenceManager.getDefaultSharedPreferences(this)
api = SelfossApi(this, this@AddSourceActivity, prefs.getBoolean("isSelfSignedCert", false))
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
mustLoginToAddSource() mustLoginToAddSource()
} }

View File

@ -80,16 +80,19 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
private var items: ArrayList<Item> = ArrayList() private var items: ArrayList<Item> = ArrayList()
private var clickBehavior = false private var clickBehavior = false
private var debugReadingItems = false
private var internalBrowser = false private var internalBrowser = false
private var articleViewer = false private var articleViewer = false
private var shouldBeCardView = false private var shouldBeCardView = false
private var displayUnreadCount = false private var displayUnreadCount = false
private var displayAllCount = false private var displayAllCount = false
private var fullHeightCards: Boolean = false private var fullHeightCards: Boolean = false
private var itemsNumber: Int = 200
private var elementsShown: Int = 0 private var elementsShown: Int = 0
private var maybeTagFilter: Tag? = null private var maybeTagFilter: Tag? = null
private var maybeSourceFilter: Sources? = null private var maybeSourceFilter: Sources? = null
private var maybeSearchFilter: String? = null private var maybeSearchFilter: String? = null
private var userIdentifier: String = ""
private lateinit var emptyText: TextView private lateinit var emptyText: TextView
private lateinit var recyclerView: RecyclerView private lateinit var recyclerView: RecyclerView
@ -139,7 +142,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
customTabActivityHelper = CustomTabActivityHelper() customTabActivityHelper = CustomTabActivityHelper()
api = SelfossApi(this, this@HomeActivity) val dirtyPref = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
api = SelfossApi(this, this@HomeActivity, dirtyPref.getBoolean("isSelfSignedCert", false))
items = ArrayList() items = ArrayList()
appColors = AppColors(this@HomeActivity) appColors = AppColors(this@HomeActivity)
@ -275,6 +279,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
private fun handleSharedPrefs() { private fun handleSharedPrefs() {
debugReadingItems = sharedPref.getBoolean("read_debug", false)
clickBehavior = sharedPref.getBoolean("tab_on_tap", false) clickBehavior = sharedPref.getBoolean("tab_on_tap", false)
internalBrowser = sharedPref.getBoolean("prefer_internal_browser", true) internalBrowser = sharedPref.getBoolean("prefer_internal_browser", true)
articleViewer = sharedPref.getBoolean("prefer_article_viewer", true) articleViewer = sharedPref.getBoolean("prefer_article_viewer", true)
@ -282,6 +287,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
displayUnreadCount = sharedPref.getBoolean("display_unread_count", true) displayUnreadCount = sharedPref.getBoolean("display_unread_count", true)
displayAllCount = sharedPref.getBoolean("display_other_count", false) displayAllCount = sharedPref.getBoolean("display_other_count", false)
fullHeightCards = sharedPref.getBoolean("full_height_cards", false) fullHeightCards = sharedPref.getBoolean("full_height_cards", false)
itemsNumber = sharedPref.getString("prefer_api_items_number", "200").toInt()
userIdentifier = sharedPref.getString("unique_id", "")
} }
private fun handleDrawer() { private fun handleDrawer() {
@ -611,7 +618,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
private fun getUnRead() { private fun getUnRead() {
elementsShown = UNREAD_SHOWN elementsShown = UNREAD_SHOWN
doCallTo(R.string.cant_get_new_elements){t, id, f -> api.newItems(t, id, f)} doCallTo(R.string.cant_get_new_elements){t, id, f -> api.newItems(t, id, f, itemsNumber)}
} }
private fun getRead() { private fun getRead() {
@ -638,7 +645,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
internalBrowser, internalBrowser,
articleViewer, articleViewer,
fullHeightCards, fullHeightCards,
appColors) appColors,
debugReadingItems,
userIdentifier)
} else { } else {
mAdapter = mAdapter =
ItemListAdapter( ItemListAdapter(
@ -648,7 +657,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
customTabActivityHelper, customTabActivityHelper,
clickBehavior, clickBehavior,
internalBrowser, internalBrowser,
articleViewer) articleViewer,
debugReadingItems,
userIdentifier)
} }
recyclerView.adapter = mAdapter recyclerView.adapter = mAdapter
mAdapter.notifyDataSetChanged() mAdapter.notifyDataSetChanged()

View File

@ -9,7 +9,7 @@ import android.view.View
import agency.tango.materialintroscreen.MaterialIntroActivity import agency.tango.materialintroscreen.MaterialIntroActivity
import agency.tango.materialintroscreen.MessageButtonBehaviour import agency.tango.materialintroscreen.MessageButtonBehaviour
import agency.tango.materialintroscreen.SlideFragmentBuilder import agency.tango.materialintroscreen.SlideFragmentBuilder
import android.support.v7.app.AppCompatDelegate
class IntroActivity : MaterialIntroActivity() { class IntroActivity : MaterialIntroActivity() {
@ -17,10 +17,12 @@ class IntroActivity : MaterialIntroActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
addSlide(SlideFragmentBuilder() addSlide(SlideFragmentBuilder()
.backgroundColor(R.color.colorPrimary) .backgroundColor(R.color.colorPrimary)
.buttonsColor(R.color.colorAccent) .buttonsColor(R.color.colorAccent)
.image(R.mipmap.ic_launcher) .image(R.drawable.web_hi_res_512)
.title(getString(R.string.intro_hello_title)) .title(getString(R.string.intro_hello_title))
.description(getString(R.string.intro_hello_message)) .description(getString(R.string.intro_hello_message))
.build()) .build())
@ -28,7 +30,7 @@ class IntroActivity : MaterialIntroActivity() {
addSlide(SlideFragmentBuilder() addSlide(SlideFragmentBuilder()
.backgroundColor(R.color.colorAccent) .backgroundColor(R.color.colorAccent)
.buttonsColor(R.color.colorPrimary) .buttonsColor(R.color.colorPrimary)
.image(R.drawable.ic_info_outline_white_48dp) .image(R.drawable.ic_info_outline_white_48px)
.title(getString(R.string.intro_needs_selfoss_title)) .title(getString(R.string.intro_needs_selfoss_title))
.description(getString(R.string.intro_needs_selfoss_message)) .description(getString(R.string.intro_needs_selfoss_message))
.build(), .build(),
@ -40,7 +42,7 @@ class IntroActivity : MaterialIntroActivity() {
addSlide(SlideFragmentBuilder() addSlide(SlideFragmentBuilder()
.backgroundColor(R.color.colorPrimaryDark) .backgroundColor(R.color.colorPrimaryDark)
.buttonsColor(R.color.colorAccentDark) .buttonsColor(R.color.colorAccentDark)
.image(R.drawable.ic_thumb_up_white_48dp) .image(R.drawable.ic_thumb_up_white_48px)
.title(getString(R.string.intro_all_set_title)) .title(getString(R.string.intro_all_set_title))
.description(getString(R.string.intro_all_set_message)) .description(getString(R.string.intro_all_set_message))
.build()) .build())

View File

@ -15,10 +15,7 @@ import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.Button import android.widget.*
import android.widget.EditText
import android.widget.Switch
import android.widget.TextView
import com.google.firebase.analytics.FirebaseAnalytics import com.google.firebase.analytics.FirebaseAnalytics
import com.mikepenz.aboutlibraries.Libs import com.mikepenz.aboutlibraries.Libs
@ -32,16 +29,20 @@ import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.utils.Config import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.checkAndDisplayStoreApk import apps.amine.bou.readerforselfoss.utils.checkAndDisplayStoreApk
import apps.amine.bou.readerforselfoss.utils.isBaseUrlValid import apps.amine.bou.readerforselfoss.utils.isBaseUrlValid
import com.crashlytics.android.Crashlytics
import com.ftinc.scoop.Scoop import com.ftinc.scoop.Scoop
import io.fabric.sdk.android.Fabric
class LoginActivity : AppCompatActivity() { class LoginActivity : AppCompatActivity() {
private var inValidCount: Int = 0 private var inValidCount: Int = 0
private var isWithSelfSignedCert = false
private var isWithLogin = false private var isWithLogin = false
private var isWithHTTPLogin = false private var isWithHTTPLogin = false
private lateinit var settings: SharedPreferences private lateinit var settings: SharedPreferences
private lateinit var editor: SharedPreferences.Editor
private lateinit var mFirebaseAnalytics: FirebaseAnalytics private lateinit var mFirebaseAnalytics: FirebaseAnalytics
private lateinit var mUrlView: EditText private lateinit var mUrlView: EditText
private lateinit var mLoginView: TextView private lateinit var mLoginView: TextView
@ -50,6 +51,8 @@ class LoginActivity : AppCompatActivity() {
private lateinit var mPasswordView: EditText private lateinit var mPasswordView: EditText
private lateinit var mHTTPPasswordView: EditText private lateinit var mHTTPPasswordView: EditText
private lateinit var mLoginFormView: View private lateinit var mLoginFormView: View
private lateinit var userIdentifier: String
private var logErrors: Boolean = false
@ -74,6 +77,11 @@ class LoginActivity : AppCompatActivity() {
settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE) settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
userIdentifier = settings.getString("unique_id", "")
logErrors = settings.getBoolean("loging_debug", false)
editor = settings.edit()
if (settings.getString("url", "").isNotEmpty()) { if (settings.getString("url", "").isNotEmpty()) {
goToMain() goToMain()
} else { } else {
@ -96,6 +104,15 @@ class LoginActivity : AppCompatActivity() {
val mPasswordLayout: TextInputLayout = findViewById(R.id.passwordLayout) val mPasswordLayout: TextInputLayout = findViewById(R.id.passwordLayout)
val mHTTPPasswordLayout: TextInputLayout = findViewById(R.id.httpPasswordInput) val mHTTPPasswordLayout: TextInputLayout = findViewById(R.id.httpPasswordInput)
val mEmailSignInButton: Button = findViewById(R.id.email_sign_in_button) val mEmailSignInButton: Button = findViewById(R.id.email_sign_in_button)
val selfHostedSwitch: Switch = findViewById(R.id.withSelfhostedCert)
val warningTextview: TextView = findViewById(R.id.warningText)
selfHostedSwitch.setOnCheckedChangeListener {_, b ->
isWithSelfSignedCert = !isWithSelfSignedCert
val visi: Int = if (b) View.VISIBLE else View.GONE
warningTextview.visibility = visi
}
mPasswordView.setOnEditorActionListener(TextView.OnEditorActionListener { _, id, _ -> mPasswordView.setOnEditorActionListener(TextView.OnEditorActionListener { _, id, _ ->
if (id == R.id.login || id == EditorInfo.IME_NULL) { if (id == R.id.login || id == EditorInfo.IME_NULL) {
@ -186,17 +203,17 @@ class LoginActivity : AppCompatActivity() {
} else { } else {
showProgress(true) showProgress(true)
val editor = settings.edit()
editor.putString("url", url) editor.putString("url", url)
editor.putString("login", login) editor.putString("login", login)
editor.putString("httpUserName", httpLogin) editor.putString("httpUserName", httpLogin)
editor.putString("password", password) editor.putString("password", password)
editor.putString("httpPassword", httpPassword) editor.putString("httpPassword", httpPassword)
editor.putBoolean("isSelfSignedCert", isWithSelfSignedCert)
editor.apply() editor.apply()
val api = SelfossApi(this, this@LoginActivity) val api = SelfossApi(this, this@LoginActivity, isWithSelfSignedCert)
api.login().enqueue(object : Callback<SuccessResponse> { api.login().enqueue(object : Callback<SuccessResponse> {
private fun preferenceError() { private fun preferenceError(t: Throwable) {
editor.remove("url") editor.remove("url")
editor.remove("login") editor.remove("login")
editor.remove("httpUserName") editor.remove("httpUserName")
@ -208,6 +225,12 @@ class LoginActivity : AppCompatActivity() {
mPasswordView.error = getString(R.string.wrong_infos) mPasswordView.error = getString(R.string.wrong_infos)
mHTTPLoginView.error = getString(R.string.wrong_infos) mHTTPLoginView.error = getString(R.string.wrong_infos)
mHTTPPasswordView.error = getString(R.string.wrong_infos) mHTTPPasswordView.error = getString(R.string.wrong_infos)
if (logErrors) {
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(100, "LOGIN_DEBUG_ERRROR", t.message)
Crashlytics.logException(t)
Toast.makeText(this@LoginActivity, t.message, Toast.LENGTH_LONG).show()
}
showProgress(false) showProgress(false)
} }
@ -216,12 +239,12 @@ class LoginActivity : AppCompatActivity() {
mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.LOGIN, Bundle()) mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.LOGIN, Bundle())
goToMain() goToMain()
} else { } else {
preferenceError() preferenceError(Exception("No response body..."))
} }
} }
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
preferenceError() preferenceError(t)
} }
}) })
} }
@ -260,6 +283,7 @@ class LoginActivity : AppCompatActivity() {
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.login_menu, menu) menuInflater.inflate(R.menu.login_menu, menu)
menu.findItem(R.id.loging_debug).isChecked = logErrors
return true return true
} }
@ -273,6 +297,14 @@ class LoginActivity : AppCompatActivity() {
.start(this) .start(this)
return true return true
} }
R.id.loging_debug -> {
val newState = !item.isChecked
item.isChecked = newState
logErrors = newState
editor.putBoolean("loging_debug", newState)
editor.apply()
return true
}
else -> return super.onOptionsItemSelected(item) else -> return super.onOptionsItemSelected(item)
} }
} }

View File

@ -6,6 +6,7 @@ import android.net.Uri
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.support.multidex.MultiDexApplication import android.support.multidex.MultiDexApplication
import android.widget.ImageView import android.widget.ImageView
import apps.amine.bou.readerforselfoss.utils.Config
import com.anupcowkur.reservoir.Reservoir import com.anupcowkur.reservoir.Reservoir
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.crashlytics.android.Crashlytics import com.crashlytics.android.Crashlytics
@ -15,22 +16,34 @@ import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
import com.mikepenz.materialdrawer.util.DrawerImageLoader import com.mikepenz.materialdrawer.util.DrawerImageLoader
import io.fabric.sdk.android.Fabric import io.fabric.sdk.android.Fabric
import java.io.IOException import java.io.IOException
import java.util.UUID.randomUUID
class MyApp : MultiDexApplication() { class MyApp : MultiDexApplication() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
if (!BuildConfig.DEBUG) Fabric.with(this, Crashlytics())
Fabric.with(this, Crashlytics())
initAmplify() initAmplify()
initCache() initCache()
val prefs = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
if (prefs.getString("unique_id", "").isEmpty()) {
val editor = prefs.edit()
editor.putString("unique_id", randomUUID().toString())
editor.apply()
}
initDrawerImageLoader() initDrawerImageLoader()
initTheme() initTheme()
tryToHandleBug()
} }
private fun initAmplify() { private fun initAmplify() {
@ -82,4 +95,16 @@ class MyApp : MultiDexApplication() {
.setSharedPreferences(PreferenceManager.getDefaultSharedPreferences(this)) .setSharedPreferences(PreferenceManager.getDefaultSharedPreferences(this))
.initialize() .initialize()
} }
private fun tryToHandleBug() {
val oldHandler = Thread.getDefaultUncaughtExceptionHandler()
Thread.setDefaultUncaughtExceptionHandler { thread, e ->
if (e is java.lang.NoClassDefFoundError && e.stackTrace.asList().any { it.toString().contains("android.view.ViewDebug") })
Unit
else
oldHandler.uncaughtException(thread, e)
}
}
} }

View File

@ -2,6 +2,7 @@ package apps.amine.bou.readerforselfoss
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.preference.PreferenceManager
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
@ -36,7 +37,10 @@ class SourcesActivity : AppCompatActivity() {
val mFab: FloatingActionButton = findViewById(R.id.fab) val mFab: FloatingActionButton = findViewById(R.id.fab)
val mRecyclerView: RecyclerView = findViewById(R.id.activity_sources) val mRecyclerView: RecyclerView = findViewById(R.id.activity_sources)
val mLayoutManager = LinearLayoutManager(this) val mLayoutManager = LinearLayoutManager(this)
val api = SelfossApi(this, this@SourcesActivity)
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
val api = SelfossApi(this, this@SourcesActivity, prefs.getBoolean("isSelfSignedCert", false))
var items: ArrayList<Sources> = ArrayList() var items: ArrayList<Sources> = ArrayList()
mFab.attachToRecyclerView(mRecyclerView) mFab.attachToRecyclerView(mRecyclerView)

View File

@ -2,15 +2,12 @@ package apps.amine.bou.readerforselfoss.adapters
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.graphics.Bitmap
import android.graphics.Color import android.graphics.Color
import android.support.constraint.ConstraintLayout import android.support.constraint.ConstraintLayout
import android.support.design.widget.Snackbar import android.support.design.widget.Snackbar
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory
import android.support.v7.widget.CardView import android.support.v7.widget.CardView
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.text.Html import android.text.Html
import android.text.format.DateUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageButton import android.widget.ImageButton
@ -22,15 +19,11 @@ import android.widget.Toast
import com.amulyakhare.textdrawable.TextDrawable import com.amulyakhare.textdrawable.TextDrawable
import com.amulyakhare.textdrawable.util.ColorGenerator import com.amulyakhare.textdrawable.util.ColorGenerator
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.BitmapImageViewTarget
import com.like.LikeButton import com.like.LikeButton
import com.like.OnLikeListener import com.like.OnLikeListener
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.*
import apps.amine.bou.readerforselfoss.R import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.api.selfoss.Item import apps.amine.bou.readerforselfoss.api.selfoss.Item
@ -39,6 +32,8 @@ import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.themes.AppColors import apps.amine.bou.readerforselfoss.themes.AppColors
import apps.amine.bou.readerforselfoss.utils.* import apps.amine.bou.readerforselfoss.utils.*
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
import com.crashlytics.android.Crashlytics
import kotlin.collections.ArrayList
class ItemCardAdapter(private val app: Activity, class ItemCardAdapter(private val app: Activity,
private val items: ArrayList<Item>, private val items: ArrayList<Item>,
@ -47,7 +42,9 @@ class ItemCardAdapter(private val app: Activity,
private val internalBrowser: Boolean, private val internalBrowser: Boolean,
private val articleViewer: Boolean, private val articleViewer: Boolean,
private val fullHeightCards: Boolean, private val fullHeightCards: Boolean,
private val appColors: AppColors) : RecyclerView.Adapter<ItemCardAdapter.ViewHolder>() { private val appColors: AppColors,
val debugReadingItems: Boolean,
val userIdentifier: String) : RecyclerView.Adapter<ItemCardAdapter.ViewHolder>() {
private val c: Context = app.baseContext private val c: Context = app.baseContext
private val generator: ColorGenerator = ColorGenerator.MATERIAL private val generator: ColorGenerator = ColorGenerator.MATERIAL
@ -130,11 +127,31 @@ class ItemCardAdapter(private val app: Activity,
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> { api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) { override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {
if (debugReadingItems) {
val message =
"message: ${response.message()} " +
"response isSuccess: ${response.isSuccessful} " +
"response code: ${response.code()} " +
"response message: ${response.message()} " +
"response errorBody: ${response.errorBody()?.string()} " +
"body success: ${response.body()?.success} " +
"body isSuccess: ${response.body()?.isSuccess}"
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(100, "READ_DEBUG_SUCCESS", message)
Crashlytics.logException(Exception("Was success, but did it work ?"))
Toast.makeText(c, message, Toast.LENGTH_LONG).show()
}
doUnmark(i, position) doUnmark(i, position)
} }
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
if (debugReadingItems) {
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(100, "READ_DEBUG_ERROR", t.message)
Crashlytics.logException(t)
Toast.makeText(c, t.message, Toast.LENGTH_LONG).show()
}
Toast.makeText(app, app.getString(R.string.cant_mark_read), Toast.LENGTH_SHORT).show() Toast.makeText(app, app.getString(R.string.cant_mark_read), Toast.LENGTH_SHORT).show()
items.add(i) items.add(i)
notifyItemInserted(position) notifyItemInserted(position)

View File

@ -3,16 +3,11 @@ package apps.amine.bou.readerforselfoss.adapters
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Color import android.graphics.Color
import android.net.Uri
import android.support.constraint.ConstraintLayout import android.support.constraint.ConstraintLayout
import android.support.design.widget.Snackbar import android.support.design.widget.Snackbar
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory
import android.support.v7.widget.RecyclerView import android.support.v7.widget.RecyclerView
import android.text.Html import android.text.Html
import android.text.format.DateUtils
import android.util.TypedValue import android.util.TypedValue
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -21,24 +16,21 @@ import android.widget.*
import com.amulyakhare.textdrawable.TextDrawable import com.amulyakhare.textdrawable.TextDrawable
import com.amulyakhare.textdrawable.util.ColorGenerator import com.amulyakhare.textdrawable.util.ColorGenerator
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.BitmapImageViewTarget
import com.like.LikeButton import com.like.LikeButton
import com.like.OnLikeListener import com.like.OnLikeListener
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.* import java.util.*
import apps.amine.bou.readerforselfoss.R import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.api.selfoss.Item import apps.amine.bou.readerforselfoss.api.selfoss.Item
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.themes.AppColors
import apps.amine.bou.readerforselfoss.utils.* import apps.amine.bou.readerforselfoss.utils.*
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
import com.crashlytics.android.Crashlytics
import kotlin.collections.ArrayList
class ItemListAdapter(private val app: Activity, class ItemListAdapter(private val app: Activity,
@ -47,7 +39,9 @@ class ItemListAdapter(private val app: Activity,
private val helper: CustomTabActivityHelper, private val helper: CustomTabActivityHelper,
private val clickBehavior: Boolean, private val clickBehavior: Boolean,
private val internalBrowser: Boolean, private val internalBrowser: Boolean,
private val articleViewer: Boolean) : RecyclerView.Adapter<ItemListAdapter.ViewHolder>() { private val articleViewer: Boolean,
val debugReadingItems: Boolean,
val userIdentifier: String) : RecyclerView.Adapter<ItemListAdapter.ViewHolder>() {
private val generator: ColorGenerator = ColorGenerator.MATERIAL private val generator: ColorGenerator = ColorGenerator.MATERIAL
private val c: Context = app.baseContext private val c: Context = app.baseContext
private val bars: ArrayList<Boolean> = ArrayList(Collections.nCopies(items.size + 1, false)) private val bars: ArrayList<Boolean> = ArrayList(Collections.nCopies(items.size + 1, false))
@ -142,11 +136,31 @@ class ItemListAdapter(private val app: Activity,
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> { api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) { override fun onResponse(call: Call<SuccessResponse>, response: Response<SuccessResponse>) {
if (debugReadingItems) {
val message =
"message: ${response.message()} " +
"response isSuccess: ${response.isSuccessful} " +
"response code: ${response.code()} " +
"response message: ${response.message()} " +
"response errorBody: ${response.errorBody()?.string()} " +
"body success: ${response.body()?.success} " +
"body isSuccess: ${response.body()?.isSuccess}"
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(100, "READ_DEBUG_SUCCESS", message)
Crashlytics.logException(Exception("Was success, but did it work ?"))
Toast.makeText(c, message, Toast.LENGTH_LONG).show()
}
doUnmark(i, position) doUnmark(i, position)
} }
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
if (debugReadingItems) {
Crashlytics.setUserIdentifier(userIdentifier)
Crashlytics.log(100, "READ_DEBUG_ERROR", t.message)
Crashlytics.logException(t)
Toast.makeText(c, t.message, Toast.LENGTH_LONG).show()
}
Toast.makeText(app, app.getString(R.string.cant_mark_read), Toast.LENGTH_SHORT).show() Toast.makeText(app, app.getString(R.string.cant_mark_read), Toast.LENGTH_SHORT).show()
items.add(i) items.add(i)
notifyItemInserted(position) notifyItemInserted(position)

View File

@ -23,26 +23,66 @@ import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
import apps.amine.bou.readerforselfoss.utils.Config import apps.amine.bou.readerforselfoss.utils.Config
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import javax.net.ssl.*
// codebeat:disable[ARITY,TOO_MANY_FUNCTIONS] // codebeat:disable[ARITY,TOO_MANY_FUNCTIONS]
class SelfossApi(c: Context, callingActivity: Activity) { class SelfossApi(c: Context, callingActivity: Activity, isWithSelfSignedCert: Boolean) {
private lateinit var service: SelfossService private lateinit var service: SelfossService
private val config: Config = Config(c) private val config: Config = Config(c)
private val userName: String private val userName: String
private val password: String private val password: String
fun OkHttpClient.Builder.maybeWithSelfSigned(isWithSelfSignedCert: Boolean): OkHttpClient.Builder =
if (isWithSelfSignedCert) {
try {
// Create a trust manager that does not validate certificate chains
val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
override fun getAcceptedIssuers(): Array<X509Certificate> =
arrayOf()
@Throws(CertificateException::class)
override fun checkClientTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) {
}
@Throws(CertificateException::class)
override fun checkServerTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) {
}
})
// Install the all-trusting trust manager
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, java.security.SecureRandom())
val sslSocketFactory = sslContext.socketFactory
OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
.hostnameVerifier { _, _ -> true }
} catch (e: Exception) {
throw RuntimeException(e)
}
} else {
this
}
fun Credentials.createAuthenticator(): DispatchingAuthenticator = fun Credentials.createAuthenticator(): DispatchingAuthenticator =
DispatchingAuthenticator.Builder() DispatchingAuthenticator.Builder()
.with("digest", DigestAuthenticator(this)) .with("digest", DigestAuthenticator(this))
.with("basic", BasicAuthenticator(this)) .with("basic", BasicAuthenticator(this))
.build() .build()
fun DispatchingAuthenticator.getHttpClien(): OkHttpClient { fun DispatchingAuthenticator.getHttpClien(isWithSelfSignedCert: Boolean): OkHttpClient {
val authCache = ConcurrentHashMap<String, CachingAuthenticator>() val authCache = ConcurrentHashMap<String, CachingAuthenticator>()
return OkHttpClient return OkHttpClient
.Builder() .Builder()
.maybeWithSelfSigned(isWithSelfSignedCert)
.authenticator(CachingAuthenticatorDecorator(this, authCache)) .authenticator(CachingAuthenticatorDecorator(this, authCache))
.addInterceptor(AuthenticationCacheInterceptor(authCache)) .addInterceptor(AuthenticationCacheInterceptor(authCache))
.build() .build()
@ -71,7 +111,7 @@ class SelfossApi(c: Context, callingActivity: Activity) {
Retrofit Retrofit
.Builder() .Builder()
.baseUrl(config.baseUrl) .baseUrl(config.baseUrl)
.client(authenticator.getHttpClien()) .client(authenticator.getHttpClien(isWithSelfSignedCert))
.addConverterFactory(GsonConverterFactory.create(gson)) .addConverterFactory(GsonConverterFactory.create(gson))
.build() .build()
service = retrofit.create(SelfossService::class.java) service = retrofit.create(SelfossService::class.java)
@ -84,16 +124,16 @@ class SelfossApi(c: Context, callingActivity: Activity) {
service.loginToSelfoss(config.userLogin, config.userPassword) service.loginToSelfoss(config.userLogin, config.userPassword)
fun readItems(tag: String?, sourceId: Long?, search: String?): Call<List<Item>> = fun readItems(tag: String?, sourceId: Long?, search: String?): Call<List<Item>> =
getItems("read", tag, sourceId, search) getItems("read", tag, sourceId, search, 200)
fun newItems(tag: String?, sourceId: Long?, search: String?): Call<List<Item>> = fun newItems(tag: String?, sourceId: Long?, search: String?, itemsNumber: Int): Call<List<Item>> =
getItems("unread", tag, sourceId, search) getItems("unread", tag, sourceId, search, itemsNumber)
fun starredItems(tag: String?, sourceId: Long?, search: String?): Call<List<Item>> = fun starredItems(tag: String?, sourceId: Long?, search: String?): Call<List<Item>> =
getItems("starred", tag, sourceId, search) getItems("starred", tag, sourceId, search, 200)
private fun getItems(type: String, tag: String?, sourceId: Long?, search: String?): Call<List<Item>> = private fun getItems(type: String, tag: String?, sourceId: Long?, search: String?, items: Int): Call<List<Item>> =
service.getItems(type, tag, sourceId, search, userName, password) service.getItems(type, tag, sourceId, search, userName, password, items)
fun markItem(itemId: String): Call<SuccessResponse> = fun markItem(itemId: String): Call<SuccessResponse> =
service.markAsRead(itemId, userName, password) service.markAsRead(itemId, userName, password)

View File

@ -22,7 +22,8 @@ internal interface SelfossService {
@Query("source") source: Long?, @Query("source") source: Long?,
@Query("search") search: String?, @Query("search") search: String?,
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String): Call<List<Item>> @Query("password") password: String,
@Query("items") items: Int): Call<List<Item>>
@POST("mark/{id}") @POST("mark/{id}")
fun markAsRead(@Path("id") id: String, fun markAsRead(@Path("id") id: String,

View File

@ -2,24 +2,33 @@ package apps.amine.bou.readerforselfoss.settings;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity; import android.preference.PreferenceActivity;
import android.preference.SwitchPreference; import android.preference.SwitchPreference;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.text.InputFilter;
import android.text.Spanned;
import android.view.MenuItem; import android.view.MenuItem;
import android.widget.Toast;
import java.util.List; import java.util.List;
import apps.amine.bou.readerforselfoss.R; import apps.amine.bou.readerforselfoss.R;
import apps.amine.bou.readerforselfoss.utils.Config;
import com.ftinc.scoop.ui.ScoopSettingsActivity; import com.ftinc.scoop.ui.ScoopSettingsActivity;
@ -119,6 +128,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
protected boolean isValidFragment(String fragmentName) { protected boolean isValidFragment(String fragmentName) {
return PreferenceFragment.class.getName().equals(fragmentName) return PreferenceFragment.class.getName().equals(fragmentName)
|| GeneralPreferenceFragment.class.getName().equals(fragmentName) || GeneralPreferenceFragment.class.getName().equals(fragmentName)
|| DebugPreferenceFragment.class.getName().equals(fragmentName)
|| LinksPreferenceFragment.class.getName().equals(fragmentName); || LinksPreferenceFragment.class.getName().equals(fragmentName);
} }
@ -144,6 +154,61 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
return true; return true;
} }
}); });
EditTextPreference itemsNumber = (EditTextPreference) findPreference("prefer_api_items_number");
itemsNumber.getEditText().setFilters(new InputFilter[]{
new InputFilter (){
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
try {
int input = Integer.parseInt(dest.toString() + source.toString());
if (input <= 200 && input >0)
return null;
} catch (NumberFormatException nfe) { }
return "";
}
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
getActivity().finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class DebugPreferenceFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_debug);
setHasOptionsMenu(true);
SharedPreferences pref = getActivity().getSharedPreferences(Config.Companion.getSettingsName(), Context.MODE_PRIVATE);
final String id = pref.getString("unique_id", "...");
final Preference identifier = findPreference("debug_identifier");
final ClipboardManager clipboard = (ClipboardManager)
getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
identifier.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
ClipData clip = ClipData.newPlainText("Selfoss unique id", id);
clipboard.setPrimaryClip(clip);
Toast.makeText(getActivity(), R.string.unique_id_to_clipboard, Toast.LENGTH_LONG).show();
return true;
}
});
identifier.setTitle(id);
} }
@Override @Override

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 953 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 466 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -2,12 +2,12 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item <item
android:drawable="@color/white"/> android:drawable="@color/ic_launcher_background"/>
<item> <item>
<bitmap <bitmap
android:gravity="center" android:gravity="center"
android:src="@mipmap/ic_launcher"/> android:src="@mipmap/ic_launcher_foreground"/>
</item> </item>
</layer-list> </layer-list>

View File

@ -0,0 +1,4 @@
<vector android:height="24dp" android:viewportHeight="24.0"
android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FFFFFF" android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
</vector>

View File

@ -0,0 +1,4 @@
<vector android:height="24dp" android:viewportHeight="24.0"
android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FFFFFF" android:pathData="M1,21h4L5,9L1,9v12zM23,10c0,-1.1 -0.9,-2 -2,-2h-6.31l0.95,-4.57 0.03,-0.32c0,-0.41 -0.17,-0.79 -0.44,-1.06L14.17,1 7.59,7.59C7.22,7.95 7,8.45 7,9v10c0,1.1 0.9,2 2,2h9c0.83,0 1.54,-0.5 1.84,-1.22l3.02,-7.05c0.09,-0.23 0.14,-0.47 0.14,-0.73v-1.91l-0.01,-0.01L23,10z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -138,6 +138,20 @@
android:hint="@string/prompt_http_password" /> android:hint="@string/prompt_http_password" />
</android.support.design.widget.TextInputLayout> </android.support.design.widget.TextInputLayout>
<Switch
android:id="@+id/withSelfhostedCert"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/self_hosted_cert_switch" />
<TextView
android:id="@+id/warningText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/self_signed_cert_warning"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:visibility="gone" />
<Button <Button
android:id="@+id/email_sign_in_button" android:id="@+id/email_sign_in_button"
style="?android:textAppearanceSmall" style="?android:textAppearanceSmall"

View File

@ -0,0 +1,11 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Switch
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
</RelativeLayout>

View File

@ -2,6 +2,14 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/loging_debug"
android:checkable="true"
android:checked="false"
android:icon="@drawable/ic_bug_report"
android:title="@string/login_menu_debug"
app:showAsAction="never" />
<item android:id="@+id/about" <item android:id="@+id/about"
android:title="@string/action_about" android:title="@string/action_about"
android:orderInCategory="102" android:orderInCategory="102"

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 803 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -131,4 +131,18 @@
<string name="blue_amber_dark_theme">Bleu/Ambre/Foncé</string> <string name="blue_amber_dark_theme">Bleu/Ambre/Foncé</string>
<string name="indigo_pink_dark_theme">Indigo/Rose/Foncé</string> <string name="indigo_pink_dark_theme">Indigo/Rose/Foncé</string>
<string name="red_teal_dark_theme">Rouge/Sarcelle/Foncé</string> <string name="red_teal_dark_theme">Rouge/Sarcelle/Foncé</string>
<string name="pref_header_debug">Debug</string>
<string name="login_debug_title">Activez pour loguer toutes les erreurs de conexion</string>
<string name="login_debug_on">Toutes les erreurs de connexion vont être loguées</string>
<string name="login_debug_off">Aucune erreur de connexion ne sera loguée</string>
<string name="login_menu_debug">Debug</string>
<string name="self_hosted_cert_switch">Certificat auto-signé ?</string>
<string name="self_signed_cert_warning">Pour des raisons de sécurités, les certificats auto-signés sont désactivés par défaut. En les activant, je ne serais pas responsable de quelconques problèmes de sécurité rencontrés.</string>
<string name="pref_selfoss_category">Api Selfoss</string>
<string name="pref_api_items_number_title">Nombre d\'articles chargés</string>
<string name="read_debug_title">Des articles lus marqués comme non lus ?</string>
<string name="read_debug_on">Les appels API vont être logués lorsequ\'un article est marqué comme lu</string>
<string name="read_debug_off">Aucun log quand un article est marqué comme lu</string>
<string name="summary_debug_identifier">Identifiant de debug</string>
<string name="unique_id_to_clipboard">Texte copié</string>
</resources> </resources>

View File

@ -131,4 +131,18 @@
<string name="blue_amber_dark_theme">Blue/Amber/Dark</string> <string name="blue_amber_dark_theme">Blue/Amber/Dark</string>
<string name="indigo_pink_dark_theme">Indigo/Pink/Dark</string> <string name="indigo_pink_dark_theme">Indigo/Pink/Dark</string>
<string name="red_teal_dark_theme">Red/Teal/Dark</string> <string name="red_teal_dark_theme">Red/Teal/Dark</string>
<string name="pref_header_debug">Debug</string>
<string name="login_debug_title">Activate to log login errors</string>
<string name="login_debug_on">Any error on the login page will be logged</string>
<string name="login_debug_off">No log on the login page</string>
<string name="login_menu_debug">Debug</string>
<string name="self_hosted_cert_switch">Using a self hosted certificate ?</string>
<string name="self_signed_cert_warning">Due to security reasons, self signed certificates are not supported by default. By activating this, I\'ll not be responsible of any security problem you encounter.</string>
<string name="pref_selfoss_category">Selfoss Api</string>
<string name="pref_api_items_number_title">Loaded items number</string>
<string name="read_debug_title">Read articles appearing as unread ?</string>
<string name="read_debug_on">Api calls will be logged when marking an article as read</string>
<string name="read_debug_off">No log when marking an item as read</string>
<string name="summary_debug_identifier">Debug identifier</string>
<string name="unique_id_to_clipboard">Identifier copied to your clipboard</string>
</resources> </resources>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFFFFF</color>
</resources>

View File

@ -133,4 +133,18 @@
<string name="blue_amber_dark_theme">Blue/Amber/Dark</string> <string name="blue_amber_dark_theme">Blue/Amber/Dark</string>
<string name="indigo_pink_dark_theme">Indigo/Pink/Dark</string> <string name="indigo_pink_dark_theme">Indigo/Pink/Dark</string>
<string name="red_teal_dark_theme">Red/Teal/Dark</string> <string name="red_teal_dark_theme">Red/Teal/Dark</string>
<string name="pref_header_debug">Debug</string>
<string name="login_debug_title">Activate to log login errors</string>
<string name="login_debug_on">Any error on the login page will be logged</string>
<string name="login_debug_off">No log on the login page</string>
<string name="login_menu_debug">Debug</string>
<string name="self_hosted_cert_switch">Using a self hosted certificate ?</string>
<string name="self_signed_cert_warning">Due to security reasons, self signed certificates are not supported by default. By activating this, I\'ll not be responsible of any security problem you encounter.</string>
<string name="pref_selfoss_category">Selfoss Api</string>
<string name="pref_api_items_number_title">Loaded items number</string>
<string name="read_debug_title">Read articles appearing as unread ?</string>
<string name="read_debug_off">No log when marking an item as read</string>
<string name="read_debug_on">Api calls will be logged when marking an article as read</string>
<string name="summary_debug_identifier">Debug identifier</string>
<string name="unique_id_to_clipboard">Identifier copied to your clipboard</string>
</resources> </resources>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<SwitchPreference
android:defaultValue="false"
android:key="loging_debug"
android:summaryOff="@string/login_debug_off"
android:summaryOn="@string/login_debug_on"
android:title="@string/login_debug_title" />
<SwitchPreference
android:defaultValue="false"
android:key="read_debug"
android:summaryOff="@string/read_debug_off"
android:summaryOn="@string/read_debug_on"
android:title="@string/read_debug_title" />
<Preference
android:enabled="true"
android:key="debug_identifier"
android:summary="@string/summary_debug_identifier" />
</PreferenceScreen>

View File

@ -1,4 +1,5 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceScreen xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<!--<SwitchPreference <!--<SwitchPreference
android:defaultValue="false" android:defaultValue="false"
@ -6,6 +7,17 @@
android:summary="@string/pref_switch_browser" android:summary="@string/pref_switch_browser"
android:title="@string/pref_switch_browser_title"/>--> android:title="@string/pref_switch_browser_title"/>-->
<PreferenceCategory
android:title="@string/pref_selfoss_category">
</PreferenceCategory>
<EditTextPreference
android:defaultValue="200"
android:inputType="number"
android:key="prefer_api_items_number"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="@string/pref_api_items_number_title" />
<PreferenceCategory <PreferenceCategory
android:title="@string/pref_general_category_links"> android:title="@string/pref_general_category_links">

View File

@ -5,6 +5,11 @@
android:icon="@drawable/ic_settings_black_24dp" android:icon="@drawable/ic_settings_black_24dp"
android:title="@string/pref_header_general"/> android:title="@string/pref_header_general"/>
<header
android:fragment="apps.amine.bou.readerforselfoss.settings.SettingsActivity$DebugPreferenceFragment"
android:icon="@drawable/ic_bug_report"
android:title="@string/pref_header_debug"/>
<header <header
android:id="@+id/theme_change" android:id="@+id/theme_change"
android:icon="@drawable/ic_color_lens_black_24dp" android:icon="@drawable/ic_color_lens_black_24dp"

View File

@ -7,7 +7,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.0.0-alpha5' classpath 'com.android.tools.build:gradle:3.0.0-beta2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong

View File

@ -1,6 +1,6 @@
#Sun Jul 02 08:13:37 CEST 2017 #Wed Aug 16 19:45:22 CEST 2017
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-milestone-1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-rc-1-all.zip