Compare commits
2 Commits
f7a29d66ca
...
b7b4ff1485
Author | SHA1 | Date | |
---|---|---|---|
b7b4ff1485 | |||
|
728eb747c3 |
13
.drone.yml
13
.drone.yml
@ -1,21 +1,20 @@
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: android
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: mingc/android-build-box:latest
|
||||
commands:
|
||||
- ./gradlew build
|
||||
|
||||
- name: code-analysis
|
||||
image: mingc/android-build-box:latest
|
||||
failure: ignore
|
||||
commands:
|
||||
- ls -la
|
||||
- ./gradlew sonarqube -Dsonar.projectKey=RFS2 -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\""
|
||||
- ./gradlew sonarqube -Dsonar.projectKey=RFS2 -Dsonar.sources=. -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN
|
||||
environment:
|
||||
SONAR_HOST_URL:
|
||||
from_secret: sonarScannerHostUrl
|
||||
SONAR_LOGIN:
|
||||
from_secret: sonarScannerLogin
|
||||
|
||||
- name: build
|
||||
image: mingc/android-build-box:latest
|
||||
commands:
|
||||
- ./gradlew :androidApp:build -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\""
|
@ -1,7 +1,5 @@
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
val ignoreGitVersion: String by project
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
kotlin("android")
|
||||
@ -34,19 +32,11 @@ fun gitVersion(): String {
|
||||
}
|
||||
|
||||
fun versionCodeFromGit(): Int {
|
||||
if (ignoreGitVersion == "true") {
|
||||
// don't care
|
||||
return 1
|
||||
}
|
||||
println("version code " + gitVersion())
|
||||
return gitVersion().toInt()
|
||||
}
|
||||
|
||||
fun versionNameFromGit(): String {
|
||||
if (ignoreGitVersion == "true") {
|
||||
// don't care
|
||||
return "1"
|
||||
}
|
||||
println("version name " + gitVersion())
|
||||
return gitVersion()
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
// TODO
|
||||
//package bou.amine.apps.readerforselfossv2.android.utils
|
||||
//
|
||||
//import bou.amine.apps.readerforselfossv2.android.utils.Config
|
||||
//import bou.amine.apps.readerforselfossv2.android.utils.parseDate
|
||||
//import org.junit.Test
|
||||
//
|
||||
//class DateUtilsTest {
|
||||
//
|
||||
// @Test
|
||||
// fun parseDateV4() {
|
||||
//
|
||||
// Config.apiVersion = 4
|
||||
// val dateString = "2013-04-07T13:43:00+01:00"
|
||||
//
|
||||
// val milliseconds = parseDate(dateString).toEpochMilli()
|
||||
// val correctMilliseconds : Long = 1365338580000
|
||||
//
|
||||
// assert(milliseconds == correctMilliseconds)
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// fun parseDateV1() {
|
||||
// Config.apiVersion = 0
|
||||
// val dateString = "2013-04-07 13:43:00"
|
||||
//
|
||||
// val milliseconds = parseDate(dateString).toEpochMilli()
|
||||
// val correctMilliseconds = 1365342180000
|
||||
//
|
||||
// assert(milliseconds == correctMilliseconds)
|
||||
// }
|
||||
//}
|
@ -1074,7 +1074,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
|
||||
if (this@HomeActivity.isNetworkAvailable(null, offlineShortcut)) {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
val success = repository.markAllAsRead(items)
|
||||
val success = repository.markAllAsRead(items.map { it.id })
|
||||
if (success) {
|
||||
Toast.makeText(
|
||||
this@HomeActivity,
|
||||
@ -1153,10 +1153,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
||||
|
||||
actions.forEach { action ->
|
||||
when {
|
||||
action.read -> doAndReportOnFail(repository.markAsReadById(action.articleId.toInt()), action)
|
||||
action.unread -> doAndReportOnFail(repository.unmarkAsReadById(action.articleId.toInt()), action)
|
||||
action.starred -> doAndReportOnFail(repository.starrById(action.articleId.toInt()), action)
|
||||
action.unstarred -> doAndReportOnFail(repository.unstarrById(action.articleId.toInt()), action)
|
||||
action.read -> doAndReportOnFail(repository.markAsRead(action.articleId.toInt()), action)
|
||||
action.unread -> doAndReportOnFail(repository.markAsRead(action.articleId.toInt()), action)
|
||||
action.starred -> doAndReportOnFail(repository.markAsRead(action.articleId.toInt()), action)
|
||||
action.unstarred -> doAndReportOnFail(repository.markAsRead(action.articleId.toInt()), action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ class ReaderActivity : AppCompatActivity(), DIAware {
|
||||
private fun readItem(item: SelfossModel.Item) {
|
||||
if (markOnScroll) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
repository.markAsRead(item)
|
||||
repository.markAsRead(item.id)
|
||||
// TODO: Handle failure
|
||||
}
|
||||
}
|
||||
@ -207,13 +207,13 @@ class ReaderActivity : AppCompatActivity(), DIAware {
|
||||
R.id.star -> {
|
||||
if (allItems[binding.pager.currentItem].starred) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
repository.unstarr(allItems[binding.pager.currentItem])
|
||||
repository.unstarr(allItems[binding.pager.currentItem].id)
|
||||
// TODO: Handle failure
|
||||
}
|
||||
afterUnsave()
|
||||
} else {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
repository.starr(allItems[binding.pager.currentItem])
|
||||
repository.starr(allItems[binding.pager.currentItem].id)
|
||||
// TODO: Handle failure
|
||||
}
|
||||
afterSave()
|
||||
|
@ -113,14 +113,14 @@ class ItemCardAdapter(
|
||||
if (c.isNetworkAvailable()) {
|
||||
if (item.starred) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
repository.unstarr(item)
|
||||
repository.unstarr(item.id)
|
||||
// TODO: Handle failure
|
||||
}
|
||||
item.starred = false
|
||||
binding.favButton.isSelected = false
|
||||
} else {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
repository.starr(item)
|
||||
repository.starr(item.id)
|
||||
// TODO: Handle failure
|
||||
}
|
||||
item.starred = true
|
||||
|
@ -79,7 +79,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
private fun readItemAtIndex(position: Int, showSnackbar: Boolean = true) {
|
||||
val i = items[position]
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
repository.markAsRead(i)
|
||||
repository.markAsRead(i.id)
|
||||
}
|
||||
if (repository.displayedItems == ItemType.UNREAD) {
|
||||
items.remove(i)
|
||||
@ -95,7 +95,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
|
||||
private fun unreadItemAtIndex(position: Int, showSnackbar: Boolean = true) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
repository.unmarkAsRead(items[position])
|
||||
repository.unmarkAsRead(items[position].id)
|
||||
// Todo: SharedItems.unreadItem(app, api, db, items[position])
|
||||
// TODO: update db
|
||||
|
||||
|
@ -76,19 +76,19 @@ override fun doWork(): Result {
|
||||
actions.forEach { action ->
|
||||
when {
|
||||
action.read -> doAndReportOnFail(
|
||||
repository.markAsReadById(action.articleId.toInt()),
|
||||
repository.markAsRead(action.articleId.toInt()),
|
||||
action
|
||||
)
|
||||
action.unread -> doAndReportOnFail(
|
||||
repository.unmarkAsReadById(action.articleId.toInt()),
|
||||
repository.unmarkAsRead(action.articleId.toInt()),
|
||||
action
|
||||
)
|
||||
action.starred -> doAndReportOnFail(
|
||||
repository.starrById(action.articleId.toInt()),
|
||||
repository.starr(action.articleId.toInt()),
|
||||
action
|
||||
)
|
||||
action.unstarred -> doAndReportOnFail(
|
||||
repository.unstarrById(action.articleId.toInt()),
|
||||
repository.unstarr(action.articleId.toInt()),
|
||||
action
|
||||
)
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ class ArticleFragment : Fragment(), DIAware {
|
||||
R.id.unread_action -> if (context != null) {
|
||||
if (this@ArticleFragment.item.unread) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
repository.markAsRead(this@ArticleFragment.item)
|
||||
repository.markAsRead(this@ArticleFragment.item.id)
|
||||
}
|
||||
this@ArticleFragment.item.unread = false
|
||||
Toast.makeText(
|
||||
@ -179,7 +179,7 @@ class ArticleFragment : Fragment(), DIAware {
|
||||
).show()
|
||||
} else {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
repository.unmarkAsRead(this@ArticleFragment.item)
|
||||
repository.unmarkAsRead(this@ArticleFragment.item.id)
|
||||
}
|
||||
this@ArticleFragment.item.unread = true
|
||||
Toast.makeText(
|
||||
|
@ -46,16 +46,16 @@ class AppColors(a: Activity) {
|
||||
|
||||
colorBackground = if (isDarkTheme) {
|
||||
a.setTheme(R.style.NoBarDark)
|
||||
a.resources.getColor(R.color.darkBackground)
|
||||
R.color.darkBackground
|
||||
} else {
|
||||
a.setTheme(R.style.NoBar)
|
||||
a.resources.getColor(R.color.grey_50)
|
||||
R.color.grey_50
|
||||
}
|
||||
|
||||
textColor = if (isDarkTheme) {
|
||||
a.resources.getColor(R.color.white)
|
||||
R.color.white
|
||||
} else {
|
||||
a.resources.getColor(R.color.grey_900)
|
||||
R.color.grey_900
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,5 +18,3 @@ kotlin.native.enableDependencyPropagation=false
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
kotlin.mpp.enableGranularSourceSetsMetadata=true
|
||||
org.gradle.parallel=true
|
||||
ignoreGitVersion=false
|
||||
|
@ -89,8 +89,4 @@ android {
|
||||
minSdk = 21
|
||||
targetSdk = 31
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package bou.amine.apps.readerforselfossv2
|
||||
|
||||
actual class Platform actual constructor() {
|
||||
actual val platform: String = "Android ${android.os.Build.VERSION.SDK_INT}"
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package bou.amine.apps.readerforselfossv2.utils
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.text.format.DateUtils
|
||||
import java.time.Instant
|
||||
import java.time.LocalDateTime
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.ZoneOffset
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
actual class DateUtils actual constructor(private val apiMajorVersion: Int) {
|
||||
actual fun parseDate(dateString: String): Long {
|
||||
|
||||
val FORMATTERV1 = "yyyy-MM-dd HH:mm:ss"
|
||||
|
||||
return if (apiMajorVersion >= 4) {
|
||||
OffsetDateTime.parse(dateString).toInstant().toEpochMilli()
|
||||
} else {
|
||||
LocalDateTime.parse(dateString, DateTimeFormatter.ofPattern(FORMATTERV1)).toInstant(
|
||||
ZoneOffset.UTC).toEpochMilli()
|
||||
}
|
||||
}
|
||||
|
||||
actual fun parseRelativeDate(dateString: String): String {
|
||||
|
||||
val date = parseDate(dateString)
|
||||
|
||||
return " " + DateUtils.getRelativeTimeSpanString(
|
||||
date,
|
||||
Instant.now().toEpochMilli(),
|
||||
DateUtils.MINUTE_IN_MILLIS,
|
||||
DateUtils.FORMAT_ABBREV_RELATIVE
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package bou.amine.apps.readerforselfossv2
|
||||
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class AndroidGreetingTest {
|
||||
|
||||
@Test
|
||||
fun testExample() {
|
||||
assertTrue("Check Android is mentioned", Greeting().greeting().contains("Android"))
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package bou.amine.apps.readerforselfossv2
|
||||
|
||||
class Greeting {
|
||||
fun greeting(): String {
|
||||
return "Hello, ${Platform().platform}!"
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package bou.amine.apps.readerforselfossv2
|
||||
|
||||
expect class Platform() {
|
||||
val platform: String
|
||||
}
|
@ -167,86 +167,69 @@ class Repository(private val api: SelfossApi, private val apiDetails: ApiDetails
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun markAsRead(item: SelfossModel.Item): Boolean {
|
||||
val success = markAsReadById(item.id)
|
||||
|
||||
if (success) {
|
||||
markAsReadLocally(item)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
suspend fun markAsReadById(id: Int): Boolean {
|
||||
suspend fun markAsRead(id: Int): Boolean {
|
||||
var success = false
|
||||
|
||||
if (isConnectionAvailable.value) {
|
||||
success = api.markAsRead(id.toString())?.isSuccess == true
|
||||
|
||||
if (success) {
|
||||
markAsReadLocally(items.first { it.id == id })
|
||||
}
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
suspend fun unmarkAsRead(item: SelfossModel.Item): Boolean {
|
||||
// TODO: Check internet connection
|
||||
val success = unmarkAsReadById(item.id)
|
||||
|
||||
if (success) {
|
||||
unmarkAsReadLocally(item)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
suspend fun unmarkAsReadById(id: Int): Boolean {
|
||||
// TODO: Check internet connection
|
||||
suspend fun unmarkAsRead(id: Int): Boolean {
|
||||
var success = false
|
||||
|
||||
if (isConnectionAvailable.value) {
|
||||
success = api.unmarkAsRead(id.toString())?.isSuccess == true
|
||||
|
||||
if (success) {
|
||||
unmarkAsReadLocally(items.first { it.id == id })
|
||||
}
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
suspend fun starr(item: SelfossModel.Item): Boolean {
|
||||
val success = starrById(item.id)
|
||||
|
||||
if (success) {
|
||||
starrLocally(item)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
suspend fun starrById(id: Int): Boolean {
|
||||
suspend fun starr(id: Int): Boolean {
|
||||
var success = false
|
||||
|
||||
if (isConnectionAvailable.value) {
|
||||
success = api.starr(id.toString())?.isSuccess == true
|
||||
|
||||
if (success) {
|
||||
starrLocally(items.first { it.id == id })
|
||||
}
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
suspend fun unstarr(item: SelfossModel.Item): Boolean {
|
||||
val success = unstarrById(item.id)
|
||||
|
||||
if (success) {
|
||||
unstarrLocally(item)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
suspend fun unstarrById(id: Int): Boolean {
|
||||
suspend fun unstarr(id: Int): Boolean {
|
||||
var success = false
|
||||
|
||||
if (isConnectionAvailable.value) {
|
||||
success = api.unstarr(id.toString())?.isSuccess == true
|
||||
|
||||
if (success) {
|
||||
unstarrLocally(items.first { it.id == id })
|
||||
}
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
|
||||
suspend fun markAllAsRead(items: ArrayList<SelfossModel.Item>): Boolean {
|
||||
suspend fun markAllAsRead(ids: List<Int>): Boolean {
|
||||
var success = false
|
||||
if (isConnectionAvailable) {
|
||||
success = api.markAllAsRead(items.map { it.id.toString() })?.isSuccess == true
|
||||
}
|
||||
|
||||
if (success) {
|
||||
for (item in items) {
|
||||
markAsReadLocally(item)
|
||||
if (isConnectionAvailable.value) {
|
||||
success = api.markAllAsRead(ids.map { it.toString() })?.isSuccess == true
|
||||
|
||||
if (success) {
|
||||
val itemsToMark = items.filter { it.id in ids }
|
||||
for (item in itemsToMark) {
|
||||
markAsReadLocally(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
return success
|
||||
|
@ -1,5 +1,7 @@
|
||||
package bou.amine.apps.readerforselfossv2.rest
|
||||
|
||||
import android.os.Parcelable
|
||||
import android.text.Html
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
class SelfossModel {
|
||||
@ -11,7 +13,7 @@ class SelfossModel {
|
||||
val unread: Int
|
||||
) {
|
||||
fun getTitleDecoded(): String {
|
||||
return tag // TODO Html.fromHtml(tag).toString()
|
||||
return Html.fromHtml(tag).toString()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,42 @@
|
||||
package bou.amine.apps.readerforselfossv2.utils
|
||||
|
||||
//import android.text.format.DateUtils
|
||||
import bou.amine.apps.readerforselfossv2.rest.SelfossModel
|
||||
import java.time.Instant
|
||||
import java.time.LocalDateTime
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.ZoneOffset
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
|
||||
fun SelfossModel.Item.parseDate(dateUtils: DateUtils): Long =
|
||||
fun SelfossModel.Item.parseDate(dateUtils: bou.amine.apps.readerforselfossv2.utils.DateUtils): Instant =
|
||||
dateUtils.parseDate(this.datetime)
|
||||
|
||||
fun SelfossModel.Item.parseRelativeDate(dateUtils: DateUtils): String =
|
||||
fun SelfossModel.Item.parseRelativeDate(dateUtils: bou.amine.apps.readerforselfossv2.utils.DateUtils): String =
|
||||
dateUtils.parseRelativeDate(this.datetime)
|
||||
|
||||
expect class DateUtils(apiMajorVersion: Int) {
|
||||
fun parseDate(dateString: String): Long
|
||||
class DateUtils(private val apiMajorVersion: Int) {
|
||||
fun parseDate(dateString: String): Instant {
|
||||
|
||||
fun parseRelativeDate(dateString: String): String
|
||||
}
|
||||
val FORMATTERV1 = "yyyy-MM-dd HH:mm:ss"
|
||||
|
||||
return if (apiMajorVersion >= 4) {
|
||||
OffsetDateTime.parse(dateString).toInstant()
|
||||
} else {
|
||||
LocalDateTime.parse(dateString, DateTimeFormatter.ofPattern(FORMATTERV1)).toInstant(ZoneOffset.UTC)
|
||||
}
|
||||
}
|
||||
|
||||
fun parseRelativeDate(dateString: String): String {
|
||||
|
||||
val date = parseDate(dateString)
|
||||
|
||||
// TODO:
|
||||
// return " " + DateUtils.getRelativeTimeSpanString(
|
||||
// date.toEpochMilli(),
|
||||
// Instant.now().toEpochMilli(),
|
||||
// 60000L, // DateUtils.MINUTE_IN_MILLIS,
|
||||
// 262144 // DateUtils.FORMAT_ABBREV_RELATIVE
|
||||
// )
|
||||
return dateString
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package bou.amine.apps.readerforselfossv2
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class CommonGreetingTest {
|
||||
|
||||
@Test
|
||||
fun testExample() {
|
||||
assertTrue(Greeting().greeting().contains("Hello"), "Check 'Hello' is mentioned")
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package bou.amine.apps.readerforselfossv2
|
||||
|
||||
import platform.UIKit.UIDevice
|
||||
|
||||
actual class Platform actual constructor() {
|
||||
actual val platform: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
|
||||
}
|
Loading…
Reference in New Issue
Block a user