diff --git a/app/build.gradle b/app/build.gradle index 82df49e..fdf141f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -25,8 +25,8 @@ android { applicationId "apps.amine.bou.readerforselfoss" minSdkVersion 16 targetSdkVersion 25 - versionCode 1511 - versionName "1.5.1.1" + versionCode 1512 + versionName "1.5.1.2" // Enabling multidex support. multiDexEnabled true diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/AddSourceActivity.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/AddSourceActivity.kt index 428913e..e171811 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/AddSourceActivity.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/AddSourceActivity.kt @@ -6,14 +6,17 @@ import android.support.constraint.ConstraintLayout import android.support.v7.app.AppCompatActivity import android.view.View import android.widget.* + +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response + import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi import apps.amine.bou.readerforselfoss.api.selfoss.Spout import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse import apps.amine.bou.readerforselfoss.utils.Config import apps.amine.bou.readerforselfoss.utils.isUrlValid -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response + class AddSourceActivity : AppCompatActivity() { @@ -39,15 +42,15 @@ class AddSourceActivity : AppCompatActivity() { mustLoginToAddSource() } - - val intent = intent if (Intent.ACTION_SEND == intent.action && "text/plain" == intent.type) { mSourceUri.setText(intent.getStringExtra(Intent.EXTRA_TEXT)) mNameInput.setText(intent.getStringExtra(Intent.EXTRA_TITLE)) } - mSaveBtn.setOnClickListener { handleSaveSource(mTags, mNameInput.text.toString(), mSourceUri.text.toString(), api!!) } + mSaveBtn.setOnClickListener { + handleSaveSource(mTags, mNameInput.text.toString(), mSourceUri.text.toString(), api!!) + } val spoutsKV = HashMap() @@ -82,7 +85,11 @@ class AddSourceActivity : AppCompatActivity() { mProgress.visibility = View.GONE mForm.visibility = View.VISIBLE - val spinnerArrayAdapter = ArrayAdapter(this@AddSourceActivity, android.R.layout.simple_spinner_item, itemsStrings) + val spinnerArrayAdapter = + ArrayAdapter( + this@AddSourceActivity, + android.R.layout.simple_spinner_item, + itemsStrings) spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) mSpoutsSpinner.adapter = spinnerArrayAdapter @@ -115,7 +122,13 @@ class AddSourceActivity : AppCompatActivity() { if (title.isEmpty() || url.isEmpty() || mSpoutsValue == null || mSpoutsValue!!.isEmpty()) { Toast.makeText(this, R.string.form_not_complete, Toast.LENGTH_SHORT).show() } else { - api.createSource(title, url, mSpoutsValue!!, mTags.text.toString(), "").enqueue(object : Callback { + api.createSource( + title, + url, + mSpoutsValue!!, + mTags.text.toString(), + "" + ).enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { if (response.body() != null && response.body()!!.isSuccess) { finish() diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/HomeActivity.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/HomeActivity.kt index 6fa78db..e2fee6d 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/HomeActivity.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/HomeActivity.kt @@ -1,5 +1,7 @@ package apps.amine.bou.readerforselfoss +import java.lang.Exception + import android.app.Activity import android.content.Context import android.content.Intent @@ -19,16 +21,7 @@ import android.view.Menu import android.view.MenuItem import android.view.View import android.widget.Toast -import apps.amine.bou.readerforselfoss.adapters.ItemCardAdapter -import apps.amine.bou.readerforselfoss.adapters.ItemListAdapter -import apps.amine.bou.readerforselfoss.api.selfoss.* -import apps.amine.bou.readerforselfoss.settings.SettingsActivity -import apps.amine.bou.readerforselfoss.utils.Config -import apps.amine.bou.readerforselfoss.utils.checkAndDisplayStoreApk -import apps.amine.bou.readerforselfoss.utils.checkApkVersion -import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper -import apps.amine.bou.readerforselfoss.utils.drawer.CustomUrlPrimaryDrawerItem -import apps.amine.bou.readerforselfoss.utils.longHash + import com.anupcowkur.reservoir.Reservoir import com.anupcowkur.reservoir.ReservoirGetCallback import com.anupcowkur.reservoir.ReservoirPutCallback @@ -54,7 +47,19 @@ import com.roughike.bottombar.BottomBarTab import retrofit2.Call import retrofit2.Callback import retrofit2.Response -import java.lang.Exception + +import apps.amine.bou.readerforselfoss.adapters.ItemCardAdapter +import apps.amine.bou.readerforselfoss.adapters.ItemListAdapter +import apps.amine.bou.readerforselfoss.api.selfoss.* +import apps.amine.bou.readerforselfoss.settings.SettingsActivity +import apps.amine.bou.readerforselfoss.utils.Config +import apps.amine.bou.readerforselfoss.utils.checkAndDisplayStoreApk +import apps.amine.bou.readerforselfoss.utils.checkApkVersion +import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper +import apps.amine.bou.readerforselfoss.utils.drawer.CustomUrlPrimaryDrawerItem +import apps.amine.bou.readerforselfoss.utils.longHash + + class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { @@ -64,48 +69,136 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { private val DRAWER_ID_TAGS = 100101L private val DRAWER_ID_SOURCES = 100110L private val DRAWER_ID_FILTERS = 100111L - private var mRecyclerView: RecyclerView? = null - private var api: SelfossApi? = null - private var items: ArrayList = ArrayList() - private var mCustomTabActivityHelper: CustomTabActivityHelper? = null + private val UNREAD_SHOWN = 1 + private val READ_SHOWN = 2 + private val FAV_SHOWN = 3 + private var items: ArrayList = ArrayList() private var clickBehavior = false private var internalBrowser = false private var articleViewer = false private var shouldBeCardView = false private var displayUnreadCount = false private var displayAllCount = false - private var editor: SharedPreferences.Editor? = null - - private val UNREAD_SHOWN = 1 - private val READ_SHOWN = 2 - private val FAV_SHOWN = 3 - private var elementsShown: Int = 0 - private var mBottomBar: BottomBar? = null - private var mCoordinatorLayout: CoordinatorLayout? = null - private var mSwipeRefreshLayout: SwipeRefreshLayout? = null - private var sharedPref: SharedPreferences? = null - private var tabNew: BottomBarTab? = null - private var tabArchive: BottomBarTab? = null - private var tabStarred: BottomBarTab? = null - private var mFirebaseRemoteConfig: FirebaseRemoteConfig? = null private var fullHeightCards: Boolean = false - private var toolbar: Toolbar? = null - private var drawer: Drawer? = null + private var elementsShown: Int = 0 private var maybeTagFilter: Tag? = null private var maybeSourceFilter: Sources? = null private var maybeSearchFilter: String? = null + private lateinit var mRecyclerView: RecyclerView + private lateinit var mBottomBar: BottomBar + private lateinit var mCoordinatorLayout: CoordinatorLayout + private lateinit var mSwipeRefreshLayout: SwipeRefreshLayout + private lateinit var tabNew: BottomBarTab + private lateinit var tabArchive: BottomBarTab + private lateinit var tabStarred: BottomBarTab + private lateinit var toolbar: Toolbar + private lateinit var drawer: Drawer + private lateinit var api: SelfossApi + private lateinit var mCustomTabActivityHelper: CustomTabActivityHelper + private lateinit var editor: SharedPreferences.Editor + private lateinit var sharedPref: SharedPreferences + private lateinit var mFirebaseRemoteConfig: FirebaseRemoteConfig + + + data class DrawerData(val tags: List?, val sources: List?) - private fun handleSharedPrefs() { - clickBehavior = this.sharedPref!!.getBoolean("tab_on_tap", false) - internalBrowser = this.sharedPref!!.getBoolean("prefer_internal_browser", true) - articleViewer = this.sharedPref!!.getBoolean("prefer_article_viewer", true) - shouldBeCardView = this.sharedPref!!.getBoolean("card_view_active", false) - displayUnreadCount = this.sharedPref!!.getBoolean("display_unread_count", true) - displayAllCount = this.sharedPref!!.getBoolean("display_other_count", false) - fullHeightCards = this.sharedPref!!.getBoolean("full_height_cards", false) + + + override fun onStart() { + super.onStart() + mCustomTabActivityHelper.bindCustomTabsService(this) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_home) + + toolbar = findViewById(R.id.toolbar) as Toolbar + setSupportActionBar(toolbar) + + if (savedInstanceState == null) { + val promptView = findViewById(R.id.prompt_view) as DefaultLayoutPromptView + Amplify.getSharedInstance().promptIfReady(promptView) + } + + mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance() + mFirebaseRemoteConfig.setDefaults(R.xml.default_remote_config) + + mCustomTabActivityHelper = CustomTabActivityHelper() + + api = SelfossApi(this) + items = ArrayList() + + mBottomBar = findViewById(R.id.bottomBar) as BottomBar + + handleDrawer() + + // TODO: clean this hack + val listenerAlreadySet = booleanArrayOf(false) + mBottomBar.setOnTabSelectListener { tabId -> + if (listenerAlreadySet[0]) { + if (tabId == R.id.tab_new) { + getUnRead() + } else if (tabId == R.id.tab_archive) { + getRead() + } else if (tabId == R.id.tab_fav) { + getStarred() + } + getElementsAccordingToTab() + } else { + listenerAlreadySet[0] = true + } + } + + mCoordinatorLayout = findViewById(R.id.coordLayout) as CoordinatorLayout + mSwipeRefreshLayout = findViewById(R.id.swipeRefreshLayout) as SwipeRefreshLayout + mRecyclerView = findViewById(R.id.my_recycler_view) as RecyclerView + + reloadLayoutManager() + + mSwipeRefreshLayout.setColorSchemeResources( + R.color.refresh_progress_1, + R.color.refresh_progress_2, + R.color.refresh_progress_3) + mSwipeRefreshLayout.setOnRefreshListener { + handleDrawerItems() + getElementsAccordingToTab() + } + + val simpleItemTouchCallback = + object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) { + + override fun getSwipeDirs(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder?): Int = + if (elementsShown != UNREAD_SHOWN) 0 else super.getSwipeDirs(recyclerView, viewHolder) + + override fun onMove(recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder): Boolean = false + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, swipeDir: Int) { + try { + val i = items[viewHolder.adapterPosition] + val position = items.indexOf(i) + + if (shouldBeCardView) { + (mRecyclerView.adapter as ItemCardAdapter).removeItemAtIndex(position) + } else { + (mRecyclerView.adapter as ItemListAdapter).removeItemAtIndex(position) + } + tabNew.setBadgeCount(items.size - 1) + + } catch (e: IndexOutOfBoundsException) {} + + } + } + + ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(mRecyclerView) + + checkAndDisplayStoreApk(this@HomeActivity) + } override fun onResume() { @@ -119,75 +212,100 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { editor = settings.edit() if (BuildConfig.GITHUB_VERSION) { - checkApkVersion(settings, editor!!, this@HomeActivity, mFirebaseRemoteConfig!!) + checkApkVersion(settings, editor, this@HomeActivity, mFirebaseRemoteConfig) } handleSharedPrefs() - tabNew = mBottomBar!!.getTabWithId(R.id.tab_new) - tabArchive = mBottomBar!!.getTabWithId(R.id.tab_archive) - tabStarred = mBottomBar!!.getTabWithId(R.id.tab_fav) + tabNew = mBottomBar.getTabWithId(R.id.tab_new) + tabArchive = mBottomBar.getTabWithId(R.id.tab_archive) + tabStarred = mBottomBar.getTabWithId(R.id.tab_fav) getElementsAccordingToTab() } - fun handleDrawer() { + override fun onStop() { + super.onStop() + mCustomTabActivityHelper.unbindCustomTabsService(this) + } + + + private fun handleSharedPrefs() { + clickBehavior = sharedPref.getBoolean("tab_on_tap", false) + internalBrowser = sharedPref.getBoolean("prefer_internal_browser", true) + articleViewer = sharedPref.getBoolean("prefer_article_viewer", true) + shouldBeCardView = sharedPref.getBoolean("card_view_active", false) + displayUnreadCount = sharedPref.getBoolean("display_unread_count", true) + displayAllCount = sharedPref.getBoolean("display_other_count", false) + fullHeightCards = sharedPref.getBoolean("full_height_cards", false) + } + + private fun handleDrawer() { drawer = DrawerBuilder() .withActivity(this) .withRootView(R.id.drawer_layout) - .withToolbar(toolbar!!) + .withToolbar(toolbar) .withActionBarDrawerToggle(true) .withActionBarDrawerToggleAnimated(true) .withShowDrawerOnFirstLaunch(true) .withOnDrawerListener(object: Drawer.OnDrawerListener { - override fun onDrawerSlide(p0: View?, p1: Float) { - mBottomBar!!.alpha = (1 - p1) + override fun onDrawerSlide(v: View?, p1: Float) { + mBottomBar.alpha = (1 - p1) } - override fun onDrawerClosed(p0: View?) { - mBottomBar!!.shySettings.showBar() + override fun onDrawerClosed(v: View?) { + mBottomBar.shySettings.showBar() } - override fun onDrawerOpened(p0: View?) { - mBottomBar!!.shySettings.hideBar() + override fun onDrawerOpened(v: View?) { + mBottomBar.shySettings.hideBar() } }) .build() - drawer!!.addStickyFooterItem( + drawer.addStickyFooterItem( PrimaryDrawerItem() .withName(R.string.action_about) .withSelectable(false) .withIcon(R.drawable.ic_info_outline) .withOnDrawerItemClickListener { _, _, _ -> LibsBuilder() - .withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR) - .withAboutIconShown(true) - .withAboutVersionShown(true) - .start(this@HomeActivity) + .withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR) + .withAboutIconShown(true) + .withAboutVersionShown(true) + .start(this@HomeActivity) false }) - drawer!!.addStickyFooterItem( + drawer.addStickyFooterItem( PrimaryDrawerItem() .withName(R.string.title_activity_settings) .withIcon(R.drawable.ic_settings) .withOnDrawerItemClickListener { _, _, _ -> - startActivityForResult(Intent(this@HomeActivity, SettingsActivity::class.java), MENU_PREFERENCES) + startActivityForResult( + Intent( + this@HomeActivity, + SettingsActivity::class.java + ), + MENU_PREFERENCES + ) false } ) } - fun handleDrawerItems() { + private fun handleDrawerItems() { fun handleDrawerData(maybeDrawerData: DrawerData?, loadedFromCache: Boolean = false) { fun handleTags(maybeTags: List?) { if (maybeTags == null) { if (loadedFromCache) - drawer!!.addItem(SecondaryDrawerItem().withName(getString(R.string.drawer_error_loading_tags)).withSelectable(false)) + drawer.addItem( + SecondaryDrawerItem() + .withName(getString(R.string.drawer_error_loading_tags)) + .withSelectable(false)) } else { for (tag in maybeTags) { @@ -196,7 +314,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { gd.shape = GradientDrawable.RECTANGLE gd.setSize(30, 30) gd.cornerRadius = 30F - drawer!!.addItem( + drawer.addItem( PrimaryDrawerItem() .withName(tag.tag) .withIdentifier(longHash(tag.tag)) @@ -220,11 +338,14 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { fun handleSources(maybeSources: List?) { if (maybeSources == null) { if (loadedFromCache) - drawer!!.addItem(SecondaryDrawerItem().withName(getString(R.string.drawer_error_loading_sources)).withSelectable(false)) + drawer.addItem( + SecondaryDrawerItem() + .withName(getString(R.string.drawer_error_loading_sources)) + .withSelectable(false)) } else for (tag in maybeSources) - drawer!!.addItem( + drawer.addItem( CustomUrlPrimaryDrawerItem() .withName(tag.title) .withIdentifier(tag.id.toLong()) @@ -238,9 +359,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { } - drawer!!.removeAllItems() + drawer.removeAllItems() if (maybeDrawerData != null) { - drawer!!.addItem( + drawer.addItem( SecondaryDrawerItem() .withName(getString(R.string.drawer_item_filters)) .withSelectable(false) @@ -253,10 +374,14 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { false } ) - drawer!!.addItem(DividerDrawerItem()) - drawer!!.addItem(SecondaryDrawerItem().withName(getString(R.string.drawer_item_tags)).withIdentifier(DRAWER_ID_TAGS).withSelectable(false)) + drawer.addItem(DividerDrawerItem()) + drawer.addItem( + SecondaryDrawerItem() + .withName(getString(R.string.drawer_item_tags)) + .withIdentifier(DRAWER_ID_TAGS) + .withSelectable(false)) handleTags(maybeDrawerData.tags) - drawer!!.addItem( + drawer.addItem( SecondaryDrawerItem() .withName(getString(R.string.drawer_item_sources)) .withIdentifier(DRAWER_ID_TAGS) @@ -280,8 +405,16 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { }) } else { if (!loadedFromCache) { - drawer!!.addItem(PrimaryDrawerItem().withName(getString(R.string.no_tags_loaded)).withIdentifier(DRAWER_ID_TAGS).withSelectable(false)) - drawer!!.addItem(PrimaryDrawerItem().withName(getString(R.string.no_sources_loaded)).withIdentifier(DRAWER_ID_SOURCES).withSelectable(false)) + drawer.addItem( + PrimaryDrawerItem() + .withName(getString(R.string.no_tags_loaded)) + .withIdentifier(DRAWER_ID_TAGS) + .withSelectable(false)) + drawer.addItem( + PrimaryDrawerItem() + .withName(getString(R.string.no_sources_loaded)) + .withIdentifier(DRAWER_ID_SOURCES) + .withSelectable(false)) } } @@ -292,11 +425,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { var sources: List? fun sourcesApiCall() { - api!!.sources.enqueue(object: Callback> { + api.sources.enqueue(object: Callback> { override fun onResponse(call: Call>?, response: Response>) { sources = response.body() val apiDrawerData = DrawerData(tags, sources) - if (maybeDrawerData == null || (maybeDrawerData != null && maybeDrawerData != apiDrawerData)) + if ((maybeDrawerData != null && maybeDrawerData != apiDrawerData) || maybeDrawerData == null) handleDrawerData(apiDrawerData) } @@ -307,7 +440,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { }) } - api!!.tags.enqueue(object: Callback> { + api.tags.enqueue(object: Callback> { override fun onResponse(call: Call>, response: Response>) { tags = response.body() sourcesApiCall() @@ -320,7 +453,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { }) } - drawer!!.addItem(PrimaryDrawerItem().withName(getString(R.string.drawer_loading)).withSelectable(false)) + drawer.addItem(PrimaryDrawerItem().withName(getString(R.string.drawer_loading)).withSelectable(false)) val resultType = object : TypeToken() {}.type Reservoir.getAsync("drawerData", resultType, object: ReservoirGetCallback { @@ -336,102 +469,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { }) } - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_home) - - toolbar = findViewById(R.id.toolbar) as Toolbar? - setSupportActionBar(toolbar) - - if (savedInstanceState == null) { - val promptView = findViewById(R.id.prompt_view) as DefaultLayoutPromptView - Amplify.getSharedInstance().promptIfReady(promptView) - } - - mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance() - mFirebaseRemoteConfig!!.setDefaults(R.xml.default_remote_config) - - mCustomTabActivityHelper = CustomTabActivityHelper() - - api = SelfossApi(this) - items = ArrayList() - - mBottomBar = findViewById(R.id.bottomBar) as BottomBar - - handleDrawer() - - // TODO: clean this hack - val listenerAlreadySet = booleanArrayOf(false) - mBottomBar!!.setOnTabSelectListener { tabId -> - if (listenerAlreadySet[0]) { - if (tabId == R.id.tab_new) { - getUnRead() - } else if (tabId == R.id.tab_archive) { - getRead() - } else if (tabId == R.id.tab_fav) { - getStarred() - } - getElementsAccordingToTab() - } else { - listenerAlreadySet[0] = true - } - } - - mCoordinatorLayout = findViewById(R.id.coordLayout) as CoordinatorLayout - mSwipeRefreshLayout = findViewById(R.id.swipeRefreshLayout) as SwipeRefreshLayout - mRecyclerView = findViewById(R.id.my_recycler_view) as RecyclerView - - reloadLayoutManager() - - mSwipeRefreshLayout!!.setColorSchemeResources( - R.color.refresh_progress_1, - R.color.refresh_progress_2, - R.color.refresh_progress_3) - mSwipeRefreshLayout!!.setOnRefreshListener { - handleDrawerItems() - getElementsAccordingToTab() - } - - val simpleItemTouchCallback = object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) { - - override fun getSwipeDirs(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder?): Int { - if (elementsShown != UNREAD_SHOWN) { - return 0 - } else { - return super.getSwipeDirs(recyclerView, viewHolder) - } - } - - override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { - return false - } - - override fun onSwiped(viewHolder: RecyclerView.ViewHolder, swipeDir: Int) { - try { - val i = items[viewHolder.adapterPosition] - val position = items.indexOf(i) - - if (shouldBeCardView) { - (mRecyclerView!!.adapter as ItemCardAdapter).removeItemAtIndex(position) - } else { - (mRecyclerView!!.adapter as ItemListAdapter).removeItemAtIndex(position) - } - tabNew!!.setBadgeCount(items.size - 1) - - } catch (e: IndexOutOfBoundsException) { - } - - } - } - - val itemTouchHelper = ItemTouchHelper(simpleItemTouchCallback) - itemTouchHelper.attachToRecyclerView(mRecyclerView) - - - checkAndDisplayStoreApk(this@HomeActivity) - - } - private fun reloadLayoutManager() { val mLayoutManager: RecyclerView.LayoutManager if (shouldBeCardView) { @@ -441,10 +478,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { mLayoutManager = GridLayoutManager(this, calculateNoOfColumns()) } - mRecyclerView!!.layoutManager = mLayoutManager - mRecyclerView!!.setHasFixedSize(true) + mRecyclerView.layoutManager = mLayoutManager + mRecyclerView.setHasFixedSize(true) - mBottomBar!!.setOnTabReselectListener { + mBottomBar.setOnTabReselectListener { if (shouldBeCardView) { if ((mLayoutManager as StaggeredGridLayoutManager).findFirstCompletelyVisibleItemPositions(null)[0] == 0) { getElementsAccordingToTab() @@ -461,71 +498,56 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { } } - private fun getElementsAccordingToTab() { - + private fun getElementsAccordingToTab() = when (elementsShown) { UNREAD_SHOWN -> getUnRead() READ_SHOWN -> getRead() FAV_SHOWN -> getStarred() else -> getUnRead() } + + private fun doCallTo(toastMessage: Int, call: (String?, Long?, String?) -> Call>) { + fun handleItemsResponse(response: Response>) { + val didUpdate = (response.body() != items) + if (response.body() != null) { + if (response.body() != items) { + items = response.body() as ArrayList + } + } else { + items = ArrayList() + } + if (didUpdate) + handleListResult() + if (items.isEmpty()) Toast.makeText(this@HomeActivity, R.string.nothing_here, Toast.LENGTH_SHORT).show() + mSwipeRefreshLayout.isRefreshing = false + } + + call(maybeTagFilter?.tag, maybeSourceFilter?.id?.toLong(), maybeSearchFilter) + .enqueue(object : Callback> { + override fun onResponse(call: Call>, response: Response>) { + handleItemsResponse(response) + } + + override fun onFailure(call: Call>, t: Throwable) { + mSwipeRefreshLayout.isRefreshing = false + Toast.makeText(this@HomeActivity, toastMessage, Toast.LENGTH_SHORT).show() + } + }) } private fun getUnRead() { elementsShown = UNREAD_SHOWN - api!!.unreadItems(maybeTagFilter?.tag, maybeSourceFilter?.id?.toLong(), maybeSearchFilter).enqueue(object : Callback> { - override fun onResponse(call: Call>, response: Response>) { - handleItemsResponse(response) - } - - override fun onFailure(call: Call>, t: Throwable) { - mSwipeRefreshLayout!!.isRefreshing = false - Toast.makeText(this@HomeActivity, R.string.cant_get_new_elements, Toast.LENGTH_SHORT).show() - } - }) - } - - private fun handleItemsResponse(response: Response>) { - val didUpdate = (response.body() != items) - if (response.body() != null) { - if (response.body() != items) { - items = response.body() as ArrayList - } - } else { - items = ArrayList() - } - if (didUpdate) - handleListResult() - if (items.isEmpty()) Toast.makeText(this@HomeActivity, R.string.nothing_here, Toast.LENGTH_SHORT).show() - mSwipeRefreshLayout!!.isRefreshing = false + doCallTo(R.string.cant_get_new_elements){t, id, f -> api.unreadItems(t, id, f)} } private fun getRead() { elementsShown = READ_SHOWN - api!!.readItems(maybeTagFilter?.tag, maybeSourceFilter?.id?.toLong(), maybeSearchFilter).enqueue(object : Callback> { - override fun onResponse(call: Call>, response: Response>) { - handleItemsResponse(response) - } - - override fun onFailure(call: Call>, t: Throwable) { - Toast.makeText(this@HomeActivity, R.string.cant_get_read, Toast.LENGTH_SHORT).show() - mSwipeRefreshLayout!!.isRefreshing = false - } - }) + doCallTo(R.string.cant_get_read){t, id, f -> api.readItems(t, id, f)} } private fun getStarred() { elementsShown = FAV_SHOWN - api!!.starredItems(maybeTagFilter?.tag, maybeSourceFilter?.id?.toLong(), maybeSearchFilter).enqueue(object : Callback> { - override fun onResponse(call: Call>, response: Response>) { - handleItemsResponse(response) - } - - override fun onFailure(call: Call>, t: Throwable) { - Toast.makeText(this@HomeActivity, R.string.cant_get_favs, Toast.LENGTH_SHORT).show() - mSwipeRefreshLayout!!.isRefreshing = false - } - }) + doCallTo(R.string.cant_get_favs){t, id, f -> api.starredItems(t, id, f)} } private fun handleListResult() { @@ -533,157 +555,58 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { val mAdapter: RecyclerView.Adapter<*> if (shouldBeCardView) { - mAdapter = ItemCardAdapter(this, items, api!!, mCustomTabActivityHelper!!, internalBrowser, articleViewer, fullHeightCards) + mAdapter = + ItemCardAdapter( + this, + items, + api, + mCustomTabActivityHelper, + internalBrowser, + articleViewer, + fullHeightCards) } else { - mAdapter = ItemListAdapter(this, items, api!!, mCustomTabActivityHelper!!, clickBehavior, internalBrowser, articleViewer) + mAdapter = + ItemListAdapter( + this, + items, + api, + mCustomTabActivityHelper, + clickBehavior, + internalBrowser, + articleViewer) } - mRecyclerView!!.adapter = mAdapter + mRecyclerView.adapter = mAdapter mAdapter.notifyDataSetChanged() reloadBadges() } - override fun onStart() { - super.onStart() - mCustomTabActivityHelper!!.bindCustomTabsService(this) - } - - override fun onStop() { - super.onStop() - mCustomTabActivityHelper!!.unbindCustomTabsService(this) - } - - override fun onCreateOptionsMenu(menu: Menu): Boolean { - val inflater = menuInflater - inflater.inflate(R.menu.home_menu, menu) - - val searchItem = menu.findItem(R.id.action_search) - val searchView = MenuItemCompat.getActionView(searchItem) as SearchView - searchView.setOnQueryTextListener(this) - - return true - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - R.id.refresh -> { - api!!.update().enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { - Toast.makeText(this@HomeActivity, - R.string.refresh_success_response, Toast.LENGTH_LONG) - .show() - } - - override fun onFailure(call: Call, t: Throwable) { - Toast.makeText(this@HomeActivity, R.string.refresh_failer_message, Toast.LENGTH_SHORT).show() - } - }) - Toast.makeText(this, R.string.refresh_in_progress, Toast.LENGTH_SHORT).show() - return true - } - R.id.readAll -> { - if (elementsShown == UNREAD_SHOWN) { - mSwipeRefreshLayout!!.isRefreshing = false - val ids = items.map { it.id } - - api!!.readAll(ids).enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { - if (response.body() != null && response.body()!!.isSuccess) { - Toast.makeText(this@HomeActivity, R.string.all_posts_read, Toast.LENGTH_SHORT).show() - } else { - Toast.makeText(this@HomeActivity, R.string.all_posts_not_read, Toast.LENGTH_SHORT).show() - } - mSwipeRefreshLayout!!.isRefreshing = false - } - - override fun onFailure(call: Call, t: Throwable) { - Toast.makeText(this@HomeActivity, R.string.all_posts_not_read, Toast.LENGTH_SHORT).show() - mSwipeRefreshLayout!!.isRefreshing = false - } - }) - items = ArrayList() - if (items.isEmpty()) Toast.makeText(this@HomeActivity, R.string.nothing_here, Toast.LENGTH_SHORT).show() - handleListResult() - } - return true - } - R.id.action_disconnect -> { - editor!!.remove("url") - editor!!.remove("login") - editor!!.remove("password") - editor!!.apply() - val intent = Intent(this, LoginActivity::class.java) - startActivity(intent) - finish() - return true - } - R.id.action_share_the_app -> { - if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) { - val share = AppInviteInvitation.IntentBuilder(getString(R.string.invitation_title)) - .setMessage(getString(R.string.invitation_message)) - .setDeepLink(Uri.parse("https://ymbh5.app.goo.gl/qbvQ")) - .setCallToActionText(getString(R.string.invitation_cta)) - .build() - startActivityForResult(share, REQUEST_INVITE) - } else { - val sendIntent = Intent() - sendIntent.action = Intent.ACTION_SEND - sendIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.invitation_message) + " https://ymbh5.app.goo.gl/qbvQ") - sendIntent.type = "text/plain" - startActivityForResult(sendIntent, REQUEST_INVITE_BYMAIL) - } - return super.onOptionsItemSelected(item) - } - else -> return super.onOptionsItemSelected(item) - } - } - - fun reloadBadges() { + private fun reloadBadges() { if (displayUnreadCount || displayAllCount) { - api!!.stats.enqueue(object : Callback { + api.stats.enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { if (response.body() != null) { - tabNew!!.setBadgeCount(response.body()!!.unread) + tabNew.setBadgeCount(response.body()!!.unread) if (displayAllCount) { - tabArchive!!.setBadgeCount(response.body()!!.total) - tabStarred!!.setBadgeCount(response.body()!!.starred) + tabArchive.setBadgeCount(response.body()!!.total) + tabStarred.setBadgeCount(response.body()!!.starred) } else { - tabArchive!!.removeBadge() - tabStarred!!.removeBadge() + tabArchive.removeBadge() + tabStarred.removeBadge() } } } - override fun onFailure(call: Call, t: Throwable) { - - } + override fun onFailure(call: Call, t: Throwable) {} }) } else { - tabNew!!.removeBadge() - tabArchive!!.removeBadge() - tabStarred!!.removeBadge() + tabNew.removeBadge() + tabArchive.removeBadge() + tabStarred.removeBadge() } } - override fun onActivityResult(req: Int, result: Int, data: Intent?) { - when (req) { - MENU_PREFERENCES -> { - drawer!!.closeDrawer() - recreate() - } - REQUEST_INVITE -> if (result == Activity.RESULT_OK) { - Answers.getInstance().logInvite(InviteEvent()) - } - REQUEST_INVITE_BYMAIL -> { - Answers.getInstance().logInvite(InviteEvent()) - super.onActivityResult(req, result, data) - } - else -> super.onActivityResult(req, result, data) - } - - } - - fun calculateNoOfColumns(): Int { + private fun calculateNoOfColumns(): Int { val displayMetrics = resources.displayMetrics val dpWidth = displayMetrics.widthPixels / displayMetrics.density return (dpWidth / 300).toInt() @@ -702,4 +625,111 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { getElementsAccordingToTab() return false } + + override fun onActivityResult(req: Int, result: Int, data: Intent?) { + when (req) { + MENU_PREFERENCES -> { + drawer.closeDrawer() + recreate() + } + REQUEST_INVITE -> if (result == Activity.RESULT_OK) { + Answers.getInstance().logInvite(InviteEvent()) + } + REQUEST_INVITE_BYMAIL -> { + Answers.getInstance().logInvite(InviteEvent()) + super.onActivityResult(req, result, data) + } + else -> super.onActivityResult(req, result, data) + } + + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + val inflater = menuInflater + inflater.inflate(R.menu.home_menu, menu) + + val searchItem = menu.findItem(R.id.action_search) + val searchView = MenuItemCompat.getActionView(searchItem) as SearchView + searchView.setOnQueryTextListener(this) + + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.refresh -> { + api.update().enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + Toast.makeText(this@HomeActivity, + R.string.refresh_success_response, Toast.LENGTH_LONG) + .show() + } + + override fun onFailure(call: Call, t: Throwable) { + Toast.makeText(this@HomeActivity, R.string.refresh_failer_message, Toast.LENGTH_SHORT).show() + } + }) + Toast.makeText(this, R.string.refresh_in_progress, Toast.LENGTH_SHORT).show() + return true + } + R.id.readAll -> { + if (elementsShown == UNREAD_SHOWN) { + mSwipeRefreshLayout.isRefreshing = false + val ids = items.map { it.id } + + api.readAll(ids).enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.body() != null && response.body()!!.isSuccess) + Toast.makeText(this@HomeActivity, R.string.all_posts_read, Toast.LENGTH_SHORT).show() + else + Toast.makeText(this@HomeActivity, R.string.all_posts_not_read, Toast.LENGTH_SHORT).show() + + mSwipeRefreshLayout.isRefreshing = false + } + + override fun onFailure(call: Call, t: Throwable) { + Toast.makeText(this@HomeActivity, R.string.all_posts_not_read, Toast.LENGTH_SHORT).show() + mSwipeRefreshLayout.isRefreshing = false + } + }) + items = ArrayList() + if (items.isEmpty()) + Toast.makeText(this@HomeActivity, R.string.nothing_here, Toast.LENGTH_SHORT).show() + handleListResult() + } + return true + } + R.id.action_disconnect -> { + editor.remove("url") + editor.remove("login") + editor.remove("password") + editor.apply() + val intent = Intent(this, LoginActivity::class.java) + startActivity(intent) + finish() + return true + } + R.id.action_share_the_app -> { + if (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) { + val share = AppInviteInvitation.IntentBuilder(getString(R.string.invitation_title)) + .setMessage(getString(R.string.invitation_message)) + .setDeepLink(Uri.parse("https://ymbh5.app.goo.gl/qbvQ")) + .setCallToActionText(getString(R.string.invitation_cta)) + .build() + startActivityForResult(share, REQUEST_INVITE) + } else { + val sendIntent = Intent() + sendIntent.action = Intent.ACTION_SEND + sendIntent.putExtra( + Intent.EXTRA_TEXT, + getString(R.string.invitation_message) + " https://ymbh5.app.goo.gl/qbvQ" + ) + sendIntent.type = "text/plain" + startActivityForResult(sendIntent, REQUEST_INVITE_BYMAIL) + } + return super.onOptionsItemSelected(item) + } + else -> return super.onOptionsItemSelected(item) + } + } } diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/IntroActivity.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/IntroActivity.kt index 61720a6..412deb8 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/IntroActivity.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/IntroActivity.kt @@ -1,14 +1,16 @@ package apps.amine.bou.readerforselfoss -import agency.tango.materialintroscreen.MaterialIntroActivity -import agency.tango.materialintroscreen.MessageButtonBehaviour -import agency.tango.materialintroscreen.SlideFragmentBuilder import android.content.Intent import android.net.Uri import android.os.Bundle import android.preference.PreferenceManager import android.view.View +import agency.tango.materialintroscreen.MaterialIntroActivity +import agency.tango.materialintroscreen.MessageButtonBehaviour +import agency.tango.materialintroscreen.SlideFragmentBuilder + + class IntroActivity : MaterialIntroActivity() { @@ -16,32 +18,32 @@ class IntroActivity : MaterialIntroActivity() { super.onCreate(savedInstanceState) addSlide(SlideFragmentBuilder() - .backgroundColor(R.color.colorPrimary) - .buttonsColor(R.color.colorAccent) - .image(R.mipmap.ic_launcher) - .title(getString(R.string.intro_hello_title)) - .description(getString(R.string.intro_hello_message)) - .build()) + .backgroundColor(R.color.colorPrimary) + .buttonsColor(R.color.colorAccent) + .image(R.mipmap.ic_launcher) + .title(getString(R.string.intro_hello_title)) + .description(getString(R.string.intro_hello_message)) + .build()) addSlide(SlideFragmentBuilder() - .backgroundColor(R.color.colorAccent) - .buttonsColor(R.color.colorPrimary) - .image(R.drawable.ic_info_outline_white_48dp) - .title(getString(R.string.intro_needs_selfoss_title)) - .description(getString(R.string.intro_needs_selfoss_message)) - .build(), - MessageButtonBehaviour(View.OnClickListener { - val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://selfoss.aditu.de")) - startActivity(browserIntent) - }, getString(R.string.intro_needs_selfoss_link))) + .backgroundColor(R.color.colorAccent) + .buttonsColor(R.color.colorPrimary) + .image(R.drawable.ic_info_outline_white_48dp) + .title(getString(R.string.intro_needs_selfoss_title)) + .description(getString(R.string.intro_needs_selfoss_message)) + .build(), + MessageButtonBehaviour(View.OnClickListener { + val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://selfoss.aditu.de")) + startActivity(browserIntent) + }, getString(R.string.intro_needs_selfoss_link))) addSlide(SlideFragmentBuilder() - .backgroundColor(R.color.colorPrimaryDark) - .buttonsColor(R.color.colorAccentDark) - .image(R.drawable.ic_thumb_up_white_48dp) - .title(getString(R.string.intro_all_set_title)) - .description(getString(R.string.intro_all_set_message)) - .build()) + .backgroundColor(R.color.colorPrimaryDark) + .buttonsColor(R.color.colorAccentDark) + .image(R.drawable.ic_thumb_up_white_48dp) + .title(getString(R.string.intro_all_set_title)) + .description(getString(R.string.intro_all_set_message)) + .build()) } override fun onFinish() { diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/LoginActivity.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/LoginActivity.kt index e0a4758..d450482 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/LoginActivity.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/LoginActivity.kt @@ -18,11 +18,7 @@ import android.widget.Button import android.widget.EditText import android.widget.Switch import android.widget.TextView -import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi -import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse -import apps.amine.bou.readerforselfoss.utils.Config -import apps.amine.bou.readerforselfoss.utils.checkAndDisplayStoreApk -import apps.amine.bou.readerforselfoss.utils.isUrlValid + import com.google.firebase.analytics.FirebaseAnalytics import com.mikepenz.aboutlibraries.Libs import com.mikepenz.aboutlibraries.LibsBuilder @@ -30,21 +26,29 @@ import retrofit2.Call import retrofit2.Callback import retrofit2.Response +import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi +import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse +import apps.amine.bou.readerforselfoss.utils.Config +import apps.amine.bou.readerforselfoss.utils.checkAndDisplayStoreApk +import apps.amine.bou.readerforselfoss.utils.isUrlValid + + class LoginActivity : AppCompatActivity() { - private var settings: SharedPreferences? = null - private var mProgressView: View? = null - private var mUrlView: EditText? = null - private var mLoginView: TextView? = null - private var mHTTPLoginView: TextView? = null - private var mPasswordView: EditText? = null - private var mHTTPPasswordView: EditText? = null private var inValidCount: Int = 0 private var isWithLogin = false private var isWithHTTPLogin = false - private var mLoginFormView: View? = null - private var mFirebaseAnalytics: FirebaseAnalytics? = null + + private lateinit var settings: SharedPreferences + private lateinit var mFirebaseAnalytics: FirebaseAnalytics + private lateinit var mUrlView: EditText + private lateinit var mLoginView: TextView + private lateinit var mHTTPLoginView: TextView + private lateinit var mProgressView: View + private lateinit var mPasswordView: EditText + private lateinit var mHTTPPasswordView: EditText + private lateinit var mLoginFormView: View @@ -53,16 +57,12 @@ class LoginActivity : AppCompatActivity() { setContentView(R.layout.activity_login) settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE) - if (settings!!.getString("url", "").isNotEmpty()) { + if (settings.getString("url", "").isNotEmpty()) { goToMain() } else { checkAndDisplayStoreApk(this@LoginActivity) } - isWithLogin = false - isWithHTTPLogin = false - inValidCount = 0 - mFirebaseAnalytics = FirebaseAnalytics.getInstance(this) mUrlView = findViewById(R.id.url) as EditText mLoginView = findViewById(R.id.login) as TextView @@ -80,7 +80,7 @@ class LoginActivity : AppCompatActivity() { val mHTTPPasswordLayout = findViewById(R.id.httpPasswordInput) as TextInputLayout val mEmailSignInButton = findViewById(R.id.email_sign_in_button) as Button - mPasswordView!!.setOnEditorActionListener(TextView.OnEditorActionListener { _, id, _ -> + mPasswordView.setOnEditorActionListener(TextView.OnEditorActionListener { _, id, _ -> if (id == R.id.login || id == EditorInfo.IME_NULL) { attemptLogin() return@OnEditorActionListener true @@ -92,26 +92,16 @@ class LoginActivity : AppCompatActivity() { mSwitch.setOnCheckedChangeListener { _, b -> isWithLogin = !isWithLogin - val visi: Int - if (b) { - visi = View.VISIBLE + val visi: Int = if (b) View.VISIBLE else View.GONE - } else { - visi = View.GONE - } mLoginLayout.visibility = visi mPasswordLayout.visibility = visi } mHTTPSwitch.setOnCheckedChangeListener { _, b -> isWithHTTPLogin = !isWithHTTPLogin - val visi: Int - if (b) { - visi = View.VISIBLE + val visi: Int = if (b) View.VISIBLE else View.GONE - } else { - visi = View.GONE - } mHTTPLoginLayout.visibility = visi mHTTPPasswordLayout.visibility = visi } @@ -126,24 +116,24 @@ class LoginActivity : AppCompatActivity() { private fun attemptLogin() { // Reset errors. - mUrlView!!.error = null - mLoginView!!.error = null - mHTTPLoginView!!.error = null - mPasswordView!!.error = null - mHTTPPasswordView!!.error = null + mUrlView.error = null + mLoginView.error = null + mHTTPLoginView.error = null + mPasswordView.error = null + mHTTPPasswordView.error = null // Store values at the time of the login attempt. - val url = mUrlView!!.text.toString() - val login = mLoginView!!.text.toString() - val httpLogin = mHTTPLoginView!!.text.toString() - val password = mPasswordView!!.text.toString() - val httpPassword = mHTTPPasswordView!!.text.toString() + val url = mUrlView.text.toString() + val login = mLoginView.text.toString() + val httpLogin = mHTTPLoginView.text.toString() + val password = mPasswordView.text.toString() + val httpPassword = mHTTPPasswordView.text.toString() var cancel = false var focusView: View? = null if (!isUrlValid(url)) { - mUrlView!!.error = getString(R.string.login_url_problem) + mUrlView.error = getString(R.string.login_url_problem) focusView = mUrlView cancel = true inValidCount++ @@ -151,8 +141,10 @@ class LoginActivity : AppCompatActivity() { val alertDialog = AlertDialog.Builder(this).create() alertDialog.setTitle(getString(R.string.warning_wrong_url)) alertDialog.setMessage(getString(R.string.text_wrong_url)) - alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK", - { dialog, _ -> dialog.dismiss() }) + alertDialog.setButton( + AlertDialog.BUTTON_NEUTRAL, + "OK", + { dialog, _ -> dialog.dismiss() }) alertDialog.show() inValidCount = 0 } @@ -160,24 +152,24 @@ class LoginActivity : AppCompatActivity() { if (isWithLogin || isWithHTTPLogin) { if (TextUtils.isEmpty(password)) { - mPasswordView!!.error = getString(R.string.error_invalid_password) + mPasswordView.error = getString(R.string.error_invalid_password) focusView = mPasswordView cancel = true } if (TextUtils.isEmpty(login)) { - mLoginView!!.error = getString(R.string.error_field_required) + mLoginView.error = getString(R.string.error_field_required) focusView = mLoginView cancel = true } } if (cancel) { - focusView!!.requestFocus() + focusView?.requestFocus() } else { showProgress(true) - val editor = settings!!.edit() + val editor = settings.edit() editor.putString("url", url) editor.putString("login", login) editor.putString("httpUserName", httpLogin) @@ -194,17 +186,17 @@ class LoginActivity : AppCompatActivity() { editor.remove("password") editor.remove("httpPassword") editor.apply() - mUrlView!!.error = getString(R.string.wrong_infos) - mLoginView!!.error = getString(R.string.wrong_infos) - mPasswordView!!.error = getString(R.string.wrong_infos) - mHTTPLoginView!!.error = getString(R.string.wrong_infos) - mHTTPPasswordView!!.error = getString(R.string.wrong_infos) + mUrlView.error = getString(R.string.wrong_infos) + mLoginView.error = getString(R.string.wrong_infos) + mPasswordView.error = getString(R.string.wrong_infos) + mHTTPLoginView.error = getString(R.string.wrong_infos) + mHTTPPasswordView.error = getString(R.string.wrong_infos) showProgress(false) } override fun onResponse(call: Call, response: Response) { if (response.body() != null && response.body()!!.isSuccess) { - mFirebaseAnalytics!!.logEvent(FirebaseAnalytics.Event.LOGIN, Bundle()) + mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.LOGIN, Bundle()) goToMain() } else { preferenceError() @@ -224,26 +216,33 @@ class LoginActivity : AppCompatActivity() { private fun showProgress(show: Boolean) { val shortAnimTime = resources.getInteger(android.R.integer.config_shortAnimTime) - mLoginFormView!!.visibility = if (show) View.GONE else View.VISIBLE - mLoginFormView!!.animate().setDuration(shortAnimTime.toLong()).alpha( - if (show) 0F else 1F).setListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - mLoginFormView!!.visibility = if (show) View.GONE else View.VISIBLE - } - }) + mLoginFormView.visibility = if (show) View.GONE else View.VISIBLE + mLoginFormView + .animate() + .setDuration(shortAnimTime.toLong()) + .alpha( + if (show) 0F else 1F + ).setListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + mLoginFormView.visibility = if (show) View.GONE else View.VISIBLE + } + }) - mProgressView!!.visibility = if (show) View.VISIBLE else View.GONE - mProgressView!!.animate().setDuration(shortAnimTime.toLong()).alpha( - if (show) 1F else 0F).setListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - mProgressView!!.visibility = if (show) View.VISIBLE else View.GONE - } - }) + mProgressView.visibility = if (show) View.VISIBLE else View.GONE + mProgressView + .animate() + .setDuration(shortAnimTime.toLong()) + .alpha( + if (show) 1F else 0F + ).setListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + mProgressView.visibility = if (show) View.VISIBLE else View.GONE + } + }) } override fun onCreateOptionsMenu(menu: Menu): Boolean { - val inflater = menuInflater - inflater.inflate(R.menu.login_menu, menu) + menuInflater.inflate(R.menu.login_menu, menu) return true } @@ -251,10 +250,10 @@ class LoginActivity : AppCompatActivity() { when (item.itemId) { R.id.about -> { LibsBuilder() - .withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR) - .withAboutIconShown(true) - .withAboutVersionShown(true) - .start(this) + .withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR) + .withAboutIconShown(true) + .withAboutVersionShown(true) + .start(this) return true } else -> return super.onOptionsItemSelected(item) diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/MainActivity.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/MainActivity.kt index c8b3692..ee3133f 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/MainActivity.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/MainActivity.kt @@ -6,6 +6,7 @@ import android.preference.PreferenceManager import android.support.v7.app.AppCompatActivity + class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/MyApp.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/MyApp.kt index 4528289..a1fc39a 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/MyApp.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/MyApp.kt @@ -5,14 +5,13 @@ import android.graphics.drawable.Drawable import android.net.Uri import android.support.multidex.MultiDexApplication import android.widget.ImageView -import com.crashlytics.android.Crashlytics -import com.github.stkent.amplify.tracking.Amplify -import io.fabric.sdk.android.Fabric import com.anupcowkur.reservoir.Reservoir import com.bumptech.glide.Glide -import com.mikepenz.iconics.IconicsDrawable +import com.crashlytics.android.Crashlytics +import com.github.stkent.amplify.tracking.Amplify import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader import com.mikepenz.materialdrawer.util.DrawerImageLoader +import io.fabric.sdk.android.Fabric import java.io.IOException diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/ReaderActivity.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/ReaderActivity.kt index d3de482..71b49b0 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/ReaderActivity.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/ReaderActivity.kt @@ -9,10 +9,7 @@ import android.view.ViewGroup import android.widget.ImageButton import android.widget.ImageView import android.widget.TextView -import apps.amine.bou.readerforselfoss.api.mercury.MercuryApi -import apps.amine.bou.readerforselfoss.api.mercury.ParsedContent -import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent -import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper + import com.bumptech.glide.Glide import org.sufficientlysecure.htmltextview.HtmlHttpImageGetter import org.sufficientlysecure.htmltextview.HtmlTextView @@ -21,18 +18,24 @@ import retrofit2.Callback import retrofit2.Response import xyz.klinker.android.drag_dismiss.activity.DragDismissActivity +import apps.amine.bou.readerforselfoss.api.mercury.MercuryApi +import apps.amine.bou.readerforselfoss.api.mercury.ParsedContent +import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent +import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper + + class ReaderActivity : DragDismissActivity() { - private var mCustomTabActivityHelper: CustomTabActivityHelper? = null + private lateinit var mCustomTabActivityHelper: CustomTabActivityHelper override fun onStart() { super.onStart() - mCustomTabActivityHelper!!.bindCustomTabsService(this) + mCustomTabActivityHelper.bindCustomTabsService(this) } override fun onStop() { super.onStop() - mCustomTabActivityHelper!!.unbindCustomTabsService(this) + mCustomTabActivityHelper.unbindCustomTabsService(this) } override fun onCreateContent(inflater: LayoutInflater, parent: ViewGroup, savedInstanceState: Bundle?): View { @@ -51,7 +54,7 @@ class ReaderActivity : DragDismissActivity() { val customTabsIntent = buildCustomTabsIntent(this@ReaderActivity) mCustomTabActivityHelper = CustomTabActivityHelper() - mCustomTabActivityHelper!!.bindCustomTabsService(this) + mCustomTabActivityHelper.bindCustomTabsService(this) parser.parseUrl(url).enqueue(object : Callback { @@ -62,7 +65,12 @@ class ReaderActivity : DragDismissActivity() { if (response.body()!!.content != null && !response.body()!!.content.isEmpty()) content.setHtml(response.body()!!.content, HtmlHttpImageGetter(content, null, true)) if (response.body()!!.lead_image_url != null && !response.body()!!.lead_image_url.isEmpty()) - Glide.with(applicationContext).load(response.body()!!.lead_image_url).asBitmap().fitCenter().into(image) + Glide + .with(applicationContext) + .load(response.body()!!.lead_image_url) + .asBitmap() + .fitCenter() + .into(image) shareBtn.setOnClickListener { val sendIntent = Intent() @@ -81,14 +89,10 @@ class ReaderActivity : DragDismissActivity() { } hideProgressBar() - } else { - errorAfterMercuryCall() - } + } else errorAfterMercuryCall() } - override fun onFailure(call: Call, t: Throwable) { - errorAfterMercuryCall() - } + override fun onFailure(call: Call, t: Throwable) = errorAfterMercuryCall() private fun errorAfterMercuryCall() { CustomTabActivityHelper.openCustomTab(this@ReaderActivity, customTabsIntent, Uri.parse(url) diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/SourcesActivity.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/SourcesActivity.kt index 08ab4fd..bf22461 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/SourcesActivity.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/SourcesActivity.kt @@ -6,14 +6,17 @@ import android.support.v7.app.AppCompatActivity import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.RecyclerView import android.widget.Toast -import apps.amine.bou.readerforselfoss.adapters.SourcesListAdapter -import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi -import apps.amine.bou.readerforselfoss.api.selfoss.Sources + import com.melnykov.fab.FloatingActionButton import retrofit2.Call import retrofit2.Callback import retrofit2.Response +import apps.amine.bou.readerforselfoss.adapters.SourcesListAdapter +import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi +import apps.amine.bou.readerforselfoss.api.selfoss.Sources + + class SourcesActivity : AppCompatActivity() { diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/ItemCardAdapter.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/ItemCardAdapter.kt index a6a5bfd..fd62ac2 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/ItemCardAdapter.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/ItemCardAdapter.kt @@ -1,6 +1,5 @@ package apps.amine.bou.readerforselfoss.adapters - import android.app.Activity import android.content.Context import android.content.Intent @@ -20,13 +19,7 @@ import android.widget.ImageView import android.widget.ImageView.ScaleType import android.widget.TextView import android.widget.Toast -import apps.amine.bou.readerforselfoss.R -import apps.amine.bou.readerforselfoss.api.selfoss.Item -import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi -import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse -import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent -import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper -import apps.amine.bou.readerforselfoss.utils.openItemUrl + import com.amulyakhare.textdrawable.TextDrawable import com.amulyakhare.textdrawable.util.ColorGenerator import com.bumptech.glide.Glide @@ -40,10 +33,21 @@ import java.text.ParseException import java.text.SimpleDateFormat import java.util.* +import apps.amine.bou.readerforselfoss.R +import apps.amine.bou.readerforselfoss.api.selfoss.Item +import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi +import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse +import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent +import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper +import apps.amine.bou.readerforselfoss.utils.openItemUrl -class ItemCardAdapter(private val app: Activity, private val items: ArrayList, private val api: SelfossApi, - private val helper: CustomTabActivityHelper, private val internalBrowser: Boolean, - private val articleViewer: Boolean, private val fullHeightCards: Boolean) : RecyclerView.Adapter() { +class ItemCardAdapter(private val app: Activity, + private val items: ArrayList, + private val api: SelfossApi, + private val helper: CustomTabActivityHelper, + private val internalBrowser: Boolean, + private val articleViewer: Boolean, + private val fullHeightCards: Boolean) : RecyclerView.Adapter() { private val c: Context = app.applicationContext private val generator: ColorGenerator = ColorGenerator.MATERIAL @@ -56,8 +60,8 @@ class ItemCardAdapter(private val app: Activity, private val items: ArrayList { override fun onResponse(call: Call, response: Response) {} override fun onFailure(call: Call, t: Throwable) { - saveBtn!!.isLiked = false + saveBtn.isLiked = false Toast.makeText(c, R.string.cant_mark_favortie, Toast.LENGTH_SHORT).show() } }) @@ -209,14 +213,14 @@ class ItemCardAdapter(private val app: Activity, private val items: ArrayList, response: Response) {} override fun onFailure(call: Call, t: Throwable) { - saveBtn!!.isLiked = true + saveBtn.isLiked = true Toast.makeText(c, R.string.cant_unmark_favortie, Toast.LENGTH_SHORT).show() } }) } }) - shareBtn!!.setOnClickListener { + shareBtn.setOnClickListener { val i = items[adapterPosition] val sendIntent = Intent() sendIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK @@ -226,7 +230,7 @@ class ItemCardAdapter(private val app: Activity, private val items: ArrayList, private val api: SelfossApi, - private val helper: CustomTabActivityHelper, private val clickBehavior: Boolean, - private val internalBrowser: Boolean, private val articleViewer: Boolean) : RecyclerView.Adapter() { + + +class ItemListAdapter(private val app: Activity, + private val items: ArrayList, + private val api: SelfossApi, + private val helper: CustomTabActivityHelper, + private val clickBehavior: Boolean, + private val internalBrowser: Boolean, + private val articleViewer: Boolean) : RecyclerView.Adapter() { private val generator: ColorGenerator = ColorGenerator.MATERIAL private val c: Context = app.applicationContext private val bars: ArrayList = ArrayList(Collections.nCopies(items.size + 1, false)) @@ -55,41 +62,41 @@ class ItemListAdapter(private val app: Activity, private val items: ArrayList { override fun onResponse(call: Call, response: Response) {} override fun onFailure(call: Call, t: Throwable) { - saveBtn!!.isLiked = false + saveBtn.isLiked = false Toast.makeText(c, R.string.cant_mark_favortie, Toast.LENGTH_SHORT).show() } }) @@ -220,14 +221,14 @@ class ItemListAdapter(private val app: Activity, private val items: ArrayList, response: Response) {} override fun onFailure(call: Call, t: Throwable) { - saveBtn!!.isLiked = true + saveBtn.isLiked = true Toast.makeText(c, R.string.cant_unmark_favortie, Toast.LENGTH_SHORT).show() } }) } }) - shareBtn!!.setOnClickListener { + shareBtn.setOnClickListener { val i = items[adapterPosition] val sendIntent = Intent() sendIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK @@ -237,7 +238,7 @@ class ItemListAdapter(private val app: Activity, private val items: ArrayList, private val api: SelfossApi) : RecyclerView.Adapter() { +import apps.amine.bou.readerforselfoss.R +import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi +import apps.amine.bou.readerforselfoss.api.selfoss.Sources +import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse + + + +class SourcesListAdapter(private val app: Activity, + private val items: ArrayList, + private val api: SelfossApi) : RecyclerView.Adapter() { private val c: Context = app.baseContext private val generator: ColorGenerator = ColorGenerator.MATERIAL @@ -49,13 +55,18 @@ class SourcesListAdapter(private val app: Activity, private val items: ArrayList val drawable = builder.build(textDrawable.toString(), color) holder.sourceImage!!.setImageDrawable(drawable) } else { - Glide.with(c).load(itm.getIcon(c)).asBitmap().centerCrop().into(object : BitmapImageViewTarget(holder.sourceImage) { - override fun setResource(resource: Bitmap) { - val circularBitmapDrawable = RoundedBitmapDrawableFactory.create(c.resources, resource) - circularBitmapDrawable.isCircular = true - fHolder.sourceImage!!.setImageDrawable(circularBitmapDrawable) - } - }) + Glide + .with(c) + .load(itm.getIcon(c)) + .asBitmap() + .centerCrop() + .into(object : BitmapImageViewTarget(holder.sourceImage) { + override fun setResource(resource: Bitmap) { + val circularBitmapDrawable = RoundedBitmapDrawableFactory.create(c.resources, resource) + circularBitmapDrawable.isCircular = true + fHolder.sourceImage!!.setImageDrawable(circularBitmapDrawable) + } + }) } holder.sourceTitle!!.text = itm.title @@ -89,12 +100,12 @@ class SourcesListAdapter(private val app: Activity, private val items: ArrayList notifyItemRemoved(adapterPosition) notifyItemRangeChanged(adapterPosition, itemCount) } else { - Toast.makeText(app, "Petit soucis lors de la suppression de la source.", Toast.LENGTH_SHORT).show() + Toast.makeText(app, R.string.can_delete_source, Toast.LENGTH_SHORT).show() } } override fun onFailure(call: Call, t: Throwable) { - Toast.makeText(app, "Petit soucis lors de la suppression de la source.", Toast.LENGTH_SHORT).show() + Toast.makeText(app, R.string.can_delete_source, Toast.LENGTH_SHORT).show() } }) } diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/api/mercury/MercuryApi.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/api/mercury/MercuryApi.kt index 57b4e2d..2668926 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/api/mercury/MercuryApi.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/api/mercury/MercuryApi.kt @@ -1,6 +1,5 @@ package apps.amine.bou.readerforselfoss.api.mercury - import com.google.gson.GsonBuilder import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor @@ -9,6 +8,7 @@ import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory + class MercuryApi(private val key: String) { private val service: MercuryService @@ -21,8 +21,13 @@ class MercuryApi(private val key: String) { val gson = GsonBuilder() .setLenient() .create() - val retrofit = Retrofit.Builder().baseUrl("https://mercury.postlight.com").client(client) - .addConverterFactory(GsonConverterFactory.create(gson)).build() + val retrofit = + Retrofit + .Builder() + .baseUrl("https://mercury.postlight.com") + .client(client) + .addConverterFactory(GsonConverterFactory.create(gson)) + .build() service = retrofit.create(MercuryService::class.java) } diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/api/mercury/MercuryModels.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/api/mercury/MercuryModels.kt index 1b05115..c4b2638 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/api/mercury/MercuryModels.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/api/mercury/MercuryModels.kt @@ -4,6 +4,7 @@ import android.os.Parcel import android.os.Parcelable + class ParsedContent(val title: String, val content: String, val date_published: String, @@ -24,17 +25,17 @@ class ParsedContent(val title: String, } constructor(source: Parcel) : this( - title = source.readString(), - content = source.readString(), - date_published = source.readString(), - lead_image_url = source.readString(), - dek = source.readString(), - url = source.readString(), - domain = source.readString(), - excerpt = source.readString(), - total_pages = source.readInt(), - rendered_pages = source.readInt(), - next_page_url = source.readString() + title = source.readString(), + content = source.readString(), + date_published = source.readString(), + lead_image_url = source.readString(), + dek = source.readString(), + url = source.readString(), + domain = source.readString(), + excerpt = source.readString(), + total_pages = source.readInt(), + rendered_pages = source.readInt(), + next_page_url = source.readString() ) override fun describeContents() = 0 diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/api/mercury/MercuryService.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/api/mercury/MercuryService.kt index 97a0ad2..e242ee0 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/api/mercury/MercuryService.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/api/mercury/MercuryService.kt @@ -7,6 +7,7 @@ import retrofit2.http.Header import retrofit2.http.Query + interface MercuryService { @GET("parser") fun parseUrl(@Query("url") url: String, @Header("x-api-key") key: String): Call diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/BooleanTypeAdapter.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/BooleanTypeAdapter.kt index 69acad7..edcdb2e 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/BooleanTypeAdapter.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/BooleanTypeAdapter.kt @@ -1,10 +1,12 @@ package apps.amine.bou.readerforselfoss.api.selfoss +import java.lang.reflect.Type + import com.google.gson.JsonParseException import com.google.gson.JsonDeserializationContext import com.google.gson.JsonElement import com.google.gson.JsonDeserializer -import java.lang.reflect.Type + internal class BooleanTypeAdapter : JsonDeserializer { diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossApi.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossApi.kt index a4be878..256146c 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossApi.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossApi.kt @@ -1,8 +1,8 @@ package apps.amine.bou.readerforselfoss.api.selfoss - import android.content.Context -import apps.amine.bou.readerforselfoss.utils.Config +import java.util.concurrent.ConcurrentHashMap + import com.burgstaller.okhttp.AuthenticationCacheInterceptor import com.burgstaller.okhttp.CachingAuthenticatorDecorator import com.burgstaller.okhttp.DispatchingAuthenticator @@ -16,7 +16,9 @@ import okhttp3.logging.HttpLoggingInterceptor import retrofit2.Call import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory -import java.util.concurrent.ConcurrentHashMap + +import apps.amine.bou.readerforselfoss.utils.Config + class SelfossApi(c: Context) { @@ -43,28 +45,33 @@ class SelfossApi(c: Context) { // note that all auth schemes should be registered as lowercase! val authenticator = DispatchingAuthenticator.Builder() - .with("digest", digestAuthenticator) - .with("basic", basicAuthenticator) - .build() + .with("digest", digestAuthenticator) + .with("basic", basicAuthenticator) + .build() val client = httpBuilder - .authenticator(CachingAuthenticatorDecorator(authenticator, authCache)) - .addInterceptor(AuthenticationCacheInterceptor(authCache)) - .addInterceptor(interceptor) - .build() + .authenticator(CachingAuthenticatorDecorator(authenticator, authCache)) + .addInterceptor(AuthenticationCacheInterceptor(authCache)) + .addInterceptor(interceptor) + .build() val builder = GsonBuilder() builder.registerTypeAdapter(Boolean::class.javaPrimitiveType, BooleanTypeAdapter()) val gson = builder - .setLenient() - .create() + .setLenient() + .create() userName = config.userLogin password = config.userPassword - val retrofit = Retrofit.Builder().baseUrl(config.baseUrl).client(client) - .addConverterFactory(GsonConverterFactory.create(gson)).build() + val retrofit = + Retrofit + .Builder() + .baseUrl(config.baseUrl) + .client(client) + .addConverterFactory(GsonConverterFactory.create(gson)) + .build() service = retrofit.create(SelfossService::class.java) } diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossModels.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossModels.kt index a67510f..6c98d99 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossModels.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossModels.kt @@ -4,10 +4,12 @@ import android.content.Context import android.net.Uri import android.os.Parcel import android.os.Parcelable + import apps.amine.bou.readerforselfoss.utils.Config import apps.amine.bou.readerforselfoss.utils.isEmptyOrNullOrNullString + private fun constructUrl(config: Config?, path: String, file: String): String { val baseUriBuilder = Uri.parse(config!!.baseUrl).buildUpon() baseUriBuilder.appendPath(path).appendPath(file) @@ -65,15 +67,15 @@ data class Item(val id: String, } constructor(source: Parcel) : this( - id = source.readString(), - datetime = source.readString(), - title = source.readString(), - unread = 0.toByte() != source.readByte(), - starred = 0.toByte() != source.readByte(), - thumbnail = source.readString(), - icon = source.readString(), - link = source.readString(), - sourcetitle = source.readString() + id = source.readString(), + datetime = source.readString(), + title = source.readString(), + unread = 0.toByte() != source.readByte(), + starred = 0.toByte() != source.readByte(), + thumbnail = source.readString(), + icon = source.readString(), + link = source.readString(), + sourcetitle = source.readString() ) override fun describeContents() = 0 diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossService.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossService.kt index 4b0f2f0..b0f0779 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossService.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossService.kt @@ -1,6 +1,5 @@ package apps.amine.bou.readerforselfoss.api.selfoss - import retrofit2.Call import retrofit2.http.DELETE import retrofit2.http.Field @@ -11,6 +10,7 @@ import retrofit2.http.Path import retrofit2.http.Query + internal interface SelfossService { @GET("login") fun loginToSelfoss(@Query("username") username: String, @Query("password") password: String): Call @@ -24,47 +24,70 @@ internal interface SelfossService { @Query("password") password: String): Call> @POST("mark/{id}") - fun markAsRead(@Path("id") id: String, @Query("username") username: String, @Query("password") password: String): Call + fun markAsRead(@Path("id") id: String, + @Query("username") username: String, + @Query("password") password: String): Call @POST("unmark/{id}") - fun unmarkAsRead(@Path("id") id: String, @Query("username") username: String, @Query("password") password: String): Call + fun unmarkAsRead(@Path("id") id: String, + @Query("username") username: String, + @Query("password") password: String): Call @FormUrlEncoded @POST("mark") - fun markAllAsRead(@Field("ids[]") ids: List, @Query("username") username: String, @Query("password") password: String): Call + fun markAllAsRead(@Field("ids[]") ids: List, + @Query("username") username: String, + @Query("password") password: String): Call @POST("starr/{id}") - fun starr(@Path("id") id: String, @Query("username") username: String, @Query("password") password: String): Call + fun starr(@Path("id") id: String, + @Query("username") username: String, + @Query("password") password: String): Call @POST("unstarr/{id}") - fun unstarr(@Path("id") id: String, @Query("username") username: String, @Query("password") password: String): Call + fun unstarr(@Path("id") id: String, + @Query("username") username: String, + @Query("password") password: String): Call @GET("stats") - fun stats(@Query("username") username: String, @Query("password") password: String): Call + fun stats(@Query("username") username: String, + @Query("password") password: String): Call @GET("tags") - fun tags(@Query("username") username: String, @Query("password") password: String): Call> + fun tags(@Query("username") username: String, + @Query("password") password: String): Call> @GET("update") - fun update(@Query("username") username: String, @Query("password") password: String): Call + fun update(@Query("username") username: String, + @Query("password") password: String): Call @GET("sources/spouts") - fun spouts(@Query("username") username: String, @Query("password") password: String): Call> + fun spouts(@Query("username") username: String, + @Query("password") password: String): Call> @GET("sources/list") - fun sources(@Query("username") username: String, @Query("password") password: String): Call> + fun sources(@Query("username") username: String, + @Query("password") password: String): Call> @DELETE("source/{id}") - fun deleteSource(@Path("id") id: String, @Query("username") username: String, @Query("password") password: String): Call + fun deleteSource(@Path("id") id: String, + @Query("username") username: String, + @Query("password") password: String): Call @FormUrlEncoded @POST("source") - fun createSource(@Field("title") title: String, @Field("url") url: String, @Field("spout") spout: String, @Field("tags") tags: String, @Field("filter") filter: String, @Query("username") username: String, @Query("password") password: String): Call + fun createSource(@Field("title") title: String, + @Field("url") url: String, + @Field("spout") spout: String, + @Field("tags") tags: String, + @Field("filter") filter: String, + @Query("username") username: String, + @Query("password") password: String): Call } diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/utils/AppUtils.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/utils/AppUtils.kt index 3381bcd..03e5c0f 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/utils/AppUtils.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/utils/AppUtils.kt @@ -7,33 +7,37 @@ import android.net.Uri import android.support.v7.app.AlertDialog import android.text.TextUtils import android.util.Patterns -import apps.amine.bou.readerforselfoss.BuildConfig -import apps.amine.bou.readerforselfoss.R + import com.google.firebase.remoteconfig.FirebaseRemoteConfig import okhttp3.HttpUrl -private fun isStoreVersion(context: Context): Boolean { - var result = false - try { - val installer = context.packageManager +import apps.amine.bou.readerforselfoss.BuildConfig +import apps.amine.bou.readerforselfoss.R + + + +fun checkAndDisplayStoreApk(context: Context) = { + fun isStoreVersion(context: Context): Boolean { + var result = false + try { + val installer = context.packageManager .getInstallerPackageName(context.packageName) - result = !TextUtils.isEmpty(installer) - } catch (e: Throwable) { + result = !TextUtils.isEmpty(installer) + } catch (e: Throwable) { + } + + return result } - return result -} - -fun checkAndDisplayStoreApk(context: Context) = if (!isStoreVersion(context) && !BuildConfig.GITHUB_VERSION) { val alertDialog = AlertDialog.Builder(context).create() alertDialog.setTitle(context.getString(R.string.warning_version)) alertDialog.setMessage(context.getString(R.string.text_version)) alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK", - { dialog, _ -> dialog.dismiss() }) + { dialog, _ -> dialog.dismiss() }) alertDialog.show() } else Unit - +} fun isUrlValid(url: String): Boolean { val baseUrl = HttpUrl.parse(url) @@ -47,44 +51,46 @@ fun isUrlValid(url: String): Boolean { } fun isEmptyOrNullOrNullString(str: String?): Boolean = - str == null || str == "null" || str.isEmpty() + str == null || str == "null" || str.isEmpty() -fun checkApkVersion(settings: SharedPreferences, editor: SharedPreferences.Editor, context: Context, mFirebaseRemoteConfig: FirebaseRemoteConfig) { - mFirebaseRemoteConfig.fetch(43200) - .addOnCompleteListener { task -> - if (task.isSuccessful) { - mFirebaseRemoteConfig.activateFetched() - } else { +fun checkApkVersion(settings: SharedPreferences, + editor: SharedPreferences.Editor, + context: Context, + mFirebaseRemoteConfig: FirebaseRemoteConfig) = { + fun isThereAnUpdate() { + val APK_LINK = "github_apk" + + val apkLink = mFirebaseRemoteConfig.getString(APK_LINK) + val storedLink = settings.getString(APK_LINK, "") + if (apkLink != storedLink && !apkLink.isEmpty()) { + val alertDialog = AlertDialog.Builder(context).create() + alertDialog.setTitle(context.getString(R.string.new_apk_available_title)) + alertDialog.setMessage(context.getString(R.string.new_apk_available_message)) + alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.new_apk_available_get)) { _, _ -> + editor.putString(APK_LINK, apkLink) + editor.apply() + val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(apkLink)) + context.startActivity(browserIntent) } - - isThereAnUpdate(settings, editor, context, mFirebaseRemoteConfig) - } -} - -private fun isThereAnUpdate(settings: SharedPreferences, editor: SharedPreferences.Editor, context: Context, mFirebaseRemoteConfig: FirebaseRemoteConfig) { - val APK_LINK = "github_apk" - - val apkLink = mFirebaseRemoteConfig.getString(APK_LINK) - val storedLink = settings.getString(APK_LINK, "") - if (apkLink != storedLink && !apkLink.isEmpty()) { - val alertDialog = AlertDialog.Builder(context).create() - alertDialog.setTitle(context.getString(R.string.new_apk_available_title)) - alertDialog.setMessage(context.getString(R.string.new_apk_available_message)) - alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.new_apk_available_get)) { _, _ -> - editor.putString(APK_LINK, apkLink) - editor.apply() - val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(apkLink)) - context.startActivity(browserIntent) - } - alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, context.getString(R.string.new_apk_available_no), + alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, context.getString(R.string.new_apk_available_no), { dialog, _ -> editor.putString(APK_LINK, apkLink) editor.apply() dialog.dismiss() }) - alertDialog.show() + alertDialog.show() + } + } + mFirebaseRemoteConfig.fetch(43200) + .addOnCompleteListener { task -> + if (task.isSuccessful) { + mFirebaseRemoteConfig.activateFetched() + } + + isThereAnUpdate() + } } fun longHash(string: String): Long { diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/utils/LinksUtils.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/utils/LinksUtils.kt index 466e825..18f6c93 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/utils/LinksUtils.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/utils/LinksUtils.kt @@ -7,11 +7,15 @@ import android.content.Intent import android.graphics.BitmapFactory import android.net.Uri import android.support.customtabs.CustomTabsIntent + +import xyz.klinker.android.drag_dismiss.DragDismissIntentBuilder + import apps.amine.bou.readerforselfoss.R import apps.amine.bou.readerforselfoss.ReaderActivity import apps.amine.bou.readerforselfoss.api.selfoss.Item import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper -import xyz.klinker.android.drag_dismiss.DragDismissIntentBuilder + + fun buildCustomTabsIntent(c: Context): CustomTabsIntent { diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/utils/drawer/CustomBaseViewHolder.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/utils/drawer/CustomBaseViewHolder.kt index 15d6bff..fc1c12f 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/utils/drawer/CustomBaseViewHolder.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/utils/drawer/CustomBaseViewHolder.kt @@ -1,7 +1,6 @@ /* From https://github.com/mikepenz/MaterialDrawer/blob/develop/app/src/main/java/com/mikepenz/materialdrawer/app/drawerItems/CustomBaseViewHolder.java */ package apps.amine.bou.readerforselfoss.utils.drawer - import android.support.v7.widget.RecyclerView import android.view.View import android.widget.ImageView @@ -10,6 +9,7 @@ import android.widget.TextView import apps.amine.bou.readerforselfoss.R + open class CustomBaseViewHolder(var view: View) : RecyclerView.ViewHolder(view) { var icon: ImageView = view.findViewById(R.id.material_drawer_icon) as ImageView var name: TextView = view.findViewById(R.id.material_drawer_name) as TextView diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/utils/drawer/CustomUrlBasePrimaryDrawerItem.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/utils/drawer/CustomUrlBasePrimaryDrawerItem.kt index c10d57b..55f7c14 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/utils/drawer/CustomUrlBasePrimaryDrawerItem.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/utils/drawer/CustomUrlBasePrimaryDrawerItem.kt @@ -1,8 +1,6 @@ /* From https://github.com/mikepenz/MaterialDrawer/blob/develop/app/src/main/java/com/mikepenz/materialdrawer/app/drawerItems/CustomUrlBasePrimaryDrawerItem.java */ package apps.amine.bou.readerforselfoss.utils.drawer - -import android.content.Context import android.net.Uri import android.support.annotation.ColorInt import android.support.annotation.ColorRes @@ -18,6 +16,7 @@ import com.mikepenz.materialdrawer.util.DrawerUIUtils import com.mikepenz.materialize.util.UIUtils + abstract class CustomUrlBasePrimaryDrawerItem : BaseDrawerItem() { fun withIcon(url: String): T { this.icon = ImageHolder(url) diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/utils/drawer/CustomUrlPrimaryDrawerItem.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/utils/drawer/CustomUrlPrimaryDrawerItem.kt index 9a56d94..b1584ca 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/utils/drawer/CustomUrlPrimaryDrawerItem.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/utils/drawer/CustomUrlPrimaryDrawerItem.kt @@ -1,18 +1,18 @@ /* From https://github.com/mikepenz/MaterialDrawer/blob/develop/app/src/main/java/com/mikepenz/materialdrawer/app/drawerItems/CustomUrlPrimaryDrawerItem.java */ package apps.amine.bou.readerforselfoss.utils.drawer - -import android.content.Context import android.support.annotation.LayoutRes import android.support.annotation.StringRes import android.view.View import android.widget.TextView -import apps.amine.bou.readerforselfoss.R import com.mikepenz.materialdrawer.holder.BadgeStyle import com.mikepenz.materialdrawer.holder.StringHolder import com.mikepenz.materialdrawer.model.interfaces.ColorfulBadgeable +import apps.amine.bou.readerforselfoss.R + + class CustomUrlPrimaryDrawerItem : CustomUrlBasePrimaryDrawerItem(), ColorfulBadgeable { protected var mBadge: StringHolder = StringHolder("") diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 9aea9a0..a5afa88 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -15,7 +15,6 @@ "Partager" "Tout lire" "Déconnecter" - "Sources" "Paramètres" "General" "Action du clique sur un article" @@ -115,4 +114,5 @@ Pas de sources chargés Chargement … Rechercher + Petit soucis lors de la suppression de la source. \ No newline at end of file diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 41990e5..8ae1d0d 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -15,7 +15,6 @@ "Delen" "Alles lezen" "Verbinding verbreken" - "Bronnen" "Instellingen" "Algemeen" "Actie bij tikken op artikelen" @@ -115,4 +114,5 @@ No sources loaded Loading … Zoeken + Can\'t delete the source... \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 08e6bd6..91e3961 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,4 +1,4 @@ - + "Reader for Selfoss" "Log in" "Password" @@ -15,7 +15,6 @@ "Share" "Read all" "Disconnect" - "Sources" "Settings" "General" "Tap action on the articles" @@ -112,9 +111,10 @@ Tags Sources edit - Couldn\'t cache your drawer data + Couldn\'t cache your drawer data No tags loaded No sources loaded Loading … Search + Can\'t delete the source... \ No newline at end of file