Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
FreshRSS-Android
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
30
Issues
30
List
Boards
Labels
Service Desk
Milestones
Merge Requests
2
Merge Requests
2
Requirements
Requirements
List
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Operations
Operations
Environments
Packages & Registries
Packages & Registries
Package Registry
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issue
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Christophe Henry
FreshRSS-Android
Commits
3bc4c92e
Commit
3bc4c92e
authored
Feb 18, 2019
by
Christophe Henry
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Persistence of auth tokens
parent
fbafca1b
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
179 additions
and
79 deletions
+179
-79
app/build.gradle
app/build.gradle
+3
-0
app/src/main/java/fr/chenry/android/freshrss/FreshRSSApplication.kt
...in/java/fr/chenry/android/freshrss/FreshRSSApplication.kt
+16
-5
app/src/main/java/fr/chenry/android/freshrss/activities/LoginActivity.kt
...va/fr/chenry/android/freshrss/activities/LoginActivity.kt
+18
-7
app/src/main/java/fr/chenry/android/freshrss/activities/MainActivity.kt
...ava/fr/chenry/android/freshrss/activities/MainActivity.kt
+3
-3
app/src/main/java/fr/chenry/android/freshrss/store/FreshRSSDabatabase.kt
...va/fr/chenry/android/freshrss/store/FreshRSSDabatabase.kt
+50
-0
app/src/main/java/fr/chenry/android/freshrss/store/Store.kt
app/src/main/java/fr/chenry/android/freshrss/store/Store.kt
+11
-6
app/src/main/java/fr/chenry/android/freshrss/store/api/Api.kt
...src/main/java/fr/chenry/android/freshrss/store/api/Api.kt
+35
-54
app/src/main/java/fr/chenry/android/freshrss/store/dao/Account.kt
...main/java/fr/chenry/android/freshrss/store/dao/Account.kt
+38
-0
app/src/main/java/fr/chenry/android/freshrss/utils/KotlinExtensions.kt
...java/fr/chenry/android/freshrss/utils/KotlinExtensions.kt
+4
-3
app/src/main/res/values/strings.xml
app/src/main/res/values/strings.xml
+1
-1
No files found.
app/build.gradle
View file @
3bc4c92e
...
...
@@ -89,4 +89,7 @@ dependencies {
testImplementation
"junit:junit:4.12"
androidTestImplementation
"androidx.test:runner:$test_runnner_version"
androidTestImplementation
"androidx.test.espresso:espresso-core:$espresso_version"
// Debug
implementation
"com.facebook.stetho:stetho:1.5.0"
}
app/src/main/java/fr/chenry/android/freshrss/FreshRSSApplication.kt
View file @
3bc4c92e
package
fr.chenry.android.freshrss
import
android.app.Application
import
android.
app.NotificationManager
import
android.
content.Context
import
androidx.core.app.NotificationManagerCompat
import
com.facebook.stetho.Stetho
import
fr.chenry.android.freshrss.store.Store
import
nl.komponents.kovenant.android.startKovenant
import
nl.komponents.kovenant.android.stopKovenant
import
nl.komponents.kovenant.deferred
import
java.util.*
class
FreshRSSApplication
:
Application
()
{
...
...
@@ -13,13 +15,19 @@ class FreshRSSApplication: Application() {
super
.
onCreate
()
// Stupid hack because Android is still not able to provide the current application application globally
// even though it is effectively a singleton...
FreshRSSApplication
.
application
=
this
FreshRSSApplication
.
application
Promise
.
resolve
(
this
)
startKovenant
()
Store
.
debugMode
=
try
{
val
properties
=
Properties
()
properties
.
load
(
baseContext
.
assets
.
open
(
"config.properties"
))
properties
.
getProperty
(
"debug"
,
"false"
)
!!
.
toBoolean
()
}
catch
(
_
:
Throwable
)
{
false
}
}
catch
(
_
:
Throwable
)
{
false
}
if
(
Store
.
debugMode
)
{
Stetho
.
initializeWithDefaults
(
this
)
}
}
override
fun
onTerminate
()
{
...
...
@@ -28,8 +36,11 @@ class FreshRSSApplication: Application() {
}
companion
object
{
lateinit
var
application
:
FreshRSSApplication
private
set
private
val
applicationPromise
=
deferred
<
FreshRSSApplication
,
Throwable
>()
val
application
:
FreshRSSApplication
get
()
=
applicationPromise
.
promise
.
get
()
val
context
:
Context
get
()
=
application
.
applicationContext
val
notificationManager
:
NotificationManagerCompat
get
()
=
NotificationManagerCompat
.
from
(
FreshRSSApplication
.
application
)
...
...
app/src/main/java/fr/chenry/android/freshrss/activities/LoginActivity.kt
View file @
3bc4c92e
...
...
@@ -13,10 +13,10 @@ import android.widget.TextView
import
androidx.appcompat.app.AppCompatActivity
import
androidx.core.widget.addTextChangedListener
import
fr.chenry.android.freshrss.R
import
fr.chenry.android.freshrss.store.FreshRSSDabatabase
import
fr.chenry.android.freshrss.store.Store
import
fr.chenry.android.freshrss.store.api.Endpoints
import
fr.chenry.android.freshrss.utils.cleanUrlSlashes
import
fr.chenry.android.freshrss.utils.e
import
fr.chenry.android.freshrss.utils.*
import
kotlinx.android.synthetic.main.activity_login.*
import
nl.komponents.kovenant.ui.failUi
import
nl.komponents.kovenant.ui.successUi
...
...
@@ -28,6 +28,13 @@ import java.util.*
class
LoginActivity
:
AppCompatActivity
(),
LoaderCallbacks
<
Cursor
>
{
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
if
(
FreshRSSDabatabase
.
instance
.
authTokensExistInDB
)
{
Store
.
init
(
FreshRSSDabatabase
.
instance
.
account
)
startNextActivity
()
return
}
setContentView
(
R
.
layout
.
activity_login
)
// Set up the login form.
password
.
setOnEditorActionListener
(
TextView
.
OnEditorActionListener
{
_
,
id
,
_
->
...
...
@@ -49,12 +56,17 @@ class LoginActivity: AppCompatActivity(), LoaderCallbacks<Cursor> {
}
catch
(
_
:
Throwable
)
{
}
computeHint
()
instance
.
addTextChangedListener
{
computeHint
()}
compute
InstanceURL
Hint
()
instance
.
addTextChangedListener
{
compute
InstanceURL
Hint
()}
resetErrors
()
instance
.
requestFocus
()
}
private
fun
startNextActivity
()
{
startActivity
(
Intent
(
this
,
MainActivity
::
class
.
java
))
//startActivity(Intent(this, TestActivity::class.java))
}
private
fun
attemptLogin
()
{
resetErrors
()
...
...
@@ -85,8 +97,7 @@ class LoginActivity: AppCompatActivity(), LoaderCallbacks<Cursor> {
}
else
{
showProgress
(
true
)
Store
.
login
(
instanceStr
,
loginStr
,
passwordStr
)
successUi
{
startActivity
(
Intent
(
this
,
MainActivity
::
class
.
java
))
//startActivity(Intent(this, TestActivity::class.java))
startNextActivity
()
}
failUi
{
this
.
e
(
it
)
instance
.
error
=
getString
(
R
.
string
.
error_instance
)
...
...
@@ -95,7 +106,7 @@ class LoginActivity: AppCompatActivity(), LoaderCallbacks<Cursor> {
}
}
private
fun
computeHint
()
{
private
fun
compute
InstanceURL
Hint
()
{
val
instanceStr
=
instance
.
text
.
toString
().
let
{
if
(
it
.
isBlank
())
resources
.
getString
(
R
.
string
.
instance_exemple
)
else
it
}
...
...
app/src/main/java/fr/chenry/android/freshrss/activities/MainActivity.kt
View file @
3bc4c92e
...
...
@@ -8,13 +8,13 @@ import fr.chenry.android.freshrss.R
import
fr.chenry.android.freshrss.components.waiting.WaitingFragment
import
fr.chenry.android.freshrss.store.*
import
fr.chenry.android.freshrss.utils.e
import
nl.komponents.kovenant.
*
import
nl.komponents.kovenant.
functional.bind
import
nl.komponents.kovenant.
deferred
import
nl.komponents.kovenant.
resolve
import
nl.komponents.kovenant.ui.failUi
import
nl.komponents.kovenant.ui.successUi
class
MainActivity
:
AppCompatActivity
()
{
private
val
deferred
=
deferred
<
Unit
,
Throwable
>()
private
val
deferred
=
deferred
<
Unit
,
Exception
>()
init
{
Store
.
refresh
().
successUi
{
deferred
.
resolve
()}.
failUi
(
deferred
::
reject
)
...
...
app/src/main/java/fr/chenry/android/freshrss/store/FreshRSSDabatabase.kt
0 → 100644
View file @
3bc4c92e
package
fr.chenry.android.freshrss.store
import
androidx.room.*
import
fr.chenry.android.freshrss.FreshRSSApplication
import
fr.chenry.android.freshrss.R
import
fr.chenry.android.freshrss.store.dao.*
import
fr.chenry.android.freshrss.utils.getOrDefault
import
nl.komponents.kovenant.task
import
kotlin.reflect.KProperty
@Database
(
version
=
1
,
entities
=
[
Account
::
class
])
abstract
class
FreshRSSDabatabase
:
RoomDatabase
()
{
private
val
authTokensDelegate
=
AuthTokensDelegate
()
var
account
:
Account
by
authTokensDelegate
val
authTokensExistInDB
get
()
=
authTokensDelegate
.
isInitialized
protected
abstract
fun
getAuthTokensDAO
():
AuthTokensDAO
companion
object
{
private
val
dbName
by
lazy
{
"${FreshRSSApplication.context.getString(R.string.app_name).toLowerCase()}.db"
}
val
instance
by
lazy
{
val
instance
=
Room
.
databaseBuilder
(
FreshRSSApplication
.
context
,
FreshRSSDabatabase
::
class
.
java
,
dbName
).
build
()
instance
.
authTokensDelegate
.
fetchAuthtokensFromDB
()
instance
}
}
inner
class
AuthTokensDelegate
{
private
lateinit
var
cachedAccount
:
Account
val
isInitialized
get
()
=
::
cachedAccount
.
isInitialized
operator
fun
getValue
(
this
Ref
:
Any
?,
property
:
KProperty
<
*
>):
Account
=
cachedAccount
operator
fun
setValue
(
this
Ref
:
Any
?,
property
:
KProperty
<
*
>,
value
:
Account
)
{
cachedAccount
=
value
task
{
getAuthTokensDAO
().
insert
(
account
)
}.
getOrDefault
(
Unit
)
}
fun
fetchAuthtokensFromDB
()
{
if
(!
isInitialized
)
{
val
authTokensFromDB
=
task
{
getAuthTokensDAO
().
getAuthTokens
()[
0
]}.
getOrDefault
(
null
)
if
(
authTokensFromDB
!=
null
)
cachedAccount
=
authTokensFromDB
}
}
}
}
app/src/main/java/fr/chenry/android/freshrss/store/Store.kt
View file @
3bc4c92e
...
...
@@ -5,6 +5,7 @@ import fr.chenry.android.freshrss.R
import
fr.chenry.android.freshrss.R.string
import
fr.chenry.android.freshrss.components.subscriptions.SubscriptionSection
import
fr.chenry.android.freshrss.store.api.Api
import
fr.chenry.android.freshrss.store.dao.Account
import
fr.chenry.android.freshrss.store.dao.common.StreamId
import
fr.chenry.android.freshrss.store.dao.common.Subscription
import
fr.chenry.android.freshrss.store.dao.store.Article
...
...
@@ -15,11 +16,13 @@ import fr.chenry.android.freshrss.utils.NotificationHelper.NotificationChanels.R
import
fr.chenry.android.freshrss.utils.e
import
nl.komponents.kovenant.*
import
nl.komponents.kovenant.functional.bind
import
nl.komponents.kovenant.ui.*
import
nl.komponents.kovenant.ui.failUi
import
nl.komponents.kovenant.ui.successUi
object
Store
{
lateinit
var
api
:
Api
private
set
var
debugMode
=
false
val
api
=
Api
()
val
subscriptions
=
GenericLiveData
<
StreamId
,
Subscription
>()
val
totalUnreadCount
=
MutableLiveData
<
Int
>()
val
contentItems
=
GenericLiveData
<
StreamId
,
GenericLiveData
<
ItemId
,
Article
>>()
...
...
@@ -29,8 +32,13 @@ object Store {
private
val
refreshingPromise
=
MutableLiveData
<
Promise
<
Unit
,
Exception
>>()
private
var
lastFetchTimestamp
=
0L
fun
init
(
account
:
Account
)
{
FreshRSSDabatabase
.
instance
.
account
=
account
api
=
Api
(
account
)
}
fun
login
(
instance
:
String
,
user
:
String
,
password
:
String
):
Promise
<
Unit
,
Exception
>
=
api
.
login
(
instance
,
user
,
password
)
bind
{
getToken
(
)}
Api
.
login
(
instance
,
user
,
password
)
then
{
init
(
it
)}
fun
refresh
():
Promise
<
Unit
,
Exception
>
{
if
(
refreshingPromise
.
value
!=
null
)
return
refreshingPromise
.
value
!!
...
...
@@ -96,9 +104,6 @@ object Store {
val
article
=
contentItems
[
streamId
]
?.
get
(
articleId
)
return
if
(
article
==
null
)
Promise
.
ofFail
(
ArticleNotFoundException
(
articleId
))
else
Promise
.
ofSuccess
(
article
)
}
private
fun
getToken
():
Promise
<
Unit
,
Exception
>
=
api
.
getToken
()
then
{
this
.
e
(
"::getToken: TODO"
);
Unit
}
}
class
ArticleNotFoundException
(
val
id
:
String
):
Exception
(
"Article with id $id cound not be found in store"
)
\ No newline at end of file
app/src/main/java/fr/chenry/android/freshrss/store/api/Api.kt
View file @
3bc4c92e
package
fr.chenry.android.freshrss.store.api
import
com.github.kittinunf.fuel.Fuel
import
fr.chenry.android.freshrss.store.dao.A
uthTokens
import
fr.chenry.android.freshrss.store.dao.A
ccount
import
fr.chenry.android.freshrss.store.dao.api.*
import
fr.chenry.android.freshrss.store.dao.common.Subscriptions
import
fr.chenry.android.freshrss.store.dao.common.SubscriptionsHandler
...
...
@@ -11,84 +11,42 @@ import nl.komponents.kovenant.functional.bind
import
nl.komponents.kovenant.then
import
nl.komponents.kovenant.ui.successUi
class
ApiNotInitializedException
:
Exception
(
"User is not logged in yet"
)
class
Api
{
private
lateinit
var
endpoints
:
Endpoints
private
lateinit
var
authTokens
:
AuthTokens
fun
login
(
instance
:
String
,
login
:
String
,
password
:
String
):
Promise
<
AuthTokens
,
Exception
>
{
val
params
=
listOf
(
"service"
to
"reader"
,
"Email"
to
login
,
"Passwd"
to
password
,
"source"
to
"FreshRSS"
,
"accountType"
to
"GOOGLE"
)
val
temporaryEndpoints
=
Endpoints
(
instance
)
return
Fuel
.
post
(
temporaryEndpoints
.
loginEndpoint
,
params
)
.
promiseWithSerializer
<
AuthTokens
>()
.
success
{
endpoints
=
temporaryEndpoints
authTokens
=
it
.
copy
(
login
=
login
)
}
}
fun
getToken
():
Promise
<
String
,
Exception
>
{
if
(!
isLogged
())
return
Promise
.
ofFail
(
ApiNotInitializedException
())
return
Fuel
.
post
(
endpoints
.
tokenEndpoint
)
.
header
(
"Authorization"
to
"GoogleLogin auth=${this.authTokens.SID}"
)
.
promiseString
()
}
class
Api
(
private
val
account
:
Account
)
{
private
val
endpoints
=
Endpoints
(
account
.
serverInstance
)
fun
getSubscriptions
():
Promise
<
Subscriptions
,
Exception
>
{
if
(!
isLogged
())
return
Promise
.
ofFail
(
ApiNotInitializedException
())
return
Fuel
.
getJson
(
endpoints
.
subscriptionEndpoint
)
.
authorize
(
this
.
a
uthTokens
)
.
authorize
(
this
.
a
ccount
)
.
promise
(
SubscriptionsHandler
.
serializer
())
.
then
{
it
.
subscriptions
}
}
fun
getUnreadCount
():
Promise
<
UnreadCountsHandler
,
Exception
>
{
if
(!
isLogged
())
return
Promise
.
ofFail
(
ApiNotInitializedException
())
return
Fuel
.
getJson
(
endpoints
.
unreadCountEndpoint
)
.
authorize
(
this
.
a
uthTokens
)
.
authorize
(
this
.
a
ccount
)
.
promise
(
UnreadCountsHandler
.
serializer
())
}
fun
getStreamItems
(
id
:
String
):
Promise
<
String
,
Exception
>
{
if
(!
isLogged
())
return
Promise
.
ofFail
(
ApiNotInitializedException
())
return
Fuel
.
getJson
(
endpoints
.
streamItemsEndpoint
,
listOf
(
"s"
to
id
))
.
authorize
(
this
.
a
uthTokens
)
.
authorize
(
this
.
a
ccount
)
.
promiseString
()
successUi
{
this
.
e
(
"::getStreamItems: TODO"
)}
}
fun
getStreamContents
(
id
:
String
):
Promise
<
ContentItemsHandler
,
Exception
>
{
if
(!
isLogged
())
return
Promise
.
ofFail
(
ApiNotInitializedException
())
return
Fuel
.
getJson
(
endpoints
.
streamContentsEndpoint
(
id
))
.
authorize
(
this
.
a
uthTokens
)
.
authorize
(
this
.
a
ccount
)
.
promise
(
ContentItemsHandler
.
serializer
())
}
fun
getTags
():
Promise
<
List
<
String
>,
Exception
>
{
if
(!
isLogged
())
return
Promise
.
ofFail
(
ApiNotInitializedException
())
return
Fuel
.
getJson
(
endpoints
.
tagEndpoint
)
.
authorize
(
this
.
a
uthTokens
)
.
authorize
(
this
.
a
ccount
)
.
promiseWithSerializer
(
TagsDeserializer
)
}
...
...
@@ -96,15 +54,13 @@ class Api {
olderTimestamp
:
Long
,
continuation
:
String
?
=
null
):
Promise
<
ContentItemsHandler
,
Exception
>
{
if
(!
isLogged
())
return
Promise
.
ofFail
(
ApiNotInitializedException
())
val
params
=
mutableListOf
(
"xt"
to
"user/-/state/com.google/read"
)
if
(!
continuation
.
isNullOrBlank
())
params
.
add
(
"c"
to
continuation
)
if
(
olderTimestamp
>
0
)
params
.
add
(
"ot"
to
"$olderTimestamp"
)
return
Fuel
.
getJson
(
endpoints
.
unreadItemsEndpoint
,
params
)
.
authorize
(
a
uthTokens
)
.
authorize
(
a
ccount
)
.
promise
<
ContentItemsHandler
>()
.
bind
{
it1
->
if
(
it1
.
continuation
.
isNotBlank
()
&&
it1
.
continuation
!=
continuation
)
{
...
...
@@ -114,5 +70,30 @@ class Api {
}
}
private
fun
isLogged
()
=
::
endpoints
.
isInitialized
&&
::
authTokens
.
isInitialized
companion
object
{
fun
login
(
instance
:
String
,
login
:
String
,
password
:
String
):
Promise
<
Account
,
Exception
>
{
val
params
=
listOf
(
"service"
to
"reader"
,
"Email"
to
login
,
"Passwd"
to
password
,
"source"
to
"FreshRSS"
,
"accountType"
to
"GOOGLE"
)
val
temporaryEndpoints
=
Endpoints
(
instance
)
return
Fuel
.
post
(
temporaryEndpoints
.
loginEndpoint
,
params
)
.
promiseWithSerializer
<
Account
>()
.
then
{
it
.
copy
(
serverInstance
=
instance
,
login
=
login
)}
.
bind
{
account
->
Fuel
.
post
(
temporaryEndpoints
.
tokenEndpoint
)
.
header
(
"Authorization"
to
"GoogleLogin auth=${account.SID}"
)
.
promiseString
()
.
then
{
account
.
copy
().
apply
{
this
.
copy
().
writeToken
=
it
}}
.
fail
{}.
then
{
account
}
}
}
}
}
app/src/main/java/fr/chenry/android/freshrss/store/dao/A
uthTokens
.kt
→
app/src/main/java/fr/chenry/android/freshrss/store/dao/A
ccount
.kt
View file @
3bc4c92e
package
fr.chenry.android.freshrss.store.dao
import
androidx.room.*
import
com.github.kittinunf.fuel.core.ResponseDeserializable
import
java.util.*
data class
AuthTokens
(
@Entity
(
tableName
=
"accounts"
)
data class
Account
(
val
SID
:
String
,
val
Auth
:
String
,
val
login
:
String
=
""
val
login
:
String
=
"default_user"
,
val
serverInstance
:
String
=
""
)
{
lateinit
var
token
:
String
// Limit to only one user for now
@PrimaryKey
var
id
=
1
set
(
_
)
=
Unit
var
writeToken
=
""
companion
object
:
ResponseDeserializable
<
AuthTokens
>
{
override
fun
deserialize
(
content
:
String
):
fr
.
chenry
.
android
.
freshrss
.
store
.
dao
.
A
uthTokens
{
companion
object
:
ResponseDeserializable
<
Account
>
{
override
fun
deserialize
(
content
:
String
):
fr
.
chenry
.
android
.
freshrss
.
store
.
dao
.
A
ccount
{
val
properties
=
Properties
()
properties
.
load
(
content
.
reader
())
return
AuthTokens
(
properties
.
getProperty
(
"SID"
,
""
),
properties
.
getProperty
(
"Auth"
,
""
))
return
Account
(
properties
.
getProperty
(
"SID"
,
""
),
properties
.
getProperty
(
"Auth"
,
""
))
}
}
}
@Dao
interface
AuthTokensDAO
{
@Insert
(
onConflict
=
OnConflictStrategy
.
REPLACE
)
fun
insert
(
account
:
Account
)
@Query
(
"SELECT * FROM accounts"
)
fun
getAuthTokens
():
List
<
Account
>
}
\ No newline at end of file
app/src/main/java/fr/chenry/android/freshrss/utils/KotlinExtensions.kt
View file @
3bc4c92e
...
...
@@ -2,7 +2,7 @@ package fr.chenry.android.freshrss.utils
import
android.util.Log
import
fr.chenry.android.freshrss.store.Store
import
fr.chenry.android.freshrss.store.dao.A
uthTokens
import
fr.chenry.android.freshrss.store.dao.A
ccount
import
com.github.kittinunf.fuel.Fuel
import
com.github.kittinunf.fuel.core.*
import
com.github.kittinunf.fuel.serialization.responseObject
...
...
@@ -66,7 +66,7 @@ fun Fuel.Companion.postJson(path: String, parameters: List<Pair<String, Any?>>?
fun
Fuel
.
Companion
.
getJson
(
path
:
String
,
parameters
:
List
<
Pair
<
String
,
Any
?
>>?
=
null
)
=
Fuel
.
get
(
path
,
parameters
.
orEmpty
()
+
(
"output"
to
"json"
))
fun
Request
.
authorize
(
a
uthTokens
:
AuthTokens
)
=
this
.
header
(
"Authorization"
to
"GoogleLogin auth=${authTokens
.SID}"
)
fun
Request
.
authorize
(
a
ccount
:
Account
)
=
this
.
header
(
"Authorization"
to
"GoogleLogin auth=${account
.SID}"
)
fun
Any
.
v
(
message
:
String
)
=
Log
.
v
(
this
::
class
.
qualifiedName
,
message
)
fun
Any
.
v
(
message
:
Throwable
)
=
Log
.
v
(
this
::
class
.
qualifiedName
,
"VERBOSE"
,
message
)
...
...
@@ -90,6 +90,7 @@ fun String?.nullIfBlank() = if(this.isNullOrBlank()) null else this
fun
<
V
,
E
>
Promise
<
V
,
E
>.
getOrDefault
(
default
:
V
)
=
try
{
this
.
get
()
}
catch
(
_
:
Exception
)
{
}
catch
(
e
:
Exception
)
{
this
.
w
(
e
)
default
}
app/src/main/res/values/strings.xml
View file @
3bc4c92e
...
...
@@ -10,7 +10,7 @@
<string
name=
"prompt_instance"
>
Your FreshRSS instance
</string>
<string
name=
"error_instance"
>
This url is not correct
</string>
<string
name=
"protocol_default"
>
https://
</string>
<string
name=
"instance_exemple"
>
your-instance.com
/p
</string>
<string
name=
"instance_exemple"
>
your-instance.com
</string>
<string
name=
"api_endpoint"
>
/api/greader
</string>
<string
name=
"full_instance_exemple"
>
@string/protocol_default
</string>
<string
name=
"login_progress_text"
>
Login to instance %s
</string>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment