chore: code style fixes for ktlint
Some checks failed
Check PR code / Lint (pull_request) Failing after 2m19s
Check PR code / build (pull_request) Has been skipped

This commit is contained in:
2025-01-11 15:23:02 +01:00
parent 5035392aff
commit 4fbebf2954
67 changed files with 1062 additions and 877 deletions

View File

@ -20,65 +20,72 @@ import org.hamcrest.Matchers.hasToString
fun performLogin(someUrl: String? = null) {
onView(withId(R.id.urlView)).perform(click()).perform(
typeTextIntoFocusedView(
if (!someUrl.isNullOrEmpty()) someUrl else "http://10.0.2.2:8888"
)
if (!someUrl.isNullOrEmpty()) someUrl else "http://10.0.2.2:8888",
),
)
onView(withId(R.id.signInButton)).perform(click())
}
fun loginAndInitHome() {
performLogin()
onView(withText(R.string.gdpr_dialog_title)).check(matches(isDisplayed()))
onView(withText("OK")).perform(click())
}
fun changeAndCancelSetting(oldValue: String, newValue: String, openSettingItem: () -> Unit) {
fun changeAndCancelSetting(
oldValue: String,
newValue: String,
openSettingItem: () -> Unit,
) {
openSettingItem()
onView(
withId(android.R.id.edit)
withId(android.R.id.edit),
).perform(replaceText(newValue))
onView(
withId(android.R.id.button2)
withId(android.R.id.button2),
).perform(click())
openSettingItem()
onView(
withId(android.R.id.edit)
withId(android.R.id.edit),
).check(matches(withText(oldValue)))
onView(
withText(newValue)
withText(newValue),
).check(doesNotExist())
onView(
withId(android.R.id.button2)
withId(android.R.id.button2),
).perform(click())
}
fun changeAndSaveSetting(oldValue: String, newValue: String, openSettingItem: () -> Unit) {
fun changeAndSaveSetting(
oldValue: String,
newValue: String,
openSettingItem: () -> Unit,
) {
openSettingItem()
onView(
withId(android.R.id.edit)
withId(android.R.id.edit),
).perform(replaceText(newValue))
onView(
withId(android.R.id.button1)
withId(android.R.id.button1),
).perform(click())
openSettingItem()
onView(
withId(android.R.id.edit)
withId(android.R.id.edit),
).check(matches(withText(newValue)))
if (oldValue.isNotEmpty()) {
onView(
withText(oldValue)
withText(oldValue),
).check(doesNotExist())
}
onView(
withId(android.R.id.button2)
withId(android.R.id.button2),
).perform(click())
}
fun testPreferencesFromArray(
context: Context,
@ArrayRes arrayRes: Int,
openSettingItem: () -> Unit
openSettingItem: () -> Unit,
) {
openSettingItem()
context.resources.getStringArray(arrayRes).forEach { res ->
@ -90,20 +97,25 @@ fun testPreferencesFromArray(
}
}
fun testAddSourceWithUrl(url: String, sourceName: String) {
fun testAddSourceWithUrl(
url: String,
sourceName: String,
) {
onView(withId(R.id.fab))
.perform(click())
onView(withId(R.id.nameInput))
.perform(click()).perform(typeTextIntoFocusedView(sourceName))
.perform(click())
.perform(typeTextIntoFocusedView(sourceName))
onView(withId(R.id.sourceUri))
.perform(click())
.perform(typeTextIntoFocusedView(url))
onView(withId(R.id.tags))
.perform(click()).perform(typeTextIntoFocusedView("tag1,tag2,tag3"))
.perform(click())
.perform(typeTextIntoFocusedView("tag1,tag2,tag3"))
onView(withId(R.id.spoutsSpinner))
.perform(click())
onData(hasToString("RSS Feed")).perform(click())
onView(withId(R.id.saveBtn))
.perform(click())
onView(withText(sourceName)).check(matches(isDisplayed()))
}
}

View File

@ -25,8 +25,9 @@ import org.hamcrest.Matcher
import org.hamcrest.Matchers
import org.hamcrest.TypeSafeMatcher
fun withError(@StringRes id: Int): TypeSafeMatcher<View?> {
fun withError(
@StringRes id: Int,
): TypeSafeMatcher<View?> {
return object : TypeSafeMatcher<View?>() {
override fun matchesSafely(view: View?): Boolean {
if (view == null) {
@ -48,11 +49,11 @@ fun withError(@StringRes id: Int): TypeSafeMatcher<View?> {
}
}
fun isPopupWindow(): Matcher<Root> {
return isPlatformPopup()
}
fun isPopupWindow(): Matcher<Root> = isPlatformPopup()
fun withDrawable(@DrawableRes id: Int) = object : TypeSafeMatcher<View>() {
fun withDrawable(
@DrawableRes id: Int,
) = object : TypeSafeMatcher<View>() {
override fun describeTo(description: Description) {
description.appendText("ImageView with drawable same as drawable with id $id")
}
@ -68,43 +69,46 @@ fun withDrawable(@DrawableRes id: Int) = object : TypeSafeMatcher<View>() {
}
}
fun hasBottombarItemText(@StringRes id: Int): Matcher<View>? {
return allOf(
fun hasBottombarItemText(
@StringRes id: Int,
): Matcher<View>? =
allOf(
withResourceName("fixed_bottom_navigation_icon"),
withParent(
allOf(
withResourceName("fixed_bottom_navigation_icon_container"),
hasSibling(withText(id))
)
)
hasSibling(withText(id)),
),
),
)
}
fun withSettingsCheckboxWidget(@StringRes id: Int): Matcher<View>? {
return allOf(
fun withSettingsCheckboxWidget(
@StringRes id: Int,
): Matcher<View>? =
allOf(
withId(android.R.id.switch_widget),
withParent(
withSettingsCheckboxFrame(id)
)
withSettingsCheckboxFrame(id),
),
)
}
fun withSettingsCheckboxFrame(@StringRes id: Int): Matcher<View>? {
return allOf(
fun withSettingsCheckboxFrame(
@StringRes id: Int,
): Matcher<View>? =
allOf(
withId(android.R.id.widget_frame),
hasSibling(
allOf(
withClassName(Matchers.equalTo(RelativeLayout::class.java.name)),
withChild(
withText(id)
)
)
)
withText(id),
),
),
),
)
}
fun openMenu() {
openActionBarOverflowOrOptionsMenu(
ApplicationProvider.getApplicationContext<Context>()
ApplicationProvider.getApplicationContext<Context>(),
)
}
}

View File

@ -23,7 +23,6 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@LargeTest
class HomeActivityTest {
@get:Rule
val activityRule = ActivityScenarioRule(LoginActivity::class.java)
@ -36,13 +35,13 @@ class HomeActivityTest {
fun testMenu() {
onView(withId(R.id.action_search)).check(matches(isDisplayed())).check(
matches(
isClickable()
)
isClickable(),
),
)
onView(withId(R.id.action_filter)).check(matches(isDisplayed())).check(
matches(
isClickable()
)
isClickable(),
),
)
openMenu()
onView(withText(R.string.readAll)).check(matches(isDisplayed()))
@ -57,19 +56,19 @@ class HomeActivityTest {
fun testMenuActions() {
onView(withId(R.id.action_search)).perform(click())
onView(
withId(R.id.search_src_text)
withId(R.id.search_src_text),
).check(matches(isFocused()))
onView(isRoot()).perform(ViewActions.pressBack())
onView(withId(R.id.action_filter)).perform(click())
onView(
withText(R.string.filter_item_sources)
withText(R.string.filter_item_sources),
).check(matches(isDisplayed()))
onView(
withText(R.string.filter_item_tags)
withText(R.string.filter_item_tags),
).check(matches(isDisplayed()))
onView(
withId(R.id.floatingActionButton2)
withId(R.id.floatingActionButton2),
).check(matches(isDisplayed()))
onView(isRoot()).perform(ViewActions.pressBack())
@ -107,14 +106,13 @@ class HomeActivityTest {
fun testEmptyView() {
onView(withId(R.id.emptyText)).check(matches(isDisplayed()))
onView(
hasBottombarItemText(R.string.tab_new)
hasBottombarItemText(R.string.tab_new),
).check(matches(isDisplayed())).check(matches(isSelected()))
onView(
hasBottombarItemText(R.string.tab_read)
hasBottombarItemText(R.string.tab_read),
).check(matches(isDisplayed())).check(matches(not(isSelected())))
onView(
hasBottombarItemText(R.string.tab_favs)
hasBottombarItemText(R.string.tab_favs),
).check(matches(isDisplayed())).check(matches(not(isSelected())))
}
}
}

View File

@ -23,7 +23,6 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@LargeTest
class LoginActivityTest {
@get:Rule
val activityRule = ActivityScenarioRule(LoginActivity::class.java)
@ -37,26 +36,32 @@ class LoginActivityTest {
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance()
IdlingRegistry
.getInstance()
.register(CountingIdlingResourceSingleton.countingIdlingResource)
}
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance()
IdlingRegistry
.getInstance()
.unregister(CountingIdlingResourceSingleton.countingIdlingResource)
}
@Test
fun viewIsInitialized() {
onView(withId(R.id.urlView)).check(matches(isDisplayed()))
onView(withId(R.id.selfSigned)).check(matches(isDisplayed())).check(matches(isNotChecked()))
onView(withId(R.id.selfSigned))
.check(matches(isDisplayed()))
.check(matches(isNotChecked()))
.check(
matches(isClickable())
matches(isClickable()),
)
onView(withId(R.id.withLogin)).check(matches(isDisplayed()))
.check(matches(isNotChecked())).check(
matches(isClickable())
onView(withId(R.id.withLogin))
.check(matches(isDisplayed()))
.check(matches(isNotChecked()))
.check(
matches(isClickable()),
)
}
@ -80,4 +85,4 @@ class LoginActivityTest {
performLogin()
onView(withText(R.string.gdpr_dialog_title)).check(matches(isDisplayed()))
}
}
}

View File

@ -26,11 +26,9 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@LargeTest
class SettingsActivityGeneralTest {
@get:Rule
val activityRule = ActivityScenarioRule(LoginActivity::class.java)
@ -38,7 +36,7 @@ class SettingsActivityGeneralTest {
fun init() {
loginAndInitHome()
openActionBarOverflowOrOptionsMenu(
ApplicationProvider.getApplicationContext()
ApplicationProvider.getApplicationContext(),
)
onView(withText(R.string.title_activity_settings)).perform(click())
onView(withText(R.string.pref_header_general)).perform(click())
@ -48,68 +46,75 @@ class SettingsActivityGeneralTest {
fun testGeneral() {
onView(withText(R.string.pref_api_items_number_title)).check(matches(isDisplayed()))
onView(
withSettingsCheckboxWidget(R.string.pref_general_infinite_loading_title)
withSettingsCheckboxWidget(R.string.pref_general_infinite_loading_title),
).check(
matches(
allOf(
isDisplayed(), not(isChecked())
)
)
isDisplayed(),
not(isChecked()),
),
),
)
onView(withText(R.string.pref_general_category_links)).check(matches(isDisplayed()))
onView(withSettingsCheckboxWidget(R.string.pref_article_viewer_title)).check(
matches(
allOf(
isDisplayed(), isChecked()
)
)
isDisplayed(),
isChecked(),
),
),
)
onView(withSettingsCheckboxWidget(R.string.reader_static_bar_title)).check(
matches(
allOf(
isDisplayed(), not(isChecked())
)
)
isDisplayed(),
not(isChecked()),
),
),
)
onView(withSettingsCheckboxFrame(R.string.reader_static_bar_title)).check(
matches(
isEnabled()
)
isEnabled(),
),
)
onView(withText(R.string.pref_general_category_displaying)).check(matches(isDisplayed()))
onView(withSettingsCheckboxWidget(R.string.pref_switch_card_view_title)).check(
matches(
allOf(
isDisplayed(), not(isChecked())
)
)
isDisplayed(),
not(isChecked()),
),
),
)
onView(withSettingsCheckboxWidget(R.string.card_height_title)).check(
matches(
allOf(
isDisplayed(), not(isChecked())
)
)
isDisplayed(),
not(isChecked()),
),
),
)
onView(withSettingsCheckboxFrame(R.string.card_height_title)).check(
matches(
not(isEnabled())
)
not(isEnabled()),
),
)
onView(withSettingsCheckboxWidget(R.string.switch_unread_count_title)).check(
matches(
allOf(
isDisplayed(), isChecked()
)
)
isDisplayed(),
isChecked(),
),
),
)
onView(withId(R.id.settings)).perform(swipeUp())
onView(withSettingsCheckboxWidget(R.string.display_all_counts_title)).check(
matches(
allOf(
isDisplayed(), not(isChecked())
)
)
isDisplayed(),
not(isChecked()),
),
),
)
}
@ -120,25 +125,25 @@ class SettingsActivityGeneralTest {
// Value check
onView(
withId(android.R.id.edit)
withId(android.R.id.edit),
).perform(replaceText("AVC"))
.check(matches(withText("")))
// TODO: should check message error. Not working for api level 30+
onView(
withId(android.R.id.edit)
withId(android.R.id.edit),
).perform(replaceText("-1"))
.check(matches(withText("")))
// TODO: should check message error. Not working for api level 30+
onView(
withId(android.R.id.edit)
withId(android.R.id.edit),
).perform(replaceText("300"))
.check(matches(withText("")))
onView(
withId(android.R.id.edit)
withId(android.R.id.edit),
).perform(typeTextIntoFocusedView("300"))
.check(matches(withText("30")))
onView(
withId(android.R.id.edit)
withId(android.R.id.edit),
).perform(replaceText("10"))
.check(matches(withText("10")))
onView(isRoot()).perform(ViewActions.pressBack())
@ -157,18 +162,18 @@ class SettingsActivityGeneralTest {
// article viewer settings
onView(withSettingsCheckboxFrame(R.string.reader_static_bar_title)).check(
matches(
isEnabled()
)
isEnabled(),
),
)
onView(withSettingsCheckboxWidget(R.string.pref_article_viewer_title)).perform(click())
onView(withSettingsCheckboxFrame(R.string.reader_static_bar_title)).check(
matches(
not(isEnabled())
)
not(isEnabled()),
),
)
onView(withSettingsCheckboxFrame(R.string.card_height_title)).check(matches(not(isEnabled())))
onView(withSettingsCheckboxWidget(R.string.pref_switch_card_view_title)).perform(click())
onView(withSettingsCheckboxFrame(R.string.card_height_title)).check(matches(isEnabled()))
}
}
}

View File

@ -21,11 +21,9 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@LargeTest
class SettingsActivityOfflineTest {
@get:Rule
val activityRule = ActivityScenarioRule(LoginActivity::class.java)
@ -38,7 +36,7 @@ class SettingsActivityOfflineTest {
}
loginAndInitHome()
openActionBarOverflowOrOptionsMenu(
ApplicationProvider.getApplicationContext()
ApplicationProvider.getApplicationContext(),
)
onView(withText(R.string.title_activity_settings)).perform(click())
onView(withText(R.string.pref_header_offline)).perform(click())
@ -49,58 +47,63 @@ class SettingsActivityOfflineTest {
onView(withSettingsCheckboxWidget(R.string.pref_switch_periodic_refresh)).check(
matches(
allOf(
isDisplayed(), not(isChecked())
)
)
isDisplayed(),
not(isChecked()),
),
),
)
onView(withSettingsCheckboxWidget(R.string.pref_switch_items_caching)).check(
matches(
allOf(
isDisplayed(), not(isChecked())
)
)
isDisplayed(),
not(isChecked()),
),
),
)
onView(withSettingsCheckboxFrame(R.string.pref_switch_items_caching)).check(
matches(
isEnabled()
)
isEnabled(),
),
)
onView(withText(R.string.pref_periodic_refresh_minutes_title)).check(
matches(
allOf(isNotEnabled(), isDisplayed())
)
allOf(isNotEnabled(), isDisplayed()),
),
)
onView(withSettingsCheckboxWidget(R.string.pref_switch_refresh_when_charging)).check(
matches(
allOf(
isDisplayed(), not(isChecked())
)
)
isDisplayed(),
not(isChecked()),
),
),
)
onView(withSettingsCheckboxFrame(R.string.pref_switch_refresh_when_charging)).check(
matches(
isNotEnabled()
)
isNotEnabled(),
),
)
onView(withSettingsCheckboxWidget(R.string.pref_switch_notify_new_items)).check(
matches(
allOf(
isDisplayed(), not(isChecked())
)
)
isDisplayed(),
not(isChecked()),
),
),
)
onView(withSettingsCheckboxFrame(R.string.pref_switch_notify_new_items)).check(
matches(
isNotEnabled()
)
isNotEnabled(),
),
)
onView(withSettingsCheckboxWidget(R.string.pref_switch_update_sources)).check(
matches(
allOf(
isDisplayed(), isChecked()
)
)
isDisplayed(),
isChecked(),
),
),
)
}
@ -111,50 +114,50 @@ class SettingsActivityOfflineTest {
onView(withText(R.string.pref_switch_items_caching_on)).check(matches(isDisplayed()))
onView(withSettingsCheckboxFrame(R.string.pref_switch_items_caching)).check(
matches(
isEnabled()
)
isEnabled(),
),
)
onView(withText(R.string.pref_periodic_refresh_minutes_title)).check(
matches(
isNotEnabled()
)
isNotEnabled(),
),
)
onView(withSettingsCheckboxFrame(R.string.pref_switch_refresh_when_charging)).check(
matches(
isNotEnabled()
)
isNotEnabled(),
),
)
onView(withSettingsCheckboxFrame(R.string.pref_switch_notify_new_items)).check(
matches(
isNotEnabled()
)
isNotEnabled(),
),
)
onView(withText(R.string.pref_switch_periodic_refresh_off)).check(
matches(
isDisplayed()
)
isDisplayed(),
),
)
onView(withSettingsCheckboxWidget(R.string.pref_switch_periodic_refresh)).perform(click())
onView(withText(R.string.pref_switch_periodic_refresh_on)).check(
matches(
isDisplayed()
)
isDisplayed(),
),
)
onView(withSettingsCheckboxFrame(R.string.pref_periodic_refresh_minutes_title)).check(
matches(
isEnabled()
)
isEnabled(),
),
)
onView(withSettingsCheckboxFrame(R.string.pref_switch_refresh_when_charging)).check(
matches(
isEnabled()
)
isEnabled(),
),
)
onView(withSettingsCheckboxFrame(R.string.pref_switch_notify_new_items)).check(
matches(
isEnabled()
)
isEnabled(),
),
)
changeAndCancelSetting("360", "123") {
onView(withText(R.string.pref_periodic_refresh_minutes_title)).perform(click())
@ -166,4 +169,4 @@ class SettingsActivityOfflineTest {
onView(withSettingsCheckboxFrame(R.string.pref_switch_notify_new_items)).perform(click())
onView(withSettingsCheckboxWidget(R.string.pref_switch_update_sources)).perform(click())
}
}
}

View File

@ -19,11 +19,9 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@LargeTest
class SettingsActivityReaderTest {
@get:Rule
val activityRule = ActivityScenarioRule(LoginActivity::class.java)
@ -36,7 +34,7 @@ class SettingsActivityReaderTest {
}
loginAndInitHome()
openActionBarOverflowOrOptionsMenu(
ApplicationProvider.getApplicationContext()
ApplicationProvider.getApplicationContext(),
)
onView(withText(R.string.title_activity_settings)).perform(click())
onView(withText(R.string.pref_header_viewer)).perform(click())
@ -47,11 +45,12 @@ class SettingsActivityReaderTest {
onView(withSettingsCheckboxFrame(R.string.pref_switch_actions_pager_scroll)).check(
matches(
allOf(
isDisplayed(), not(
isChecked()
)
)
)
isDisplayed(),
not(
isChecked(),
),
),
),
)
onView(withText(R.string.pref_content_reader_font_size)).check(matches(isDisplayed()))
onView(withText(R.string.settings_reader_font)).check(matches(isDisplayed()))
@ -61,14 +60,14 @@ class SettingsActivityReaderTest {
fun testReaderActions() {
onView(withText(R.string.pref_switch_actions_pager_scroll_off)).check(
matches(
isDisplayed()
)
isDisplayed(),
),
)
onView(withSettingsCheckboxFrame(R.string.pref_switch_actions_pager_scroll)).perform(click())
onView(withText(R.string.pref_switch_actions_pager_scroll_on)).check(
matches(
isDisplayed()
)
isDisplayed(),
),
)
onView(withText(R.string.pref_content_reader_font_size)).perform(click())
@ -83,4 +82,4 @@ class SettingsActivityReaderTest {
onView(withText(R.string.settings_reader_font)).perform(click())
}
}
}
}

View File

@ -20,7 +20,6 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@LargeTest
class SettingsActivityTest {
@get:Rule
val activityRule = ActivityScenarioRule(LoginActivity::class.java)
lateinit var context: Context
@ -35,10 +34,8 @@ class SettingsActivityTest {
onView(withText(R.string.title_activity_settings)).perform(click())
}
@Test
fun testAllSettings() {
onView(withText(R.string.pref_header_general)).check(matches(isDisplayed()))
onView(withText(R.string.pref_header_viewer)).check(matches(isDisplayed()))
onView(withText(R.string.pref_header_offline)).check(matches(isDisplayed()))
@ -48,14 +45,13 @@ class SettingsActivityTest {
matches(
allOf(
isDisplayed(),
not(isSelected())
)
)
not(isSelected()),
),
),
)
onView(withText(R.string.action_about)).check(matches(isDisplayed()))
}
@Test
fun testThemes() {
testPreferencesFromArray(context, R.array.ModeTitles) {
@ -63,7 +59,6 @@ class SettingsActivityTest {
}
}
@Test
fun testExperimentail() {
onView(withText(R.string.pref_header_experimental)).perform(click())
@ -75,13 +70,11 @@ class SettingsActivityTest {
}
}
@Test
fun testBugReports() {
onView(withText(R.string.pref_switch_disable_acra)).perform(click())
}
@Test
fun testLinks() {
onView(withText(R.string.pref_header_links)).perform(click())
@ -91,10 +84,9 @@ class SettingsActivityTest {
onView(withText(R.string.translation)).check(matches(isDisplayed()))
}
@Test
fun testAbout() {
onView(withText(R.string.action_about)).perform(click())
onView(withText("ACRA")).check(matches(isDisplayed()))
}
}
}

View File

@ -41,11 +41,10 @@ class SourcesActivityTest {
fun addSource() {
testAddSourceWithUrl(
"https://lorem-rss.herokuapp.com/feed?unit=year&interval=1&length=10",
sourceName
sourceName,
)
}
@Test
fun addSourceCheckContent() {
testAddSourceWithUrl("https://news.google.com/rss?hl=en-US&gl=US&ceid=US:en", sourceName)
@ -54,7 +53,7 @@ class SourcesActivityTest {
onView(withText(R.string.menu_home_refresh)).perform(click())
onView(withText(R.string.refresh_dialog_message)).check(matches(isDisplayed()))
onView(
withId(android.R.id.button1)
withId(android.R.id.button1),
).perform(click())
Thread.sleep(10000)
onView(withId(R.id.swipeRefreshLayout)).perform(swipeDown())
@ -74,10 +73,9 @@ class SourcesActivityTest {
onView(withText(sourceName)).check(doesNotExist())
}
private fun goToSources() {
openMenu()
onView(withText(R.string.menu_home_sources))
.perform(click())
}
}
}

View File

@ -49,7 +49,10 @@ import org.kodein.di.instance
import java.security.MessageDigest
import java.util.concurrent.TimeUnit
class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAware {
class HomeActivity :
AppCompatActivity(),
SearchView.OnQueryTextListener,
DIAware {
private var items: ArrayList<SelfossModel.Item> = ArrayList()
private var elementsShown: ItemType = ItemType.UNREAD
@ -171,11 +174,12 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
getElementsAccordingToTab()
}
} else {
Toast.makeText(
this@HomeActivity,
"Found null when swiping at positon $position.",
Toast.LENGTH_LONG,
).show()
Toast
.makeText(
this@HomeActivity,
"Found null when swiping at positon $position.",
Toast.LENGTH_LONG,
).show()
}
}
}
@ -200,15 +204,18 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
tabNewBadge =
TextBadgeItem()
.setText("")
.setHideOnSelect(false).hide(false)
.setHideOnSelect(false)
.hide(false)
tabArchiveBadge =
TextBadgeItem()
.setText("")
.setHideOnSelect(false).hide(false)
.setHideOnSelect(false)
.hide(false)
tabStarredBadge =
TextBadgeItem()
.setText("")
.setHideOnSelect(false).hide(false)
.setHideOnSelect(false)
.hide(false)
if (appSettingsService.isDisplayUnreadCountEnabled()) {
lifecycleScope.launch {
@ -236,14 +243,12 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
BottomNavigationItem(
R.drawable.ic_tab_fiber_new_black_24dp,
getString(R.string.tab_new),
)
.setBadgeItem(tabNewBadge)
).setBadgeItem(tabNewBadge)
val tabArchive =
BottomNavigationItem(
R.drawable.ic_tab_archive_black_24dp,
getString(R.string.tab_read),
)
.setBadgeItem(tabArchiveBadge)
).setBadgeItem(tabArchiveBadge)
val tabStarred =
BottomNavigationItem(
R.drawable.ic_tab_favorite_black_24dp,
@ -425,17 +430,17 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
binding.recyclerView.addOnScrollListener(recyclerViewScrollListener)
}
private fun getLastVisibleItem(): Int {
return when (val manager = binding.recyclerView.layoutManager) {
private fun getLastVisibleItem(): Int =
when (val manager = binding.recyclerView.layoutManager) {
is StaggeredGridLayoutManager ->
manager.findLastCompletelyVisibleItemPositions(
null,
).last()
manager
.findLastCompletelyVisibleItemPositions(
null,
).last()
is GridLayoutManager -> manager.findLastCompletelyVisibleItemPosition()
else -> 0
}
}
private fun mayBeEmpty() =
if (items.isEmpty()) {
@ -577,7 +582,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
messageRes: Int,
doFn: () -> Unit,
) {
AlertDialog.Builder(this@HomeActivity)
AlertDialog
.Builder(this@HomeActivity)
.setMessage(messageRes)
.setTitle(titleRes)
.setPositiveButton(android.R.string.ok) { _, _ -> doFn() }
@ -589,7 +595,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.issue_tracker -> {
baseContext.openUrlInBrowser(AppSettingsService.trackerUrl)
baseContext.openUrlInBrowser(AppSettingsService.BUG_URL)
return true
}
@ -606,18 +612,19 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
CoroutineScope(Dispatchers.Main).launch {
val updatedRemote = repository.updateRemote()
if (updatedRemote) {
Toast.makeText(
this@HomeActivity,
R.string.refresh_success_response,
Toast.LENGTH_LONG,
)
.show()
Toast
.makeText(
this@HomeActivity,
R.string.refresh_success_response,
Toast.LENGTH_LONG,
).show()
} else {
Toast.makeText(
this@HomeActivity,
R.string.refresh_failer_message,
Toast.LENGTH_SHORT,
).show()
Toast
.makeText(
this@HomeActivity,
R.string.refresh_failer_message,
Toast.LENGTH_SHORT,
).show()
}
CountingIdlingResourceSingleton.decrement()
}
@ -633,25 +640,26 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
CoroutineScope(Dispatchers.Main).launch {
val success = repository.markAllAsRead(items)
if (success) {
Toast.makeText(
this@HomeActivity,
R.string.all_posts_read,
Toast.LENGTH_SHORT,
).show()
Toast
.makeText(
this@HomeActivity,
R.string.all_posts_read,
Toast.LENGTH_SHORT,
).show()
tabNewBadge.removeBadge()
getElementsAccordingToTab()
} else {
Toast.makeText(
this@HomeActivity,
R.string.all_posts_not_read,
Toast.LENGTH_SHORT,
).show()
Toast
.makeText(
this@HomeActivity,
R.string.all_posts_not_read,
Toast.LENGTH_SHORT,
).show()
}
handleListResult()
binding.swipeRefreshLayout.isRefreshing = false
CountingIdlingResourceSingleton.decrement()
}
}
}
@ -661,7 +669,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
R.id.action_disconnect -> {
needsConfirmation(
R.string.confirm_disconnect_title,
R.string.confirm_disconnect_description
R.string.confirm_disconnect_description,
) {
runBlocking {
repository.logout()
@ -702,7 +710,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
private fun handleRecurringTask() {
if (appSettingsService.isPeriodicRefreshEnabled()) {
val myConstraints =
Constraints.Builder()
Constraints
.Builder()
.setRequiresBatteryNotLow(true)
.setRequiresCharging(appSettingsService.isRefreshWhenChargingOnlyEnabled())
.setRequiresStorageNotLow(true)
@ -711,19 +720,19 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
val backgroundWork =
PeriodicWorkRequestBuilder<LoadingWorker>(
appSettingsService.getRefreshMinutes(),
TimeUnit.MINUTES
)
.setConstraints(myConstraints)
TimeUnit.MINUTES,
).setConstraints(myConstraints)
.addTag("selfoss-loading")
.build()
WorkManager.getInstance(
baseContext,
).enqueueUniquePeriodicWork(
"selfoss-loading",
ExistingPeriodicWorkPolicy.KEEP,
backgroundWork
)
WorkManager
.getInstance(
baseContext,
).enqueueUniquePeriodicWork(
"selfoss-loading",
ExistingPeriodicWorkPolicy.KEEP,
backgroundWork,
)
}
}
}
}

View File

@ -84,7 +84,9 @@ class ImageActivity : AppCompatActivity() {
return super.onOptionsItemSelected(item)
}
private inner class ScreenSlidePagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) {
private inner class ScreenSlidePagerAdapter(
fa: FragmentActivity,
) : FragmentStateAdapter(fa) {
override fun getItemCount(): Int = allImages.size
override fun createFragment(position: Int): Fragment = ImageFragment.newInstance(allImages[position])

View File

@ -30,7 +30,9 @@ import org.kodein.di.DIAware
import org.kodein.di.android.closestDI
import org.kodein.di.instance
class LoginActivity : AppCompatActivity(), DIAware {
class LoginActivity :
AppCompatActivity(),
DIAware {
private var inValidCount: Int = 0
private var isWithLogin = false
@ -108,7 +110,7 @@ class LoginActivity : AppCompatActivity(), DIAware {
repository.updateApiInformation()
ACRA.errorReporter.putCustomData(
"SELFOSS_API_VERSION",
appSettingsService.getApiVersion().toString()
appSettingsService.getApiVersion().toString(),
)
CountingIdlingResourceSingleton.decrement()
}
@ -132,9 +134,18 @@ class LoginActivity : AppCompatActivity(), DIAware {
binding.passwordView.error = null
// Store values at the time of the login attempt.
val url = binding.urlView.text.toString().trim()
val login = binding.loginView.text.toString().trim()
val password = binding.passwordView.text.toString().trim()
val url =
binding.urlView.text
.toString()
.trim()
val login =
binding.loginView.text
.toString()
.trim()
val password =
binding.passwordView.text
.toString()
.trim()
failInvalidUrl(url)
failLoginDetails(password, login)
@ -151,11 +162,12 @@ class LoginActivity : AppCompatActivity(), DIAware {
repository.updateApiInformation()
} catch (e: Exception) {
if (e.message?.startsWith("No transformation found") == true) {
Toast.makeText(
applicationContext,
R.string.application_selfoss_only,
Toast.LENGTH_LONG,
).show()
Toast
.makeText(
applicationContext,
R.string.application_selfoss_only,
Toast.LENGTH_LONG,
).show()
preferenceError()
showProgress(false)
}
@ -270,7 +282,7 @@ class LoginActivity : AppCompatActivity(), DIAware {
return when (item.itemId) {
R.id.issue_tracker -> {
val browserIntent =
Intent(Intent.ACTION_VIEW, Uri.parse(AppSettingsService.trackerUrl))
Intent(Intent.ACTION_VIEW, Uri.parse(AppSettingsService.BUG_URL))
startActivity(browserIntent)
return true
}
@ -280,9 +292,9 @@ class LoginActivity : AppCompatActivity(), DIAware {
.withAboutIconShown(true)
.withAboutVersionShown(true)
.withAboutSpecial2("Bug reports")
.withAboutSpecial2Description(AppSettingsService.trackerUrl)
.withAboutSpecial2Description(AppSettingsService.BUG_URL)
.withAboutSpecial1("Project Page")
.withAboutSpecial1Description(AppSettingsService.sourceUrl)
.withAboutSpecial1Description(AppSettingsService.SOURCE_URL)
.start(this)
true
}
@ -290,4 +302,4 @@ class LoginActivity : AppCompatActivity(), DIAware {
else -> super.onOptionsItemSelected(item)
}
}
}
}

View File

@ -9,11 +9,11 @@ import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.multidex.MultiDexApplication
import bou.amine.apps.readerforselfossv2.DI.networkModule
import bou.amine.apps.readerforselfossv2.android.testing.TestingHelper
import bou.amine.apps.readerforselfossv2.android.viewmodel.AppViewModel
import bou.amine.apps.readerforselfossv2.dao.DriverFactory
import bou.amine.apps.readerforselfossv2.dao.ReaderForSelfossDB
import bou.amine.apps.readerforselfossv2.di.networkModule
import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
import com.github.ln_12.library.ConnectivityStatus
@ -36,21 +36,23 @@ import org.kodein.di.bind
import org.kodein.di.instance
import org.kodein.di.singleton
class MyApp : MultiDexApplication(), DIAware {
class MyApp :
MultiDexApplication(),
DIAware {
override val di by DI.lazy {
bind<AppSettingsService>() with singleton { AppSettingsService(ACRA.isACRASenderServiceProcess() || TestingHelper().isUnitTest()) }
import(networkModule)
bind<DriverFactory>() with singleton { DriverFactory(applicationContext) }
bind<ReaderForSelfossDB>() with singleton { ReaderForSelfossDB(driverFactory.createDriver()) }
bind<Repository>() with
singleton {
Repository(
instance(),
instance(),
isConnectionAvailable,
instance(),
)
}
singleton {
Repository(
instance(),
instance(),
isConnectionAvailable,
instance(),
)
}
bind<ConnectivityStatus>() with singleton { ConnectivityStatus(applicationContext) }
bind<AppViewModel>() with singleton { AppViewModel(repository = instance()) }
}
@ -89,11 +91,12 @@ class MyApp : MultiDexApplication(), DIAware {
R.string.network_connectivity_lost
}
Toast.makeText(
applicationContext,
toastMessage,
Toast.LENGTH_SHORT,
).show()
Toast
.makeText(
applicationContext,
toastMessage,
Toast.LENGTH_SHORT,
).show()
}
}
}
@ -151,13 +154,13 @@ class MyApp : MultiDexApplication(), DIAware {
val name = getString(R.string.notification_channel_sync)
val importance = NotificationManager.IMPORTANCE_LOW
val mChannel = NotificationChannel(AppSettingsService.syncChannelId, name, importance)
val mChannel = NotificationChannel(AppSettingsService.SYNC_CHANNEL_ID, name, importance)
val newItemsChannelname = getString(R.string.new_items_channel_sync)
val newItemsChannelimportance = NotificationManager.IMPORTANCE_DEFAULT
val newItemsChannelmChannel =
NotificationChannel(
AppSettingsService.newItemsChannelId,
AppSettingsService.NEW_ITEMS_CHANNEL,
newItemsChannelname,
newItemsChannelimportance,
)
@ -199,4 +202,4 @@ class MyApp : MultiDexApplication(), DIAware {
super.onPause(owner)
}
}
}
}

View File

@ -22,7 +22,9 @@ import org.kodein.di.DIAware
import org.kodein.di.android.closestDI
import org.kodein.di.instance
class ReaderActivity : AppCompatActivity(), DIAware {
class ReaderActivity :
AppCompatActivity(),
DIAware {
private var currentItem: Int = 0
private lateinit var toolbarMenu: Menu
@ -99,19 +101,19 @@ class ReaderActivity : AppCompatActivity(), DIAware {
oldInstanceState.clear()
}
private inner class ScreenSlidePagerAdapter(fa: FragmentActivity) :
FragmentStateAdapter(fa) {
private inner class ScreenSlidePagerAdapter(
fa: FragmentActivity,
) : FragmentStateAdapter(fa) {
override fun getItemCount(): Int = allItems.size
override fun createFragment(position: Int): Fragment =
ArticleFragment.newInstance(allItems[position])
override fun createFragment(position: Int): Fragment = ArticleFragment.newInstance(allItems[position])
}
override fun onKeyDown(
keyCode: Int,
event: KeyEvent?,
): Boolean {
return when (keyCode) {
): Boolean =
when (keyCode) {
KeyEvent.KEYCODE_VOLUME_DOWN -> {
val currentFragment =
supportFragmentManager.findFragmentByTag("f" + binding.pager.currentItem) as ArticleFragment
@ -130,7 +132,6 @@ class ReaderActivity : AppCompatActivity(), DIAware {
super.onKeyDown(keyCode, event)
}
}
}
private fun alignmentMenu() {
val showJustify = appSettingsService.getActiveAllignment() == AppSettingsService.ALIGN_LEFT
@ -229,4 +230,4 @@ class ReaderActivity : AppCompatActivity(), DIAware {
startActivity(intent)
overridePendingTransition(0, 0)
}
}
}

View File

@ -18,7 +18,9 @@ import org.kodein.di.DIAware
import org.kodein.di.android.closestDI
import org.kodein.di.instance
class SourcesActivity : AppCompatActivity(), DIAware {
class SourcesActivity :
AppCompatActivity(),
DIAware {
private lateinit var binding: ActivitySourcesBinding
override val di by closestDI()
@ -68,11 +70,12 @@ class SourcesActivity : AppCompatActivity(), DIAware {
binding.recyclerView.adapter = mAdapter
mAdapter.notifyDataSetChanged()
} else {
Toast.makeText(
this@SourcesActivity,
R.string.cant_get_sources,
Toast.LENGTH_SHORT,
).show()
Toast
.makeText(
this@SourcesActivity,
R.string.cant_get_sources,
Toast.LENGTH_SHORT,
).show()
}
CountingIdlingResourceSingleton.decrement()
}
@ -81,4 +84,4 @@ class SourcesActivity : AppCompatActivity(), DIAware {
startActivity(Intent(this@SourcesActivity, UpsertSourceActivity::class.java))
}
}
}
}

View File

@ -21,7 +21,9 @@ import org.kodein.di.DIAware
import org.kodein.di.android.closestDI
import org.kodein.di.instance
class UpsertSourceActivity : AppCompatActivity(), DIAware {
class UpsertSourceActivity :
AppCompatActivity(),
DIAware {
private var existingSource: SelfossModel.SourceDetail? = null
private var mSpoutsValue: String? = null
@ -105,11 +107,12 @@ class UpsertSourceActivity : AppCompatActivity(), DIAware {
}
fun handleSpoutFailure(networkIssue: Boolean = false) {
Toast.makeText(
this@UpsertSourceActivity,
if (networkIssue) R.string.cant_get_spouts_no_network else R.string.cant_get_spouts,
Toast.LENGTH_SHORT,
).show()
Toast
.makeText(
this@UpsertSourceActivity,
if (networkIssue) R.string.cant_get_spouts_no_network else R.string.cant_get_spouts,
Toast.LENGTH_SHORT,
).show()
binding.progress.visibility = View.GONE
}
@ -192,11 +195,12 @@ class UpsertSourceActivity : AppCompatActivity(), DIAware {
if (successfullyAddedSource) {
finish()
} else {
Toast.makeText(
this@UpsertSourceActivity,
R.string.cant_create_source,
Toast.LENGTH_SHORT,
).show()
Toast
.makeText(
this@UpsertSourceActivity,
R.string.cant_create_source,
Toast.LENGTH_SHORT,
).show()
}
}
}

View File

@ -49,7 +49,10 @@ class ItemCardAdapter(
return ViewHolder(binding)
}
private fun handleClickListeners(holderBinding: CardItemBinding, position: Int) {
private fun handleClickListeners(
holderBinding: CardItemBinding,
position: Int,
) {
holderBinding.favButton.setOnClickListener {
val item = items[position]
if (item.starred) {
@ -96,12 +99,13 @@ class ItemCardAdapter(
binding.title.setLinkTextColor(c.resources.getColor(R.color.colorAccent))
binding.sourceTitleAndDate.text = try {
itm.sourceAuthorAndDate()
} catch (e: Exception) {
e.sendSilentlyWithAcraWithName("ItemCardAdapter parse date")
itm.sourceAuthorOnly()
}
binding.sourceTitleAndDate.text =
try {
itm.sourceAuthorAndDate()
} catch (e: Exception) {
e.sendSilentlyWithAcraWithName("ItemCardAdapter parse date")
itm.sourceAuthorOnly()
}
if (!appSettingsService.isFullHeightCardsEnabled()) {
binding.itemImage.maxHeight = imageMaxHeight
@ -125,5 +129,7 @@ class ItemCardAdapter(
}
}
inner class ViewHolder(val binding: CardItemBinding) : RecyclerView.ViewHolder(binding.root)
}
inner class ViewHolder(
val binding: CardItemBinding,
) : RecyclerView.ViewHolder(binding.root)
}

View File

@ -53,12 +53,13 @@ class ItemListAdapter(
binding.title.setLinkTextColor(c.resources.getColor(R.color.colorAccent))
binding.sourceTitleAndDate.text = try {
itm.sourceAuthorAndDate()
} catch (e: Exception) {
e.sendSilentlyWithAcraWithName("ItemListAdapter parse date")
itm.sourceAuthorOnly()
}
binding.sourceTitleAndDate.text =
try {
itm.sourceAuthorAndDate()
} catch (e: Exception) {
e.sendSilentlyWithAcraWithName("ItemListAdapter parse date")
itm.sourceAuthorOnly()
}
if (itm.getThumbnail(repository.baseUrl).isEmpty()) {
if (itm.getIcon(repository.baseUrl).isEmpty()) {
@ -72,5 +73,7 @@ class ItemListAdapter(
}
}
inner class ViewHolder(val binding: ListItemBinding) : RecyclerView.ViewHolder(binding.root)
}
inner class ViewHolder(
val binding: ListItemBinding,
) : RecyclerView.ViewHolder(binding.root)
}

View File

@ -18,7 +18,9 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.kodein.di.DIAware
abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapter<VH>(), DIAware {
abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> :
RecyclerView.Adapter<VH>(),
DIAware {
abstract val items: ArrayList<SelfossModel.Item>
abstract val repository: Repository
abstract val binding: ViewBinding
@ -45,8 +47,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
app.findViewById(R.id.coordLayout),
R.string.marked_as_read,
Snackbar.LENGTH_LONG,
)
.setAction(R.string.undo_string) {
).setAction(R.string.undo_string) {
unreadItemAtIndex(item, position, false)
}
@ -66,8 +67,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
app.findViewById(R.id.coordLayout),
R.string.marked_as_unread,
Snackbar.LENGTH_LONG,
)
.setAction(R.string.undo_string) {
).setAction(R.string.undo_string) {
readItemAtIndex(item, position, false)
}
@ -77,7 +77,10 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
s.show()
}
protected fun handleLinkOpening(holderBinding: ViewBinding, position: Int) {
protected fun handleLinkOpening(
holderBinding: ViewBinding,
position: Int,
) {
holderBinding.root.setOnClickListener {
repository.setReaderItems(items)
c.openItemUrl(

View File

@ -29,7 +29,8 @@ import org.kodein.di.instance
class SourcesListAdapter(
private val app: Activity,
private val items: ArrayList<SelfossModel.SourceDetail>,
) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>(), DIAware {
) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>(),
DIAware {
private val c: Context = app.baseContext
private lateinit var binding: SourceListItemBinding
@ -61,11 +62,12 @@ class SourcesListAdapter(
notifyItemRemoved(position)
notifyItemRangeChanged(position, itemCount)
} else {
Toast.makeText(
app,
R.string.can_delete_source,
Toast.LENGTH_SHORT,
).show()
Toast
.makeText(
app,
R.string.can_delete_source,
Toast.LENGTH_SHORT,
).show()
}
}
}
@ -99,5 +101,7 @@ class SourcesListAdapter(
override fun getItemCount(): Int = items.size
inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView)
inner class ViewHolder(
val mView: ConstraintLayout,
) : RecyclerView.ViewHolder(mView)
}

View File

@ -23,11 +23,13 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.kodein.di.DIAware
import org.kodein.di.instance
import java.util.*
import java.util.Timer
import kotlin.concurrent.schedule
class LoadingWorker(val context: Context, params: WorkerParameters) :
Worker(context, params),
class LoadingWorker(
val context: Context,
params: WorkerParameters,
) : Worker(context, params),
DIAware {
override val di by lazy { (applicationContext as MyApp).di }
private val repository: Repository by instance()
@ -40,12 +42,13 @@ class LoadingWorker(val context: Context, params: WorkerParameters) :
applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notification =
NotificationCompat.Builder(applicationContext, AppSettingsService.syncChannelId)
NotificationCompat
.Builder(applicationContext, AppSettingsService.SYNC_CHANNEL_ID)
.setContentTitle(context.getString(R.string.loading_notification_title))
.setContentText(context.getString(R.string.loading_notification_text))
.setOngoing(true)
.setPriority(PRIORITY_LOW)
.setChannelId(AppSettingsService.syncChannelId)
.setChannelId(AppSettingsService.SYNC_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_stat_cloud_download_black_24dp)
notificationManager.notify(1, notification.build())
@ -87,19 +90,18 @@ class LoadingWorker(val context: Context, params: WorkerParameters) :
PendingIntent.getActivity(context, 0, intent, pflags)
val newItemsNotification =
NotificationCompat.Builder(
applicationContext,
AppSettingsService.newItemsChannelId,
)
.setContentTitle(context.getString(R.string.new_items_notification_title))
NotificationCompat
.Builder(
applicationContext,
AppSettingsService.NEW_ITEMS_CHANNEL,
).setContentTitle(context.getString(R.string.new_items_notification_title))
.setContentText(
context.getString(
R.string.new_items_notification_text,
newSize,
),
)
.setPriority(PRIORITY_DEFAULT)
.setChannelId(AppSettingsService.newItemsChannelId)
).setPriority(PRIORITY_DEFAULT)
.setChannelId(AppSettingsService.NEW_ITEMS_CHANNEL)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.setSmallIcon(R.drawable.ic_tab_fiber_new_black_24dp)

View File

@ -66,7 +66,9 @@ import java.util.concurrent.ExecutionException
private const val IMAGE_JPG = "image/jpg"
class ArticleFragment : Fragment(), DIAware {
class ArticleFragment :
Fragment(),
DIAware {
private var fontSize: Int = 16
private lateinit var item: SelfossModel.Item
private lateinit var url: String
@ -115,12 +117,13 @@ class ArticleFragment : Fragment(), DIAware {
contentText = item.content
contentTitle = item.title.getHtmlDecoded()
contentImage = item.getThumbnail(repository.baseUrl)
contentSource = try {
item.sourceAuthorAndDate()
} catch (e: Exception) {
e.sendSilentlyWithAcraWithName("Article Fragment parse date")
item.sourceAuthorOnly()
}
contentSource =
try {
item.sourceAuthorAndDate()
} catch (e: Exception) {
e.sendSilentlyWithAcraWithName("Article Fragment parse date")
item.sourceAuthorOnly()
}
allImages = item.getImages()
fontSize = appSettingsService.getFontSize()
@ -166,7 +169,8 @@ class ArticleFragment : Fragment(), DIAware {
} catch (e: InflateException) {
e.sendSilentlyWithAcraWithName("webview not available")
try {
AlertDialog.Builder(requireContext())
AlertDialog
.Builder(requireContext())
.setMessage(requireContext().getString(R.string.webview_dialog_issue_message))
.setTitle(requireContext().getString(R.string.webview_dialog_issue_title))
.setPositiveButton(
@ -174,8 +178,7 @@ class ArticleFragment : Fragment(), DIAware {
) { _, _ ->
appSettingsService.disableArticleViewer()
requireActivity().finish()
}
.create()
}.create()
.show()
} catch (e: IllegalStateException) {
e.sendSilentlyWithAcraWithName("Context required is null")
@ -234,21 +237,23 @@ class ArticleFragment : Fragment(), DIAware {
repository.markAsRead(this@ArticleFragment.item)
}
this@ArticleFragment.item.unread = false
Toast.makeText(
requireContext(),
R.string.marked_as_read,
Toast.LENGTH_LONG,
).show()
Toast
.makeText(
requireContext(),
R.string.marked_as_read,
Toast.LENGTH_LONG,
).show()
} else {
CoroutineScope(Dispatchers.IO).launch {
repository.unmarkAsRead(this@ArticleFragment.item)
}
this@ArticleFragment.item.unread = true
Toast.makeText(
context,
R.string.marked_as_unread,
Toast.LENGTH_LONG,
).show()
Toast
.makeText(
context,
R.string.marked_as_unread,
Toast.LENGTH_LONG,
).show()
}
} catch (e: IllegalStateException) {
e.sendSilentlyWithAcraWithName("Context required is null")
@ -321,8 +326,7 @@ class ArticleFragment : Fragment(), DIAware {
.asBitmap()
.load(
lead_image_url,
)
.apply(RequestOptions.fitCenterTransform())
).apply(RequestOptions.fitCenterTransform())
.into(binding.imageView)
} else {
binding.imageView.visibility = View.GONE
@ -336,14 +340,16 @@ class ArticleFragment : Fragment(), DIAware {
override fun shouldOverrideUrlLoading(
view: WebView?,
url: String,
): Boolean {
return if (context != null && url.isUrlValid() && binding.webcontent.hitTestResult.type != WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
): Boolean =
if (context != null &&
url.isUrlValid() &&
binding.webcontent.hitTestResult.type != WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE
) {
requireContext().openUrlInBrowser(url)
true
} else {
false
}
}
@Deprecated("Deprecated in Java")
override fun shouldInterceptRequest(
@ -352,12 +358,18 @@ class ArticleFragment : Fragment(), DIAware {
): WebResourceResponse? {
val glideOptions = RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL)
if (url.lowercase(Locale.US).contains(".jpg") ||
url.lowercase(Locale.US)
url
.lowercase(Locale.US)
.contains(".jpeg")
) {
try {
val image =
Glide.with(view).asBitmap().apply(glideOptions).load(url).submit()
Glide
.with(view)
.asBitmap()
.apply(glideOptions)
.load(url)
.submit()
.get()
return WebResourceResponse(
IMAGE_JPG,
@ -370,7 +382,12 @@ class ArticleFragment : Fragment(), DIAware {
} else if (url.lowercase(Locale.US).contains(".png")) {
try {
val image =
Glide.with(view).asBitmap().apply(glideOptions).load(url).submit()
Glide
.with(view)
.asBitmap()
.apply(glideOptions)
.load(url)
.submit()
.get()
return WebResourceResponse(
IMAGE_JPG,
@ -383,7 +400,12 @@ class ArticleFragment : Fragment(), DIAware {
} else if (url.lowercase(Locale.US).contains(".webp")) {
try {
val image =
Glide.with(view).asBitmap().apply(glideOptions).load(url).submit()
Glide
.with(view)
.asBitmap()
.apply(glideOptions)
.load(url)
.submit()
.get()
return WebResourceResponse(
IMAGE_JPG,
@ -422,7 +444,6 @@ class ArticleFragment : Fragment(), DIAware {
context.theme.resolveAttribute(R.attr.colorOnSurface, colorOnSurface, true)
context.theme.resolveAttribute(R.attr.colorSurface, colorSurface, true)
} catch (e: IllegalStateException) {
e.sendSilentlyWithAcraWithName("Context issue when setting attributes, but context wasn't null before")
}
@ -450,15 +471,13 @@ class ArticleFragment : Fragment(), DIAware {
GestureDetector(
activity,
object : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapUp(e: MotionEvent): Boolean {
return performClick()
}
override fun onSingleTapUp(e: MotionEvent): Boolean = performClick()
},
)
binding.webcontent.setOnTouchListener { _, event ->
gestureDetector.onTouchEvent(
event
event,
)
}
@ -597,10 +616,11 @@ class ArticleFragment : Fragment(), DIAware {
}
fun performClick(): Boolean {
if (allImages != null && (
binding.webcontent.hitTestResult.type == WebView.HitTestResult.IMAGE_TYPE ||
binding.webcontent.hitTestResult.type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE
)
if (allImages != null &&
(
binding.webcontent.hitTestResult.type == WebView.HitTestResult.IMAGE_TYPE ||
binding.webcontent.hitTestResult.type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE
)
) {
val position: Int = allImages.indexOf(binding.webcontent.hitTestResult.extra)
@ -612,4 +632,4 @@ class ArticleFragment : Fragment(), DIAware {
}
return false
}
}
}

View File

@ -33,7 +33,9 @@ import org.kodein.di.DIAware
import org.kodein.di.android.x.closestDI
import org.kodein.di.instance
class FilterSheetFragment : BottomSheetDialogFragment(), DIAware {
class FilterSheetFragment :
BottomSheetDialogFragment(),
DIAware {
private lateinit var binding: FilterFragmentBinding
override val di: DI by closestDI()
private val repository: Repository by instance()
@ -80,7 +82,8 @@ class FilterSheetFragment : BottomSheetDialogFragment(), DIAware {
val c = Chip(context)
c.ellipsize = TextUtils.TruncateAt.END
Glide.with(context)
Glide
.with(context)
.load(source.getIcon(repository.baseUrl))
.into(
object : ViewTarget<Chip?, Drawable?>(c) {
@ -190,4 +193,4 @@ class FilterSheetFragment : BottomSheetDialogFragment(), DIAware {
companion object {
const val TAG = "FilterModalBottomSheet"
}
}
}

View File

@ -14,7 +14,7 @@ class ImageFragment : Fragment() {
private lateinit var imageUrl: String
private val glideOptions = RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL)
private var _binding: FragmentImageBinding? = null
private val binding get() = _binding
val binding get() = _binding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -31,7 +31,8 @@ class ImageFragment : Fragment() {
val view = binding?.root
binding!!.photoView.visibility = View.VISIBLE
Glide.with(requireActivity())
Glide
.with(requireActivity())
.asBitmap()
.apply(glideOptions)
.load(imageUrl)

View File

@ -17,9 +17,12 @@ fun SelfossModel.Item.preloadImages(context: Context): Boolean {
try {
for (url in imageUrls) {
if (URLUtil.isValidUrl(url)) {
Glide.with(context).asBitmap()
Glide
.with(context)
.asBitmap()
.apply(glideOptions)
.load(url).submit()
.load(url)
.submit()
}
}
} catch (e: Error) {
@ -40,4 +43,4 @@ fun String.toTextDrawableString(): String {
}
}
return textDrawable.toString()
}
}

View File

@ -64,15 +64,14 @@ class SettingsActivity :
outState.putCharSequence(TITLE_TAG, title)
}
override fun onSupportNavigateUp(): Boolean {
return if (supportFragmentManager.popBackStackImmediate()) {
override fun onSupportNavigateUp(): Boolean =
if (supportFragmentManager.popBackStackImmediate()) {
supportActionBar?.title = getText(R.string.title_activity_settings)
false
} else {
super.onBackPressed()
true
}
}
override fun onPreferenceStartFragment(
caller: PreferenceFragmentCompat,
@ -81,15 +80,17 @@ class SettingsActivity :
// Instantiate the new Fragment
val args = pref.extras
val fragment =
supportFragmentManager.fragmentFactory.instantiate(
classLoader,
pref.fragment.toString(),
).apply {
arguments = args
setTargetFragment(caller, 0)
}
supportFragmentManager.fragmentFactory
.instantiate(
classLoader,
pref.fragment.toString(),
).apply {
arguments = args
setTargetFragment(caller, 0)
}
// Replace the existing Fragment with the new Fragment
supportFragmentManager.beginTransaction()
supportFragmentManager
.beginTransaction()
.replace(R.id.settings, fragment)
.addToBackStack(null)
.commit()
@ -108,7 +109,7 @@ class SettingsActivity :
preferenceManager.findPreference<Preference>(CURRENT_THEME)?.onPreferenceChangeListener =
Preference.OnPreferenceChangeListener { _, newValue ->
AppCompatDelegate.setDefaultNightMode(
newValue.toString().toInt()
newValue.toString().toInt(),
) // ListPreference Only takes string-arrays ¯\_(ツ)_/¯
true
}
@ -144,11 +145,12 @@ class SettingsActivity :
val input: Int = (dest.toString() + source.toString()).toInt()
if (input in 1..200) return@InputFilter null
} catch (nfe: NumberFormatException) {
Toast.makeText(
activity,
R.string.items_number_should_be_number,
Toast.LENGTH_LONG
).show()
Toast
.makeText(
activity,
R.string.items_number_should_be_number,
Toast.LENGTH_LONG,
).show()
}
""
},
@ -234,19 +236,19 @@ class SettingsActivity :
preferenceManager.findPreference<Preference>("trackerLink")?.onPreferenceClickListener =
Preference.OnPreferenceClickListener {
openUrl(AppSettingsService.trackerUrl)
openUrl(AppSettingsService.BUG_URL)
true
}
preferenceManager.findPreference<Preference>("sourceLink")?.onPreferenceClickListener =
Preference.OnPreferenceClickListener {
openUrl(AppSettingsService.sourceUrl)
openUrl(AppSettingsService.SOURCE_URL)
false
}
preferenceManager.findPreference<Preference>("translation")?.onPreferenceClickListener =
Preference.OnPreferenceClickListener {
openUrl(AppSettingsService.translationUrl)
openUrl(AppSettingsService.TRANSLATION_URL)
false
}
}
@ -260,4 +262,4 @@ class SettingsActivity :
setPreferencesFromResource(R.xml.pref_experimental, rootKey)
}
}
}
}

View File

@ -3,7 +3,6 @@ package bou.amine.apps.readerforselfossv2.android.testing
import androidx.test.espresso.idling.CountingIdlingResource
object CountingIdlingResourceSingleton {
private const val RESOURCE = "GLOBAL"
@JvmField
@ -18,4 +17,4 @@ object CountingIdlingResourceSingleton {
countingIdlingResource.decrement()
}
}
}
}

View File

@ -2,7 +2,6 @@ package bou.amine.apps.readerforselfossv2.android.testing
import android.os.Build
class TestingHelper {
fun isUnitTest(): Boolean {
var device = Build.DEVICE
@ -16,4 +15,4 @@ class TestingHelper {
}
return device == "robolectric" && product == "robolectric"
}
}
}

View File

@ -16,9 +16,10 @@ fun Context.shareLink(
sendIntent.putExtra(Intent.EXTRA_SUBJECT, itemTitle)
sendIntent.type = "text/plain"
startActivity(
Intent.createChooser(
sendIntent,
getString(R.string.share),
).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
Intent
.createChooser(
sendIntent,
getString(R.string.share),
).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
)
}

View File

@ -59,7 +59,5 @@ class CircleImageView
textView.text = text.toTextDrawableString()
}
private fun colorFromIdentifier(key: String): Int {
return colorScheme[abs(key.hashCode()) % colorScheme.size]
}
private fun colorFromIdentifier(key: String): Int = colorScheme[abs(key.hashCode()) % colorScheme.size]
}

View File

@ -18,7 +18,6 @@ import bou.amine.apps.readerforselfossv2.model.SelfossModel
import bou.amine.apps.readerforselfossv2.utils.toStringUriWithHttp
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
fun Context.openItemUrl(
currentItem: Int,
linkDecoded: String,
@ -26,11 +25,12 @@ fun Context.openItemUrl(
app: Activity,
) {
if (!linkDecoded.isUrlValid()) {
Toast.makeText(
this,
this.getString(R.string.cant_open_invalid_url),
Toast.LENGTH_LONG,
).show()
Toast
.makeText(
this,
this.getString(R.string.cant_open_invalid_url),
Toast.LENGTH_LONG,
).show()
} else {
if (articleViewer) {
val intent = Intent(this, ReaderActivity::class.java)
@ -42,8 +42,7 @@ fun Context.openItemUrl(
}
}
fun String.isUrlValid(): Boolean =
this.toHttpUrlOrNull() != null && Patterns.WEB_URL.matcher(this).matches()
fun String.isUrlValid(): Boolean = this.toHttpUrlOrNull() != null && Patterns.WEB_URL.matcher(this).matches()
fun String.isBaseUrlInvalid(): Boolean {
val baseUrl = this.toHttpUrlOrNull()
@ -61,7 +60,6 @@ fun Context.openItemUrlInBrowserAsNewTask(i: SelfossModel.Item) {
}
fun Context.openUrlInBrowserAsNewTask(url: String) {
val intent = Intent(Intent.ACTION_VIEW)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
intent.data = Uri.parse(url)
@ -80,7 +78,6 @@ fun Context.mayBeStartActivity(intent: Intent) {
} catch (e: ActivityNotFoundException) {
Toast.makeText(this, getString(R.string.no_browser), Toast.LENGTH_SHORT).show()
}
}
class LinkOnTouchListener : View.OnTouchListener {
@ -122,4 +119,4 @@ class LinkOnTouchListener : View.OnTouchListener {
}
return ret
}
}
}

View File

@ -6,4 +6,4 @@ import org.acra.ktx.sendSilentlyWithAcra
fun Throwable.sendSilentlyWithAcraWithName(name: String) {
ACRA.errorReporter.putCustomData("error_source", name)
this.sendSilentlyWithAcra()
}
}

View File

@ -8,22 +8,19 @@ import org.acra.config.CoreConfiguration
import org.acra.config.ReportingAdministrator
import org.acra.data.CrashReportData
@AutoService(ReportingAdministrator::class)
class AcraReportingAdministrator : ReportingAdministrator {
override fun shouldStartCollecting(
context: Context,
config: CoreConfiguration,
reportBuilder: ReportBuilder
): Boolean {
return reportBuilder.exception !is DeadSystemException && (reportBuilder.exception != null && reportBuilder.exception!!::class.simpleName != "CannotDeliverBroadcastException")
}
reportBuilder: ReportBuilder,
): Boolean =
reportBuilder.exception !is DeadSystemException &&
(reportBuilder.exception != null && reportBuilder.exception!!::class.simpleName != "CannotDeliverBroadcastException")
override fun shouldSendReport(
context: Context,
config: CoreConfiguration,
crashReportData: CrashReportData
): Boolean {
return crashReportData.get("BRAND") != "redroid"
}
}
crashReportData: CrashReportData,
): Boolean = crashReportData.get("BRAND") != "redroid"
}

View File

@ -13,7 +13,8 @@ import java.io.InputStream
fun Context.bitmapCenterCrop(
url: String,
iv: ImageView,
) = Glide.with(this)
) = Glide
.with(this)
.asBitmap()
.load(url)
.apply(RequestOptions.centerCropTransform())
@ -25,7 +26,8 @@ fun Context.circularDrawable(
) {
view.textView.text = ""
Glide.with(this)
Glide
.with(this)
.load(url)
.into(view.imageView)
}

View File

@ -7,7 +7,9 @@ import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch
class AppViewModel(private val repository: Repository) : ViewModel() {
class AppViewModel(
private val repository: Repository,
) : ViewModel() {
private val _networkAvailableProvider = MutableSharedFlow<Boolean>()
val networkAvailableProvider = _networkAvailableProvider.asSharedFlow()
private var wasConnected = true
@ -19,11 +21,10 @@ class AppViewModel(private val repository: Repository) : ViewModel() {
if (isConnected && !wasConnected && repository.connectionMonitored) {
_networkAvailableProvider.emit(true)
wasConnected = true
} else if (!isConnected && wasConnected && repository.connectionMonitored)
{
_networkAvailableProvider.emit(false)
wasConnected = false
}
} else if (!isConnected && wasConnected && repository.connectionMonitored) {
_networkAvailableProvider.emit(false)
wasConnected = false
}
}
}
}

View File

@ -11,13 +11,17 @@ fun dialogMessage(): String {
return latestDialog.findViewById<TextView>(android.R.id.message)?.text.toString()
}
fun Menu.assertClickable(@IdRes id: Int) {
fun Menu.assertClickable(
@IdRes id: Int,
) {
this.assertVisible(id)
val item = this.findItem(id)
assertTrue(item.isEnabled)
}
fun Menu.assertVisible(@IdRes id: Int) {
fun Menu.assertVisible(
@IdRes id: Int,
) {
val item = this.findItem(id)
assertTrue(item.isVisible)
}
}

View File

@ -11,10 +11,8 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.Robolectric
@RunWith(RobotElectriqueRunnerclass::class)
@RunWith(RobotElectriqueRunner::class)
class LoginActivityTest {
@Test
fun login_shouldDisplay() {
Robolectric.buildActivity(LoginActivity::class.java).use { controller ->
@ -74,4 +72,4 @@ class LoginActivityTest {
assertEquals(expectedIntent.component, actual.component)
}
}*/
}
}

View File

@ -3,10 +3,8 @@ package bou.amine.apps.readerforselfossv2.android.tests.robolectric
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
class RobotElectriqueRunnerclass(testClass: Class<*>?) :
RobolectricTestRunner(testClass) {
override fun buildGlobalConfig(): Config {
return Config.Builder().setSdk(25, 30, 33).build()
}
}
class RobotElectriqueRunner(
testClass: Class<*>?,
) : RobolectricTestRunner(testClass) {
override fun buildGlobalConfig(): Config = Config.Builder().setSdk(25, 30, 33).build()
}

View File

@ -42,14 +42,14 @@ private const val FEED_URL = "https://test.com/feed"
private const val TAGS = "Test, New"
private val NUMBER_ARTICLES = 100
private val NUMBER_UNREAD = 50
private val NUMBER_STARRED = 20
class RepositoryTest {
private val db = mockk<ReaderForSelfossDB>(relaxed = true)
private val appSettingsService = mockk<AppSettingsService>()
private val api = mockk<SelfossApi>()
private val NUMBER_ARTICLES = 100
private val NUMBER_UNREAD = 50
private val NUMBER_STARRED = 20
private lateinit var repository: Repository
private fun initializeRepository(
@ -75,19 +75,20 @@ class RepositoryTest {
every { appSettingsService.isUpdateSourcesEnabled() } returns false
coEvery { api.apiInformation() } returns
StatusAndData(
success = true,
data = SelfossModel.ApiInformation(
StatusAndData(
success = true,
data =
SelfossModel.ApiInformation(
"2.19-ba1e8e3",
"4.0.0",
SelfossModel.ApiConfiguration(false, true)
SelfossModel.ApiConfiguration(false, true),
),
)
)
coEvery { api.stats() } returns
StatusAndData(
success = true,
data = SelfossModel.Stats(NUMBER_ARTICLES, NUMBER_UNREAD, NUMBER_STARRED),
)
StatusAndData(
success = true,
data = SelfossModel.Stats(NUMBER_ARTICLES, NUMBER_UNREAD, NUMBER_STARRED),
)
every { db.itemsQueries.deleteItemsWhereSource(any()) } returns Unit
every { db.itemsQueries.items().executeAsList() } returns generateTestDBItems()
@ -117,7 +118,7 @@ class RepositoryTest {
fun get_api_4_date_with_api_1_version_stored() {
every { appSettingsService.getApiVersion() } returns 1
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
StatusAndData(success = true, data = generateTestApiItem())
StatusAndData(success = true, data = generateTestApiItem())
every { appSettingsService.updateApiVersion(any()) } returns Unit
initializeRepository()
@ -133,14 +134,15 @@ class RepositoryTest {
fun get_public_access() {
every { appSettingsService.updatePublicAccess(any()) } returns Unit
coEvery { api.apiInformation() } returns
StatusAndData(
success = true,
data = SelfossModel.ApiInformation(
StatusAndData(
success = true,
data =
SelfossModel.ApiInformation(
"2.19-ba1e8e3",
"4.0.0",
SelfossModel.ApiConfiguration(true, true)
SelfossModel.ApiConfiguration(true, true),
),
)
)
every { appSettingsService.getUserName() } returns ""
initializeRepository()
@ -153,14 +155,15 @@ class RepositoryTest {
fun get_public_access_username_not_empty() {
every { appSettingsService.updatePublicAccess(any()) } returns Unit
coEvery { api.apiInformation() } returns
StatusAndData(
success = true,
data = SelfossModel.ApiInformation(
StatusAndData(
success = true,
data =
SelfossModel.ApiInformation(
"2.19-ba1e8e3",
"4.0.0",
SelfossModel.ApiConfiguration(true, true)
SelfossModel.ApiConfiguration(true, true),
),
)
)
every { appSettingsService.getUserName() } returns "username"
initializeRepository()
@ -173,14 +176,15 @@ class RepositoryTest {
fun get_public_access_no_auth() {
every { appSettingsService.updatePublicAccess(any()) } returns Unit
coEvery { api.apiInformation() } returns
StatusAndData(
success = true,
data = SelfossModel.ApiInformation(
StatusAndData(
success = true,
data =
SelfossModel.ApiInformation(
"2.19-ba1e8e3",
"4.0.0",
SelfossModel.ApiConfiguration(true, false)
SelfossModel.ApiConfiguration(true, false),
),
)
)
every { appSettingsService.getUserName() } returns ""
initializeRepository()
@ -193,14 +197,15 @@ class RepositoryTest {
fun get_public_access_disabled() {
every { appSettingsService.updatePublicAccess(any()) } returns Unit
coEvery { api.apiInformation() } returns
StatusAndData(
success = true,
data = SelfossModel.ApiInformation(
StatusAndData(
success = true,
data =
SelfossModel.ApiInformation(
"2.19-ba1e8e3",
"4.0.0",
SelfossModel.ApiConfiguration(false, true)
SelfossModel.ApiConfiguration(false, true),
),
)
)
every { appSettingsService.getUserName() } returns ""
initializeRepository()
@ -216,10 +221,10 @@ class RepositoryTest {
val itemParameters = FakeItemParameters()
itemParameters.datetime = "2021-04-23 11:45:32"
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
StatusAndData(
success = true,
data = generateTestApiItem(itemParameters),
)
StatusAndData(
success = true,
data = generateTestApiItem(itemParameters),
)
initializeRepository()
runBlocking {
@ -232,7 +237,7 @@ class RepositoryTest {
@Test
fun get_newer_items() {
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
StatusAndData(success = true, data = generateTestApiItem())
StatusAndData(success = true, data = generateTestApiItem())
initializeRepository()
runBlocking {
@ -247,7 +252,7 @@ class RepositoryTest {
@Test
fun get_all_newer_items() {
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
StatusAndData(success = true, data = generateTestApiItem())
StatusAndData(success = true, data = generateTestApiItem())
initializeRepository()
repository.displayedItems = ItemType.ALL
@ -263,7 +268,7 @@ class RepositoryTest {
@Test
fun get_newer_starred_items() {
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
StatusAndData(success = true, data = generateTestApiItem())
StatusAndData(success = true, data = generateTestApiItem())
initializeRepository()
repository.displayedItems = ItemType.STARRED
@ -302,8 +307,8 @@ class RepositoryTest {
coEvery { db.itemsQueries.items().executeAsList() } returns generateTestDBItems(
itemParameter1,
) +
generateTestDBItems(itemParameter2) +
generateTestDBItems(itemParameter3)
generateTestDBItems(itemParameter2) +
generateTestDBItems(itemParameter3)
every { appSettingsService.isItemCachingEnabled() } returns true
@ -330,8 +335,8 @@ class RepositoryTest {
coEvery { db.itemsQueries.items().executeAsList() } returns generateTestDBItems(
itemParameter1,
) +
generateTestDBItems(itemParameter2) +
generateTestDBItems(itemParameter3)
generateTestDBItems(itemParameter2) +
generateTestDBItems(itemParameter3)
every { appSettingsService.isItemCachingEnabled() } returns true
@ -360,7 +365,7 @@ class RepositoryTest {
@Test
fun get_older_items() {
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
StatusAndData(success = true, data = generateTestApiItem())
StatusAndData(success = true, data = generateTestApiItem())
initializeRepository()
repository.items = ArrayList(generateTestApiItem())
@ -376,7 +381,7 @@ class RepositoryTest {
@Test
fun get_all_older_items() {
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
StatusAndData(success = true, data = generateTestApiItem())
StatusAndData(success = true, data = generateTestApiItem())
initializeRepository()
repository.items = ArrayList(generateTestApiItem())
@ -393,7 +398,7 @@ class RepositoryTest {
@Test
fun get_older_starred_items() {
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
StatusAndData(success = true, data = generateTestApiItem())
StatusAndData(success = true, data = generateTestApiItem())
initializeRepository()
repository.displayedItems = ItemType.STARRED
@ -833,7 +838,7 @@ class RepositoryTest {
@Test
fun create_source() {
coEvery { api.createSourceForVersion(any(), any(), any(), any()) } returns
SuccessResponse(true)
SuccessResponse(true)
initializeRepository()
var response: Boolean
@ -861,7 +866,7 @@ class RepositoryTest {
@Test
fun create_source_but_response_fails() {
coEvery { api.createSourceForVersion(any(), any(), any(), any()) } returns
SuccessResponse(false)
SuccessResponse(false)
initializeRepository()
var response: Boolean
@ -889,7 +894,7 @@ class RepositoryTest {
@Test
fun create_source_without_connection() {
coEvery { api.createSourceForVersion(any(), any(), any(), any()) } returns
SuccessResponse(true)
SuccessResponse(true)
initializeRepository(MutableStateFlow(false))
var response: Boolean
@ -962,10 +967,10 @@ class RepositoryTest {
@Test
fun update_remote() {
coEvery { api.update() } returns
StatusAndData(
success = true,
data = "finished",
)
StatusAndData(
success = true,
data = "finished",
)
initializeRepository()
var response: Boolean
@ -980,10 +985,10 @@ class RepositoryTest {
@Test
fun update_remote_but_response_fails() {
coEvery { api.update() } returns
StatusAndData(
success = false,
data = "unallowed access",
)
StatusAndData(
success = false,
data = "unallowed access",
)
initializeRepository()
var response: Boolean
@ -998,10 +1003,10 @@ class RepositoryTest {
@Test
fun update_remote_with_unallowed_access() {
coEvery { api.update() } returns
StatusAndData(
success = true,
data = "unallowed access",
)
StatusAndData(
success = true,
data = "unallowed access",
)
initializeRepository()
var response: Boolean
@ -1016,10 +1021,10 @@ class RepositoryTest {
@Test
fun update_remote_without_connection() {
coEvery { api.update() } returns
StatusAndData(
success = true,
data = "undocumented...",
)
StatusAndData(
success = true,
data = "undocumented...",
)
initializeRepository(MutableStateFlow(false))
var response: Boolean
@ -1109,11 +1114,11 @@ class RepositoryTest {
any(),
)
} returnsMany
listOf(
StatusAndData(success = true, data = generateTestApiItem(itemParameter1)),
StatusAndData(success = true, data = generateTestApiItem(itemParameter2)),
StatusAndData(success = true, data = generateTestApiItem(itemParameter1)),
)
listOf(
StatusAndData(success = true, data = generateTestApiItem(itemParameter1)),
StatusAndData(success = true, data = generateTestApiItem(itemParameter2)),
StatusAndData(success = true, data = generateTestApiItem(itemParameter1)),
)
initializeRepository()
prepareSearch()
@ -1127,7 +1132,7 @@ class RepositoryTest {
@Test
fun cache_items_but_response_fails() {
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
StatusAndData(success = false, data = generateTestApiItem())
StatusAndData(success = false, data = generateTestApiItem())
initializeRepository()
prepareSearch()
@ -1141,7 +1146,7 @@ class RepositoryTest {
@Test
fun cache_items_without_connection() {
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
StatusAndData(success = false, data = generateTestApiItem())
StatusAndData(success = false, data = generateTestApiItem())
initializeRepository(MutableStateFlow(false))
prepareSearch()
@ -1168,4 +1173,4 @@ class RepositoryTest {
)
repository.searchFilter = "search"
}
}
}

View File

@ -3,8 +3,8 @@ package bou.amine.apps.readerforselfossv2.tests.repository
import bou.amine.apps.readerforselfossv2.dao.ITEM
import bou.amine.apps.readerforselfossv2.model.SelfossModel
fun generateTestDBItems(item: FakeItemParameters = FakeItemParameters()): List<ITEM> {
return listOf(
fun generateTestDBItems(item: FakeItemParameters = FakeItemParameters()): List<ITEM> =
listOf(
ITEM(
id = item.id,
datetime = item.datetime,
@ -20,10 +20,9 @@ fun generateTestDBItems(item: FakeItemParameters = FakeItemParameters()): List<I
author = item.author,
),
)
}
fun generateTestApiItem(item: FakeItemParameters = FakeItemParameters()): List<SelfossModel.Item> {
return listOf(
fun generateTestApiItem(item: FakeItemParameters = FakeItemParameters()): List<SelfossModel.Item> =
listOf(
SelfossModel.Item(
id = item.id.toInt(),
datetime = item.datetime,
@ -39,7 +38,6 @@ fun generateTestApiItem(item: FakeItemParameters = FakeItemParameters()): List<S
author = item.author,
),
)
}
class FakeItemParameters {
var id = "20"
@ -56,4 +54,4 @@ class FakeItemParameters {
var sourcetitle = "La Chimica e la Società"
var tags = "Chimica, Testing"
var author = "Someone important"
}
}