diff --git a/app/build.gradle b/app/build.gradle index ba9916e..e058e99 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,6 @@ apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' -apply plugin: 'kotlin-android-extensions' - android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -39,6 +37,9 @@ android { } compileSdkVersion 30 buildToolsVersion '30.0.3' + buildFeatures { + viewBinding true + } defaultConfig { applicationId "apps.amine.bou.readerforselfoss" minSdkVersion 16 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 2ccfcfb..5246df3 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/AddSourceActivity.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/AddSourceActivity.kt @@ -23,11 +23,11 @@ import apps.amine.bou.readerforselfoss.themes.Toppings import apps.amine.bou.readerforselfoss.utils.Config import apps.amine.bou.readerforselfoss.utils.isBaseUrlValid import com.ftinc.scoop.Scoop -import kotlinx.android.synthetic.main.activity_add_source.* import retrofit2.Call import retrofit2.Callback import retrofit2.Response import android.graphics.PorterDuff +import apps.amine.bou.readerforselfoss.databinding.ActivityAddSourceBinding @@ -37,50 +37,53 @@ class AddSourceActivity : AppCompatActivity() { private lateinit var api: SelfossApi private lateinit var appColors: AppColors + private lateinit var binding: ActivityAddSourceBinding override fun onCreate(savedInstanceState: Bundle?) { appColors = AppColors(this@AddSourceActivity) super.onCreate(savedInstanceState) + binding = ActivityAddSourceBinding.inflate(layoutInflater) + val view = binding.root - setContentView(R.layout.activity_add_source) + setContentView(view) val scoop = Scoop.getInstance() - scoop.bind(this, Toppings.PRIMARY.value, toolbar) + scoop.bind(this, Toppings.PRIMARY.value, binding.toolbar) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value) } - val drawable = nameInput.background + val drawable = binding.nameInput.background drawable.setColorFilter(appColors.colorAccent, PorterDuff.Mode.SRC_ATOP) // TODO: clean if(Build.VERSION.SDK_INT > 16) { - nameInput.background = drawable + binding.nameInput.background = drawable } else{ - nameInput.setBackgroundDrawable(drawable) + binding.nameInput.setBackgroundDrawable(drawable) } - val drawable1 = sourceUri.background + val drawable1 = binding.sourceUri.background drawable1.setColorFilter(appColors.colorAccent, PorterDuff.Mode.SRC_ATOP) if(Build.VERSION.SDK_INT > 16) { - sourceUri.background = drawable1 + binding.sourceUri.background = drawable1 } else{ - sourceUri.setBackgroundDrawable(drawable1) + binding.sourceUri.setBackgroundDrawable(drawable1) } - val drawable2 = tags.background + val drawable2 = binding.tags.background drawable2.setColorFilter(appColors.colorAccent, PorterDuff.Mode.SRC_ATOP) if(Build.VERSION.SDK_INT > 16) { - tags.background = drawable2 + binding.tags.background = drawable2 } else{ - tags.setBackgroundDrawable(drawable2) + binding.tags.setBackgroundDrawable(drawable2) } - setSupportActionBar(toolbar) + setSupportActionBar(binding.toolbar) supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayShowHomeEnabled(true) @@ -98,12 +101,12 @@ class AddSourceActivity : AppCompatActivity() { mustLoginToAddSource() } - maybeGetDetailsFromIntentSharing(intent, sourceUri, nameInput) + maybeGetDetailsFromIntentSharing(intent, binding.sourceUri, binding.nameInput) - saveBtn.setTextColor(appColors.colorAccent) + binding.saveBtn.setTextColor(appColors.colorAccent) - saveBtn.setOnClickListener { - handleSaveSource(tags, nameInput.text.toString(), sourceUri.text.toString(), api!!) + binding.saveBtn.setOnClickListener { + handleSaveSource(binding.tags, binding.nameInput.text.toString(), binding.sourceUri.text.toString(), api) } } @@ -114,7 +117,7 @@ class AddSourceActivity : AppCompatActivity() { if (config.baseUrl.isEmpty() || !config.baseUrl.isBaseUrlValid(this@AddSourceActivity)) { mustLoginToAddSource() } else { - handleSpoutsSpinner(spoutsSpinner, api, progress, formContainer) + handleSpoutsSpinner(binding.spoutsSpinner, api, binding.progress, binding.formContainer) } } 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 02ffe97..8b86b79 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/HomeActivity.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/HomeActivity.kt @@ -29,6 +29,7 @@ import apps.amine.bou.readerforselfoss.adapters.ItemListAdapter import apps.amine.bou.readerforselfoss.adapters.ItemsAdapter import apps.amine.bou.readerforselfoss.api.selfoss.* import apps.amine.bou.readerforselfoss.background.LoadingWorker +import apps.amine.bou.readerforselfoss.databinding.ActivityHomeBinding import apps.amine.bou.readerforselfoss.persistence.database.AppDatabase import apps.amine.bou.readerforselfoss.persistence.entities.ActionEntity import apps.amine.bou.readerforselfoss.persistence.migrations.MIGRATION_1_2 @@ -64,7 +65,6 @@ import com.mikepenz.materialdrawer.holder.StringHolder import com.mikepenz.materialdrawer.model.DividerDrawerItem import com.mikepenz.materialdrawer.model.PrimaryDrawerItem import com.mikepenz.materialdrawer.model.SecondaryDrawerItem -import kotlinx.android.synthetic.main.activity_home.* import retrofit2.Call import retrofit2.Callback import retrofit2.Response @@ -123,6 +123,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { private var firstVisible: Int = 0 private lateinit var recyclerViewScrollListener: RecyclerView.OnScrollListener private lateinit var settings: SharedPreferences + private lateinit var binding: ActivityHomeBinding private var recyclerAdapter: RecyclerView.Adapter<*>? = null @@ -151,6 +152,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { config = Config(this@HomeActivity) super.onCreate(savedInstanceState) + binding = ActivityHomeBinding.inflate(layoutInflater) + val view = binding.root fromTabShortcut = intent.getIntExtra("shortcutTab", -1) != -1 offlineShortcut = intent.getBooleanExtra("startOffline", false) @@ -159,11 +162,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { elementsShown = intent.getIntExtra("shortcutTab", UNREAD_SHOWN) } - setContentView(R.layout.activity_home) + setContentView(view) handleThemeBinding() - setSupportActionBar(toolBar) + setSupportActionBar(binding.toolBar) db = Room.databaseBuilder( applicationContext, @@ -196,12 +199,12 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { } private fun handleSwipeRefreshLayout() { - swipeRefreshLayout.setColorSchemeResources( + binding.swipeRefreshLayout.setColorSchemeResources( R.color.refresh_progress_1, R.color.refresh_progress_2, R.color.refresh_progress_3 ) - swipeRefreshLayout.setOnRefreshListener { + binding.swipeRefreshLayout.setOnRefreshListener { offlineShortcut = false allItems = ArrayList() lastFetchDone = false @@ -238,7 +241,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { val i = items.elementAtOrNull(position) if (i != null) { - val adapter = recyclerView.adapter as ItemsAdapter<*> + val adapter = binding.recyclerView.adapter as ItemsAdapter<*> val wasItemUnread = adapter.unreadItemStatusAtIndex(position) @@ -276,7 +279,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { } } - ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(recyclerView) + ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(binding.recyclerView) } private fun handleBottomBar() { @@ -313,18 +316,17 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { ).setActiveColorResource(R.color.pink) .setBadgeItem(tabStarredBadge) - bottomBar + binding.bottomBar .addItem(tabNew) .addItem(tabArchive) .addItem(tabStarred) .setFirstSelectedPosition(0) .initialise() - - bottomBar.setMode(BottomNavigationBar.MODE_SHIFTING) - bottomBar.setBackgroundStyle(BottomNavigationBar.BACKGROUND_STYLE_STATIC) + binding.bottomBar.setMode(BottomNavigationBar.MODE_SHIFTING) + binding.bottomBar.setBackgroundStyle(BottomNavigationBar.BACKGROUND_STYLE_STATIC) if (fromTabShortcut) { - bottomBar.selectTab(elementsShown - 1) + binding.bottomBar.selectTab(elementsShown - 1) } } @@ -345,7 +347,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { reloadLayoutManager() if (!infiniteScroll) { - recyclerView.setHasFixedSize(true) + binding.recyclerView.setHasFixedSize(true) } else { handleInfiniteScroll() } @@ -444,7 +446,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { private fun handleThemeBinding() { val scoop = Scoop.getInstance() - scoop.bind(this, Toppings.PRIMARY.value, toolBar) + scoop.bind(this, Toppings.PRIMARY.value, binding.toolBar) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value) } @@ -467,18 +469,18 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { drawer = drawer { rootViewRes = R.id.drawer_layout - toolbar = toolBar + toolbar = binding.toolBar actionBarDrawerToggleEnabled = true actionBarDrawerToggleAnimated = true showOnFirstLaunch = true onSlide { _, p1 -> - bottomBar.alpha = (1 - p1) + binding.bottomBar.alpha = (1 - p1) } onClosed { - bottomBar.show() + binding.bottomBar.show() } onOpened { - bottomBar.hide() + binding.bottomBar.hide() } if (displayAccountHeader) { @@ -823,7 +825,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { } private fun reloadLayoutManager() { - val currentManager = recyclerView.layoutManager + val currentManager = binding.recyclerView.layoutManager val layoutManager: RecyclerView.LayoutManager // This will only update the layout manager if settings changed @@ -834,7 +836,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { this, calculateNoOfColumns() ) - recyclerView.layoutManager = layoutManager + binding.recyclerView.layoutManager = layoutManager } is GridLayoutManager -> if (shouldBeCardView) { @@ -844,7 +846,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { ) layoutManager.gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS - recyclerView.layoutManager = layoutManager + binding.recyclerView.layoutManager = layoutManager } else -> if (currentManager == null) { @@ -853,7 +855,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { this, calculateNoOfColumns() ) - recyclerView.layoutManager = layoutManager + binding.recyclerView.layoutManager = layoutManager } else { layoutManager = StaggeredGridLayoutManager( calculateNoOfColumns(), @@ -861,7 +863,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { ) layoutManager.gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS - recyclerView.layoutManager = layoutManager + binding.recyclerView.layoutManager = layoutManager } } else { } @@ -869,11 +871,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { } private fun handleBottomBarActions() { - bottomBar.setTabSelectedListener(object : BottomNavigationBar.OnTabSelectedListener { + binding.bottomBar.setTabSelectedListener(object : BottomNavigationBar.OnTabSelectedListener { override fun onTabUnselected(position: Int) = Unit override fun onTabReselected(position: Int) { - val layoutManager = recyclerView.adapter + val layoutManager = binding.recyclerView.adapter when (layoutManager) { is StaggeredGridLayoutManager -> @@ -898,8 +900,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { if (itemsCaching) { - if (!swipeRefreshLayout.isRefreshing) { - swipeRefreshLayout.post { swipeRefreshLayout.isRefreshing = true } + if (!binding.swipeRefreshLayout.isRefreshing) { + binding.swipeRefreshLayout.post { binding.swipeRefreshLayout.isRefreshing = true } } thread { @@ -951,7 +953,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { recyclerViewScrollListener = object : RecyclerView.OnScrollListener() { override fun onScrolled(localRecycler: RecyclerView, dx: Int, dy: Int) { if (dy > 0) { - val manager = recyclerView.layoutManager + val manager = binding.recyclerView.layoutManager val lastVisibleItem: Int = when (manager) { is StaggeredGridLayoutManager -> manager.findLastCompletelyVisibleItemPositions( null @@ -967,17 +969,17 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { } } - recyclerView.clearOnScrollListeners() - recyclerView.addOnScrollListener(recyclerViewScrollListener) + binding.recyclerView.clearOnScrollListeners() + binding.recyclerView.addOnScrollListener(recyclerViewScrollListener) } private fun mayBeEmpty() = if (items.isEmpty()) { - emptyText.visibility = View.VISIBLE - recyclerView.visibility = View.GONE + binding.emptyText.visibility = View.VISIBLE + binding.recyclerView.visibility = View.GONE } else { - emptyText.visibility = View.GONE - recyclerView.visibility = View.VISIBLE + binding.emptyText.visibility = View.GONE + binding.recyclerView.visibility = View.VISIBLE } private fun getElementsAccordingToTab( @@ -1002,8 +1004,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { if (itemsCaching) { - if (!swipeRefreshLayout.isRefreshing) { - swipeRefreshLayout.post { swipeRefreshLayout.isRefreshing = true } + if (!binding.swipeRefreshLayout.isRefreshing) { + binding.swipeRefreshLayout.post { binding.swipeRefreshLayout.isRefreshing = true } } thread { @@ -1073,11 +1075,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { handleListResult(appendResults) if (!appendResults) mayBeEmpty() - swipeRefreshLayout.isRefreshing = false + binding.swipeRefreshLayout.isRefreshing = false } - if (!swipeRefreshLayout.isRefreshing) { - swipeRefreshLayout.post { swipeRefreshLayout.isRefreshing = true } + if (!binding.swipeRefreshLayout.isRefreshing) { + binding.swipeRefreshLayout.post { binding.swipeRefreshLayout.isRefreshing = true } } if (this@HomeActivity.isNetworkAccessible(this@HomeActivity.findViewById(R.id.coordLayout), offlineShortcut)) { @@ -1091,7 +1093,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { } override fun onFailure(call: Call>, t: Throwable) { - swipeRefreshLayout.isRefreshing = false + binding.swipeRefreshLayout.isRefreshing = false Toast.makeText( this@HomeActivity, toastMessage, @@ -1100,7 +1102,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { } }) } else { - swipeRefreshLayout.post { swipeRefreshLayout.isRefreshing = false } + binding.swipeRefreshLayout.post { binding.swipeRefreshLayout.isRefreshing = false } } } @@ -1145,7 +1147,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { private fun handleListResult(appendResults: Boolean = false) { if (appendResults) { - val oldManager = recyclerView.layoutManager + val oldManager = binding.recyclerView.layoutManager firstVisible = when (oldManager) { is StaggeredGridLayoutManager -> oldManager.findFirstCompletelyVisibleItemPositions(null).last() @@ -1190,14 +1192,14 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { updateItems(it) } - recyclerView.addItemDecoration( + binding.recyclerView.addItemDecoration( DividerItemDecoration( this@HomeActivity, DividerItemDecoration.VERTICAL ) ) } - recyclerView.adapter = recyclerAdapter + binding.recyclerView.adapter = recyclerAdapter } else { if (!appendResults) { (recyclerAdapter as ItemsAdapter<*>).updateAllItems(items) @@ -1348,7 +1350,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { R.id.readAll -> { if (elementsShown == UNREAD_SHOWN) { needsConfirmation(R.string.readAll, R.string.markall_dialog_message) { - swipeRefreshLayout.isRefreshing = false + binding.swipeRefreshLayout.isRefreshing = false val ids = allItems.map { it.id } val itemsByTag: Map = allItems.flattenTags() @@ -1383,7 +1385,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { } - swipeRefreshLayout.isRefreshing = false + binding.swipeRefreshLayout.isRefreshing = false } override fun onFailure(call: Call, t: Throwable) { @@ -1392,7 +1394,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { R.string.all_posts_not_read, Toast.LENGTH_SHORT ).show() - swipeRefreshLayout.isRefreshing = false + binding.swipeRefreshLayout.isRefreshing = false } }) items = ArrayList() diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/ImageActivity.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/ImageActivity.kt index b0426fa..91f9624 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/ImageActivity.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/ImageActivity.kt @@ -5,27 +5,31 @@ import android.view.MenuItem import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentStatePagerAdapter +import apps.amine.bou.readerforselfoss.databinding.ActivityImageBinding import apps.amine.bou.readerforselfoss.fragments.ImageFragment -import kotlinx.android.synthetic.main.activity_reader.* class ImageActivity : AppCompatActivity() { private lateinit var allImages : ArrayList private var position : Int = 0 + private lateinit var binding: ActivityImageBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + binding = ActivityImageBinding.inflate(layoutInflater) + val view = binding.root - setContentView(R.layout.activity_image) + setContentView(view) - setSupportActionBar(toolBar) + setSupportActionBar(binding.toolBar) supportActionBar?.setDisplayShowTitleEnabled(false) supportActionBar?.setDisplayHomeAsUpEnabled(true) allImages = intent.getStringArrayListExtra("allImages") as ArrayList position = intent.getIntExtra("position", 0) - pager.adapter = ScreenSlidePagerAdapter(supportFragmentManager) - pager.currentItem = position + binding.pager.adapter = ScreenSlidePagerAdapter(supportFragmentManager) + binding.pager.currentItem = position } override fun onOptionsItemSelected(item: MenuItem): Boolean { 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 eeb7735..b66f713 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/LoginActivity.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/LoginActivity.kt @@ -17,13 +17,13 @@ import android.widget.TextView import android.widget.Toast import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse +import apps.amine.bou.readerforselfoss.databinding.ActivityLoginBinding import apps.amine.bou.readerforselfoss.themes.AppColors import apps.amine.bou.readerforselfoss.utils.Config import apps.amine.bou.readerforselfoss.utils.isBaseUrlValid import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible import com.mikepenz.aboutlibraries.Libs import com.mikepenz.aboutlibraries.LibsBuilder -import kotlinx.android.synthetic.main.activity_login.* import retrofit2.Call import retrofit2.Callback import retrofit2.Response @@ -39,15 +39,18 @@ class LoginActivity : AppCompatActivity() { private lateinit var editor: SharedPreferences.Editor private lateinit var userIdentifier: String private lateinit var appColors: AppColors + private lateinit var binding: ActivityLoginBinding override fun onCreate(savedInstanceState: Bundle?) { appColors = AppColors(this@LoginActivity) super.onCreate(savedInstanceState) + binding = ActivityLoginBinding.inflate(layoutInflater) + val view = binding.root - setContentView(R.layout.activity_login) + setContentView(view) - setSupportActionBar(toolbar) + setSupportActionBar(binding.toolbar) handleBaseUrlFail() @@ -65,14 +68,14 @@ class LoginActivity : AppCompatActivity() { private fun handleActions() { - withSelfhostedCert.setOnCheckedChangeListener { _, b -> + binding.withSelfhostedCert.setOnCheckedChangeListener { _, b -> isWithSelfSignedCert = !isWithSelfSignedCert val visi: Int = if (b) View.VISIBLE else View.GONE - warningText.visibility = visi + binding.warningText.visibility = visi } - passwordView.setOnEditorActionListener( + binding.passwordView.setOnEditorActionListener( TextView.OnEditorActionListener { _, id, _ -> if (id == R.id.loginView || id == EditorInfo.IME_NULL) { attemptLogin() @@ -82,22 +85,22 @@ class LoginActivity : AppCompatActivity() { } ) - signInButton.setOnClickListener { attemptLogin() } + binding.signInButton.setOnClickListener { attemptLogin() } - withLogin.setOnCheckedChangeListener { _, b -> + binding.withLogin.setOnCheckedChangeListener { _, b -> isWithLogin = !isWithLogin val visi: Int = if (b) View.VISIBLE else View.GONE - loginLayout.visibility = visi - passwordLayout.visibility = visi + binding.loginLayout.visibility = visi + binding.passwordLayout.visibility = visi } - withHttpLogin.setOnCheckedChangeListener { _, b -> + binding.withHttpLogin.setOnCheckedChangeListener { _, b -> isWithHTTPLogin = !isWithHTTPLogin val visi: Int = if (b) View.VISIBLE else View.GONE - httpLoginInput.visibility = visi - httpPasswordInput.visibility = visi + binding.httpLoginInput.visibility = visi + binding.httpPasswordInput.visibility = visi } } @@ -124,25 +127,25 @@ class LoginActivity : AppCompatActivity() { private fun attemptLogin() { // Reset errors. - urlView.error = null - loginView.error = null - httpLoginView.error = null - passwordView.error = null - httpPasswordView.error = null + binding.urlView.error = null + binding.loginView.error = null + binding.httpLoginView.error = null + binding.passwordView.error = null + binding.httpPasswordView.error = null // Store values at the time of the login attempt. - val url = urlView.text.toString() - val login = loginView.text.toString() - val httpLogin = httpLoginView.text.toString() - val password = passwordView.text.toString() - val httpPassword = httpPasswordView.text.toString() + val url = binding.urlView.text.toString() + val login = binding.loginView.text.toString() + val httpLogin = binding.httpLoginView.text.toString() + val password = binding.passwordView.text.toString() + val httpPassword = binding.httpPasswordView.text.toString() var cancel = false var focusView: View? = null if (!url.isBaseUrlValid(this@LoginActivity)) { - urlView.error = getString(R.string.login_url_problem) - focusView = urlView + binding.urlView.error = getString(R.string.login_url_problem) + focusView = binding.urlView cancel = true inValidCount++ if (inValidCount == 3) { @@ -161,28 +164,28 @@ class LoginActivity : AppCompatActivity() { if (isWithLogin) { if (TextUtils.isEmpty(password)) { - passwordView.error = getString(R.string.error_invalid_password) - focusView = passwordView + binding.passwordView.error = getString(R.string.error_invalid_password) + focusView = binding.passwordView cancel = true } if (TextUtils.isEmpty(login)) { - loginView.error = getString(R.string.error_field_required) - focusView = loginView + binding.loginView.error = getString(R.string.error_field_required) + focusView = binding.loginView cancel = true } } if (isWithHTTPLogin) { if (TextUtils.isEmpty(httpPassword)) { - httpPasswordView.error = getString(R.string.error_invalid_password) - focusView = httpPasswordView + binding.httpPasswordView.error = getString(R.string.error_invalid_password) + focusView = binding.httpPasswordView cancel = true } if (TextUtils.isEmpty(httpLogin)) { - httpLoginView.error = getString(R.string.error_field_required) - focusView = httpLoginView + binding.httpLoginView.error = getString(R.string.error_field_required) + focusView = binding.httpLoginView cancel = true } } @@ -216,11 +219,11 @@ class LoginActivity : AppCompatActivity() { editor.remove("password") editor.remove("httpPassword") editor.apply() - urlView.error = getString(R.string.wrong_infos) - loginView.error = getString(R.string.wrong_infos) - passwordView.error = getString(R.string.wrong_infos) - httpLoginView.error = getString(R.string.wrong_infos) - httpPasswordView.error = getString(R.string.wrong_infos) + binding.urlView.error = getString(R.string.wrong_infos) + binding.loginView.error = getString(R.string.wrong_infos) + binding.passwordView.error = getString(R.string.wrong_infos) + binding.httpLoginView.error = getString(R.string.wrong_infos) + binding.httpPasswordView.error = getString(R.string.wrong_infos) showProgress(false) } @@ -248,28 +251,28 @@ class LoginActivity : AppCompatActivity() { private fun showProgress(show: Boolean) { val shortAnimTime = resources.getInteger(android.R.integer.config_shortAnimTime) - loginForm.visibility = if (show) View.GONE else View.VISIBLE - loginForm + binding.loginForm.visibility = if (show) View.GONE else View.VISIBLE + binding.loginForm .animate() .setDuration(shortAnimTime.toLong()) .alpha( if (show) 0F else 1F ).setListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { - loginForm.visibility = if (show) View.GONE else View.VISIBLE + binding.loginForm.visibility = if (show) View.GONE else View.VISIBLE } } ) - loginProgress.visibility = if (show) View.VISIBLE else View.GONE - loginProgress + binding.loginProgress.visibility = if (show) View.VISIBLE else View.GONE + binding.loginProgress .animate() .setDuration(shortAnimTime.toLong()) .alpha( if (show) 1F else 0F ).setListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { - loginProgress.visibility = if (show) View.VISIBLE else View.GONE + binding.loginProgress.visibility = if (show) View.VISIBLE else View.GONE } } ) 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 93d54c5..d857b1b 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/MainActivity.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/MainActivity.kt @@ -4,12 +4,18 @@ import android.content.Intent import android.os.Bundle import android.preference.PreferenceManager import androidx.appcompat.app.AppCompatActivity +import apps.amine.bou.readerforselfoss.databinding.ActivityAddSourceBinding +import apps.amine.bou.readerforselfoss.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { + private lateinit var binding: ActivityMainBinding + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + binding = ActivityMainBinding.inflate(layoutInflater) + val view = binding.root + setContentView(view) val intent = Intent(this, LoginActivity::class.java) 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 0a0d11d..c496525 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/ReaderActivity.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/ReaderActivity.kt @@ -20,6 +20,8 @@ import androidx.room.Room 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.databinding.ActivityImageBinding +import apps.amine.bou.readerforselfoss.databinding.ActivityReaderBinding import apps.amine.bou.readerforselfoss.fragments.ArticleFragment import apps.amine.bou.readerforselfoss.persistence.database.AppDatabase import apps.amine.bou.readerforselfoss.persistence.entities.ActionEntity @@ -35,7 +37,6 @@ import apps.amine.bou.readerforselfoss.utils.persistence.toEntity import apps.amine.bou.readerforselfoss.utils.succeeded import apps.amine.bou.readerforselfoss.utils.toggleStar import com.ftinc.scoop.Scoop -import kotlinx.android.synthetic.main.activity_reader.* import me.relex.circleindicator.CircleIndicator import retrofit2.Call import retrofit2.Callback @@ -54,6 +55,7 @@ class ReaderActivity : AppCompatActivity() { private lateinit var db: AppDatabase private lateinit var prefs: SharedPreferences + private lateinit var binding: ActivityReaderBinding private var activeAlignment: Int = 1 val JUSTIFY = 1 @@ -76,8 +78,10 @@ class ReaderActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + binding = ActivityReaderBinding.inflate(layoutInflater) + val view = binding.root - setContentView(R.layout.activity_reader) + setContentView(view) db = Room.databaseBuilder( applicationContext, @@ -85,12 +89,12 @@ class ReaderActivity : AppCompatActivity() { ).addMigrations(MIGRATION_1_2).addMigrations(MIGRATION_2_3).addMigrations(MIGRATION_3_4).build() val scoop = Scoop.getInstance() - scoop.bind(this, Toppings.PRIMARY.value, toolBar) + scoop.bind(this, Toppings.PRIMARY.value, binding.toolBar) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value) } - setSupportActionBar(toolBar) + setSupportActionBar(binding.toolBar) supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayShowHomeEnabled(true) @@ -119,9 +123,9 @@ class ReaderActivity : AppCompatActivity() { readItem(allItems[currentItem]) - pager.adapter = + binding.pager.adapter = ScreenSlidePagerAdapter(supportFragmentManager, AppColors(this@ReaderActivity)) - pager.currentItem = currentItem + binding.pager.currentItem = currentItem } override fun onResume() { @@ -129,10 +133,10 @@ class ReaderActivity : AppCompatActivity() { notifyAdapter() - pager.setPageTransformer(true, DepthPageTransformer()) - (indicator as CircleIndicator).setViewPager(pager) + binding.pager.setPageTransformer(true, DepthPageTransformer()) + (binding.indicator as CircleIndicator).setViewPager(binding.pager) - pager.addOnPageChangeListener( + binding.pager.addOnPageChangeListener( object : ViewPager.SimpleOnPageChangeListener() { override fun onPageSelected(position: Int) { @@ -142,7 +146,7 @@ class ReaderActivity : AppCompatActivity() { } else { canFavorite() } - readItem(allItems[pager.currentItem]) + readItem(allItems[binding.pager.currentItem]) } } ) @@ -181,19 +185,19 @@ class ReaderActivity : AppCompatActivity() { } private fun notifyAdapter() { - (pager.adapter as ScreenSlidePagerAdapter).notifyDataSetChanged() + (binding.pager.adapter as ScreenSlidePagerAdapter).notifyDataSetChanged() } override fun onPause() { super.onPause() if (markOnScroll) { - pager.clearOnPageChangeListeners() + binding.pager.clearOnPageChangeListeners() } } override fun onSaveInstanceState(oldInstanceState: Bundle) { super.onSaveInstanceState(oldInstanceState) - oldInstanceState!!.clear() + oldInstanceState.clear() } private inner class ScreenSlidePagerAdapter(fm: FragmentManager, val appColors: AppColors) : @@ -245,14 +249,14 @@ class ReaderActivity : AppCompatActivity() { override fun onOptionsItemSelected(item: MenuItem): Boolean { fun afterSave() { - allItems[pager.currentItem] = - allItems[pager.currentItem].toggleStar() + allItems[binding.pager.currentItem] = + allItems[binding.pager.currentItem].toggleStar() notifyAdapter() canRemoveFromFavorite() } fun afterUnsave() { - allItems[pager.currentItem] = allItems[pager.currentItem].toggleStar() + allItems[binding.pager.currentItem] = allItems[binding.pager.currentItem].toggleStar() notifyAdapter() canFavorite() } @@ -264,7 +268,7 @@ class ReaderActivity : AppCompatActivity() { } R.id.save -> { if (this@ReaderActivity.isNetworkAccessible(null)) { - api.starrItem(allItems[pager.currentItem].id) + api.starrItem(allItems[binding.pager.currentItem].id) .enqueue(object : Callback { override fun onResponse( call: Call, @@ -286,14 +290,14 @@ class ReaderActivity : AppCompatActivity() { }) } else { thread { - db.actionsDao().insertAllActions(ActionEntity(allItems[pager.currentItem].id, false, false, true, false)) + db.actionsDao().insertAllActions(ActionEntity(allItems[binding.pager.currentItem].id, false, false, true, false)) afterSave() } } } R.id.unsave -> { if (this@ReaderActivity.isNetworkAccessible(null)) { - api.unstarrItem(allItems[pager.currentItem].id) + api.unstarrItem(allItems[binding.pager.currentItem].id) .enqueue(object : Callback { override fun onResponse( call: Call, @@ -315,7 +319,7 @@ class ReaderActivity : AppCompatActivity() { }) } else { thread { - db.actionsDao().insertAllActions(ActionEntity(allItems[pager.currentItem].id, false, false, false, true)) + db.actionsDao().insertAllActions(ActionEntity(allItems[binding.pager.currentItem].id, false, false, false, true)) afterUnsave() } } 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 4069aa2..80a9da3 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/SourcesActivity.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/SourcesActivity.kt @@ -12,12 +12,13 @@ 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.Source +import apps.amine.bou.readerforselfoss.databinding.ActivityImageBinding +import apps.amine.bou.readerforselfoss.databinding.ActivitySourcesBinding import apps.amine.bou.readerforselfoss.themes.AppColors import apps.amine.bou.readerforselfoss.themes.Toppings import apps.amine.bou.readerforselfoss.utils.Config import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible import com.ftinc.scoop.Scoop -import kotlinx.android.synthetic.main.activity_sources.* import retrofit2.Call import retrofit2.Callback import retrofit2.Response @@ -25,31 +26,34 @@ import retrofit2.Response class SourcesActivity : AppCompatActivity() { private lateinit var appColors: AppColors + private lateinit var binding: ActivitySourcesBinding override fun onCreate(savedInstanceState: Bundle?) { appColors = AppColors(this@SourcesActivity) super.onCreate(savedInstanceState) + binding = ActivitySourcesBinding.inflate(layoutInflater) + val view = binding.root - setContentView(R.layout.activity_sources) + setContentView(view) val scoop = Scoop.getInstance() - scoop.bind(this, Toppings.PRIMARY.value, toolbar) + scoop.bind(this, Toppings.PRIMARY.value, binding.toolbar) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value) } - setSupportActionBar(toolbar) + setSupportActionBar(binding.toolbar) supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayShowHomeEnabled(true) - fab.rippleColor = appColors.colorAccentDark - fab.backgroundTintList = ColorStateList.valueOf(appColors.colorAccent) + binding.fab.rippleColor = appColors.colorAccentDark + binding.fab.backgroundTintList = ColorStateList.valueOf(appColors.colorAccent) } override fun onStop() { super.onStop() - recyclerView.clearOnScrollListeners() + binding.recyclerView.clearOnScrollListeners() } override fun onResume() { @@ -68,8 +72,8 @@ class SourcesActivity : AppCompatActivity() { ) var items: ArrayList = ArrayList() - recyclerView.setHasFixedSize(true) - recyclerView.layoutManager = mLayoutManager + binding.recyclerView.setHasFixedSize(true) + binding.recyclerView.layoutManager = mLayoutManager if (this@SourcesActivity.isNetworkAccessible(this@SourcesActivity.findViewById(R.id.recyclerView))) { api.sources.enqueue(object : Callback> { @@ -81,7 +85,7 @@ class SourcesActivity : AppCompatActivity() { items = response.body() as ArrayList } val mAdapter = SourcesListAdapter(this@SourcesActivity, items, api) - recyclerView.adapter = mAdapter + binding.recyclerView.adapter = mAdapter mAdapter.notifyDataSetChanged() if (items.isEmpty()) { Toast.makeText( @@ -102,7 +106,7 @@ class SourcesActivity : AppCompatActivity() { }) } - fab.setOnClickListener { + binding.fab.setOnClickListener { startActivity(Intent(this@SourcesActivity, AddSourceActivity::class.java)) } } 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 afdc2a5..4b5897c 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 @@ -14,6 +14,7 @@ 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.databinding.CardItemBinding import apps.amine.bou.readerforselfoss.persistence.database.AppDatabase import apps.amine.bou.readerforselfoss.persistence.entities.ActionEntity import apps.amine.bou.readerforselfoss.themes.AppColors @@ -34,11 +35,6 @@ import com.amulyakhare.textdrawable.util.ColorGenerator import com.bumptech.glide.Glide import com.like.LikeButton import com.like.OnLikeListener -import kotlinx.android.synthetic.main.card_item.view.* -import kotlinx.android.synthetic.main.card_item.view.itemImage -import kotlinx.android.synthetic.main.card_item.view.sourceTitleAndDate -import kotlinx.android.synthetic.main.card_item.view.title -import kotlinx.android.synthetic.main.list_item.view.* import retrofit2.Call import retrofit2.Callback import retrofit2.Response @@ -64,77 +60,79 @@ class ItemCardAdapter( c.resources.getDimension(R.dimen.card_image_max_height).toInt() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - val v = LayoutInflater.from(c).inflate(R.layout.card_item, parent, false) as CardView - return ViewHolder(v) + val binding = CardItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return ViewHolder(binding) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { - val itm = items[position] + with(holder) { + val itm = items[position] - holder.mView.favButton.isLiked = itm.starred - holder.mView.title.text = itm.getTitleDecoded() - holder.mView.title.setTextColor(ContextCompat.getColor( - c, - appColors.textColor - )) - holder.mView.title.setOnTouchListener(LinkOnTouchListener()) + binding.favButton.isLiked = itm.starred + binding.title.text = itm.getTitleDecoded() + binding.title.setTextColor(ContextCompat.getColor( + c, + appColors.textColor + )) + binding.title.setOnTouchListener(LinkOnTouchListener()) - holder.mView.title.setLinkTextColor(appColors.colorAccent) + binding.title.setLinkTextColor(appColors.colorAccent) - holder.mView.sourceTitleAndDate.text = itm.sourceAndDateText() + binding.sourceTitleAndDate.text = itm.sourceAndDateText() - holder.mView.sourceTitleAndDate.setTextColor(ContextCompat.getColor( - c, - appColors.textColor - )) + binding.sourceTitleAndDate.setTextColor(ContextCompat.getColor( + c, + appColors.textColor + )) - if (!fullHeightCards) { - holder.mView.itemImage.maxHeight = imageMaxHeight - holder.mView.itemImage.scaleType = ScaleType.CENTER_CROP + if (!fullHeightCards) { + binding.itemImage.maxHeight = imageMaxHeight + binding.itemImage.scaleType = ScaleType.CENTER_CROP + } + + if (itm.getThumbnail(c).isEmpty()) { + binding.itemImage.visibility = View.GONE + Glide.with(c).clear(binding.itemImage) + binding.itemImage.setImageDrawable(null) + } else { + binding.itemImage.visibility = View.VISIBLE + c.bitmapCenterCrop(config, itm.getThumbnail(c), binding.itemImage) + } + + if (itm.getIcon(c).isEmpty()) { + val color = generator.getColor(itm.getSourceTitle()) + + val drawable = + TextDrawable + .builder() + .round() + .build(itm.getSourceTitle().toTextDrawableString(c), color) + binding.sourceImage.setImageDrawable(drawable) + } else { + c.circularBitmapDrawable(config, itm.getIcon(c), binding.sourceImage) + } + + binding.favButton.isLiked = itm.starred } - - if (itm.getThumbnail(c).isEmpty()) { - holder.mView.itemImage.visibility = View.GONE - Glide.with(c).clear(holder.mView.itemImage) - holder.mView.itemImage.setImageDrawable(null) - } else { - holder.mView.itemImage.visibility = View.VISIBLE - c.bitmapCenterCrop(config, itm.getThumbnail(c), holder.mView.itemImage) - } - - if (itm.getIcon(c).isEmpty()) { - val color = generator.getColor(itm.getSourceTitle()) - - val drawable = - TextDrawable - .builder() - .round() - .build(itm.getSourceTitle().toTextDrawableString(c), color) - holder.mView.sourceImage.setImageDrawable(drawable) - } else { - c.circularBitmapDrawable(config, itm.getIcon(c), holder.mView.sourceImage) - } - - holder.mView.favButton.isLiked = itm.starred } override fun getItemCount(): Int { return items.size } - inner class ViewHolder(val mView: CardView) : RecyclerView.ViewHolder(mView) { + inner class ViewHolder(val binding: CardItemBinding) : RecyclerView.ViewHolder(binding.root) { init { - mView.setCardBackgroundColor(appColors.cardBackgroundColor) + binding.root.setCardBackgroundColor(appColors.cardBackgroundColor) handleClickListeners() handleCustomTabActions() } private fun handleClickListeners() { - mView.favButton.setOnLikeListener(object : OnLikeListener { + binding.favButton.setOnLikeListener(object : OnLikeListener { override fun liked(likeButton: LikeButton) { - val (id) = items[adapterPosition] + val (id) = items[bindingAdapterPosition] if (c.isNetworkAccessible(null)) { api.starrItem(id).enqueue(object : Callback { override fun onResponse( @@ -147,7 +145,7 @@ class ItemCardAdapter( call: Call, t: Throwable ) { - mView.favButton.isLiked = false + binding.favButton.isLiked = false Toast.makeText( c, R.string.cant_mark_favortie, @@ -163,7 +161,7 @@ class ItemCardAdapter( } override fun unLiked(likeButton: LikeButton) { - val (id) = items[adapterPosition] + val (id) = items[bindingAdapterPosition] if (c.isNetworkAccessible(null)) { api.unstarrItem(id).enqueue(object : Callback { override fun onResponse( @@ -176,7 +174,7 @@ class ItemCardAdapter( call: Call, t: Throwable ) { - mView.favButton.isLiked = true + binding.favButton.isLiked = true Toast.makeText( c, R.string.cant_unmark_favortie, @@ -192,13 +190,13 @@ class ItemCardAdapter( } }) - mView.shareBtn.setOnClickListener { - val item = items[adapterPosition] + binding.shareBtn.setOnClickListener { + val item = items[bindingAdapterPosition] c.shareLink(item.getLinkDecoded(), item.getTitleDecoded()) } - mView.browserBtn.setOnClickListener { - c.openInBrowserAsNewTask(items[adapterPosition]) + binding.browserBtn.setOnClickListener { + c.openInBrowserAsNewTask(items[bindingAdapterPosition]) } } @@ -206,11 +204,11 @@ class ItemCardAdapter( val customTabsIntent = c.buildCustomTabsIntent() helper.bindCustomTabsService(app) - mView.setOnClickListener { + binding.root.setOnClickListener { c.openItemUrl( items, - adapterPosition, - items[adapterPosition].getLinkDecoded(), + bindingAdapterPosition, + items[bindingAdapterPosition].getLinkDecoded(), customTabsIntent, internalBrowser, articleViewer, diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/ItemListAdapter.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/ItemListAdapter.kt index 6e7c669..477d3b5 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/ItemListAdapter.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/ItemListAdapter.kt @@ -18,6 +18,7 @@ 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.databinding.ListItemBinding import apps.amine.bou.readerforselfoss.persistence.database.AppDatabase import apps.amine.bou.readerforselfoss.themes.AppColors import apps.amine.bou.readerforselfoss.utils.Config @@ -35,7 +36,6 @@ import com.amulyakhare.textdrawable.TextDrawable import com.amulyakhare.textdrawable.util.ColorGenerator import com.like.LikeButton import com.like.OnLikeListener -import kotlinx.android.synthetic.main.list_item.view.* import retrofit2.Call import retrofit2.Callback import retrofit2.Response @@ -59,59 +59,57 @@ class ItemListAdapter( private val c: Context = app.baseContext override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - val v = LayoutInflater.from(c).inflate( - R.layout.list_item, - parent, - false - ) as ConstraintLayout - return ViewHolder(v) + val binding = ListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return ViewHolder(binding) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { - val itm = items[position] + with(holder) { + val itm = items[position] - holder.mView.title.text = itm.getTitleDecoded() + binding.title.text = itm.getTitleDecoded() - holder.mView.title.setTextColor(ContextCompat.getColor( - c, - appColors.textColor - )) + binding.title.setTextColor(ContextCompat.getColor( + c, + appColors.textColor + )) - holder.mView.title.setOnTouchListener(LinkOnTouchListener()) + binding.title.setOnTouchListener(LinkOnTouchListener()) - holder.mView.title.setLinkTextColor(appColors.colorAccent) + binding.title.setLinkTextColor(appColors.colorAccent) - holder.mView.sourceTitleAndDate.text = itm.sourceAndDateText() + binding.sourceTitleAndDate.text = itm.sourceAndDateText() - holder.mView.sourceTitleAndDate.setTextColor(ContextCompat.getColor( - c, - appColors.textColor - )) + binding.sourceTitleAndDate.setTextColor(ContextCompat.getColor( + c, + appColors.textColor + )) - if (itm.getThumbnail(c).isEmpty()) { + if (itm.getThumbnail(c).isEmpty()) { - if (itm.getIcon(c).isEmpty()) { - val color = generator.getColor(itm.getSourceTitle()) + if (itm.getIcon(c).isEmpty()) { + val color = generator.getColor(itm.getSourceTitle()) - val drawable = - TextDrawable - .builder() - .round() - .build(itm.getSourceTitle().toTextDrawableString(c), color) + val drawable = + TextDrawable + .builder() + .round() + .build(itm.getSourceTitle().toTextDrawableString(c), color) - holder.mView.itemImage.setImageDrawable(drawable) + binding.itemImage.setImageDrawable(drawable) + } else { + c.circularBitmapDrawable(config, itm.getIcon(c), binding.itemImage) + } } else { - c.circularBitmapDrawable(config, itm.getIcon(c), holder.mView.itemImage) + c.bitmapCenterCrop(config, itm.getThumbnail(c), binding.itemImage) } - } else { - c.bitmapCenterCrop(config, itm.getThumbnail(c), holder.mView.itemImage) } } override fun getItemCount(): Int = items.size - inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) { + inner class ViewHolder(val binding: ListItemBinding) : RecyclerView.ViewHolder(binding.root) { init { handleCustomTabActions() @@ -121,11 +119,11 @@ class ItemListAdapter( val customTabsIntent = c.buildCustomTabsIntent() helper.bindCustomTabsService(app) - mView.setOnClickListener { + binding.root.setOnClickListener { c.openItemUrl( items, - adapterPosition, - items[adapterPosition].getLinkDecoded(), + bindingAdapterPosition, + items[bindingAdapterPosition].getLinkDecoded(), customTabsIntent, internalBrowser, articleViewer, diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/SourcesListAdapter.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/SourcesListAdapter.kt index 505ef32..5f2806e 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/SourcesListAdapter.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/SourcesListAdapter.kt @@ -12,13 +12,13 @@ import apps.amine.bou.readerforselfoss.R import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi import apps.amine.bou.readerforselfoss.api.selfoss.Source import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse +import apps.amine.bou.readerforselfoss.databinding.SourceListItemBinding import apps.amine.bou.readerforselfoss.utils.Config import apps.amine.bou.readerforselfoss.utils.glide.circularBitmapDrawable import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible import apps.amine.bou.readerforselfoss.utils.toTextDrawableString import com.amulyakhare.textdrawable.TextDrawable import com.amulyakhare.textdrawable.util.ColorGenerator -import kotlinx.android.synthetic.main.source_list_item.view.* import retrofit2.Call import retrofit2.Callback import retrofit2.Response @@ -31,14 +31,11 @@ class SourcesListAdapter( private val c: Context = app.baseContext private val generator: ColorGenerator = ColorGenerator.MATERIAL private lateinit var config: Config + private lateinit var binding: SourceListItemBinding override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - val v = LayoutInflater.from(c).inflate( - R.layout.source_list_item, - parent, - false - ) as ConstraintLayout - return ViewHolder(v) + binding = SourceListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return ViewHolder(binding.root) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { @@ -53,12 +50,12 @@ class SourcesListAdapter( .builder() .round() .build(itm.getTitleDecoded().toTextDrawableString(c), color) - holder.mView.itemImage.setImageDrawable(drawable) + binding.itemImage.setImageDrawable(drawable) } else { - c.circularBitmapDrawable(config, itm.getIcon(c), holder.mView.itemImage) + c.circularBitmapDrawable(config, itm.getIcon(c), binding.itemImage) } - holder.mView.sourceTitle.text = itm.getTitleDecoded() + binding.sourceTitle.text = itm.getTitleDecoded() } override fun getItemCount(): Int = items.size diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ArticleFragment.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ArticleFragment.kt index 8007a84..f3fd9a0 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ArticleFragment.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ArticleFragment.kt @@ -29,6 +29,7 @@ import apps.amine.bou.readerforselfoss.api.mercury.ParsedContent 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.databinding.FragmentArticleBinding import apps.amine.bou.readerforselfoss.persistence.database.AppDatabase import apps.amine.bou.readerforselfoss.persistence.entities.ActionEntity import apps.amine.bou.readerforselfoss.persistence.migrations.MIGRATION_1_2 @@ -50,7 +51,6 @@ import com.bumptech.glide.Glide import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.request.RequestOptions import com.github.rubensousa.floatingtoolbar.FloatingToolbar -import kotlinx.android.synthetic.main.fragment_article.view.* import retrofit2.Call import retrofit2.Callback import retrofit2.Response @@ -77,8 +77,8 @@ class ArticleFragment : Fragment() { private lateinit var db: AppDatabase private lateinit var textAlignment: String private lateinit var config: Config - - private var rootView: ViewGroup? = null + private var _binding: FragmentArticleBinding? = null + private val binding get() = _binding!! private lateinit var prefs: SharedPreferences @@ -94,16 +94,16 @@ class ArticleFragment : Fragment() { } override fun onCreate(savedInstanceState: Bundle?) { - appColors = AppColors(activity!!) - config = Config(activity!!) + appColors = AppColors(requireActivity()) + config = Config(requireActivity()) super.onCreate(savedInstanceState) - pageNumber = arguments!!.getInt(ARG_POSITION) - allItems = arguments!!.getParcelableArrayList(ARG_ITEMS) as ArrayList + pageNumber = requireArguments().getInt(ARG_POSITION) + allItems = requireArguments().getParcelableArrayList(ARG_ITEMS) as ArrayList db = Room.databaseBuilder( - context!!, + requireContext(), AppDatabase::class.java, "selfoss-database" ).addMigrations(MIGRATION_1_2).addMigrations(MIGRATION_2_3).addMigrations(MIGRATION_3_4).build() } @@ -114,13 +114,12 @@ class ArticleFragment : Fragment() { savedInstanceState: Bundle? ): View? { try { - rootView = inflater - .inflate(R.layout.fragment_article, container, false) as ViewGroup + _binding = FragmentArticleBinding.inflate(inflater, container, false) url = allItems[pageNumber.toInt()].getLinkDecoded() contentText = allItems[pageNumber.toInt()].content contentTitle = allItems[pageNumber.toInt()].getTitleDecoded() - contentImage = allItems[pageNumber.toInt()].getThumbnail(activity!!) + contentImage = allItems[pageNumber.toInt()].getThumbnail(requireActivity()) contentSource = allItems[pageNumber.toInt()].sourceAndDateText() allImages = allItems[pageNumber.toInt()].getImages() @@ -130,11 +129,11 @@ class ArticleFragment : Fragment() { font = prefs.getString("reader_font", "")!! if (font.isNotEmpty()) { - resId = context!!.resources.getIdentifier(font, "font", context!!.packageName) + resId = requireContext().resources.getIdentifier(font, "font", requireContext().packageName) typeface = try { - ResourcesCompat.getFont(context!!, resId)!! + ResourcesCompat.getFont(requireContext(), resId)!! } catch (e: java.lang.Exception) { - // ACRA.getErrorReporter().maybeHandleSilentException(Throwable("Font loading issue: ${e.message}"), context!!) + // ACRA.getErrorReporter().maybeHandleSilentException(Throwable("Font loading issue: ${e.message}"), requireContext()) // Just to be sure null } @@ -142,27 +141,27 @@ class ArticleFragment : Fragment() { refreshAlignment() - val settings = activity!!.getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE) + val settings = requireActivity().getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE) val api = SelfossApi( - context!!, - activity!!, + requireContext(), + requireActivity(), settings.getBoolean("isSelfSignedCert", false), prefs.getString("api_timeout", "-1")!!.toLong() ) - fab = rootView!!.fab + fab = binding.fab fab.backgroundTintList = ColorStateList.valueOf(appColors.colorAccent) fab.rippleColor = appColors.colorAccentDark - val floatingToolbar: FloatingToolbar = rootView!!.floatingToolbar + val floatingToolbar: FloatingToolbar = binding.floatingToolbar floatingToolbar.attachFab(fab) floatingToolbar.background = ColorDrawable(appColors.colorAccent) - val customTabsIntent = activity!!.buildCustomTabsIntent() + val customTabsIntent = requireActivity().buildCustomTabsIntent() mCustomTabActivityHelper = CustomTabActivityHelper() mCustomTabActivityHelper!!.bindCustomTabsService(activity) @@ -172,17 +171,17 @@ class ArticleFragment : Fragment() { override fun onItemClick(item: MenuItem) { when (item.itemId) { R.id.more_action -> getContentFromMercury(customTabsIntent, prefs) - R.id.share_action -> activity!!.shareLink(url, contentTitle) - R.id.open_action -> activity!!.openItemUrl( + R.id.share_action -> requireActivity().shareLink(url, contentTitle) + R.id.open_action -> requireActivity().openItemUrl( allItems, pageNumber.toInt(), url, customTabsIntent, false, false, - activity!! + requireActivity() ) - R.id.unread_action -> if ((context != null && context!!.isNetworkAccessible(null)) || context == null) { + R.id.unread_action -> if ((context != null && requireContext().isNetworkAccessible(null)) || context == null) { api.unmarkItem(allItems[pageNumber.toInt()].id).enqueue( object : Callback { override fun onResponse( @@ -212,35 +211,35 @@ class ArticleFragment : Fragment() { } ) - rootView!!.source.text = contentSource + binding.source.text = contentSource if (typeface != null) { - rootView!!.source.typeface = typeface + binding.source.typeface = typeface } if (contentText.isEmptyOrNullOrNullString()) { getContentFromMercury(customTabsIntent, prefs) } else { - rootView!!.titleView.text = contentTitle + binding.titleView.text = contentTitle if (typeface != null) { - rootView!!.titleView.typeface = typeface + binding.titleView.typeface = typeface } htmlToWebview() if (!contentImage.isEmptyOrNullOrNullString() && context != null) { - rootView!!.imageView.visibility = View.VISIBLE + binding.imageView.visibility = View.VISIBLE Glide - .with(context!!) + .with(requireContext()) .asBitmap() .loadMaybeBasicAuth(config, contentImage) .apply(RequestOptions.fitCenterTransform()) - .into(rootView!!.imageView) + .into(binding.imageView) } else { - rootView!!.imageView.visibility = View.GONE + binding.imageView.visibility = View.GONE } } - rootView!!.nestedScrollView.setOnScrollChangeListener( + binding.nestedScrollView.setOnScrollChangeListener( NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY -> if (scrollY > oldScrollY) { fab.hide() @@ -251,22 +250,27 @@ class ArticleFragment : Fragment() { ) } catch (e: InflateException) { - AlertDialog.Builder(context!!) - .setMessage(context!!.getString(R.string.webview_dialog_issue_message)) - .setTitle(context!!.getString(R.string.webview_dialog_issue_title)) + AlertDialog.Builder(requireContext()) + .setMessage(requireContext().getString(R.string.webview_dialog_issue_message)) + .setTitle(requireContext().getString(R.string.webview_dialog_issue_title)) .setPositiveButton(android.R.string.ok ) { dialog, which -> - val sharedPref = PreferenceManager.getDefaultSharedPreferences(context!!) + val sharedPref = PreferenceManager.getDefaultSharedPreferences(requireContext()) val editor = sharedPref.edit() editor.putBoolean("prefer_article_viewer", false) editor.commit() - activity!!.finish() + requireActivity().finish() } .create() .show() } - return rootView + return binding.root + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null } private fun refreshAlignment() { @@ -281,8 +285,8 @@ class ArticleFragment : Fragment() { customTabsIntent: CustomTabsIntent, prefs: SharedPreferences ) { - if ((context != null && context!!.isNetworkAccessible(null)) || context == null) { - rootView!!.progressBar.visibility = View.VISIBLE + if ((context != null && requireContext().isNetworkAccessible(null)) || context == null) { + binding.progressBar.visibility = View.VISIBLE val parser = MercuryApi() parser.parseUrl(url).enqueue( @@ -295,9 +299,9 @@ class ArticleFragment : Fragment() { try { if (response.body() != null && response.body()!!.content != null && !response.body()!!.content.isNullOrEmpty()) { try { - rootView!!.titleView.text = response.body()!!.title + binding.titleView.text = response.body()!!.title if (typeface != null) { - rootView!!.titleView.typeface = typeface + binding.titleView.typeface = typeface } try { // Note: Mercury may return relative urls... If it does the url val will not be changed. @@ -317,18 +321,18 @@ class ArticleFragment : Fragment() { try { if (response.body()!!.lead_image_url != null && !response.body()!!.lead_image_url.isNullOrEmpty() && context != null) { - rootView!!.imageView.visibility = View.VISIBLE + binding.imageView.visibility = View.VISIBLE try { Glide - .with(context!!) + .with(requireContext()) .asBitmap() .loadMaybeBasicAuth(config, response.body()!!.lead_image_url.orEmpty()) .apply(RequestOptions.fitCenterTransform()) - .into(rootView!!.imageView) + .into(binding.imageView) } catch (e: Exception) { } } else { - rootView!!.imageView.visibility = View.GONE + binding.imageView.visibility = View.GONE } } catch (e: Exception) { if (context != null) { @@ -336,9 +340,9 @@ class ArticleFragment : Fragment() { } try { - rootView!!.nestedScrollView.scrollTo(0, 0) + binding.nestedScrollView.scrollTo(0, 0) - rootView!!.progressBar.visibility = View.GONE + binding.progressBar.visibility = View.GONE } catch (e: Exception) { if (context != null) { } @@ -370,32 +374,32 @@ class ArticleFragment : Fragment() { val stringColor = String.format("#%06X", 0xFFFFFF and appColors.colorAccent) val attrs: IntArray = intArrayOf(android.R.attr.fontFamily) - val a: TypedArray = context!!.obtainStyledAttributes(resId, attrs) + val a: TypedArray = requireContext().obtainStyledAttributes(resId, attrs) - rootView!!.webcontent.settings.standardFontFamily = a.getString(0) - rootView!!.webcontent.visibility = View.VISIBLE + binding.webcontent.settings.standardFontFamily = a.getString(0) + binding.webcontent.visibility = View.VISIBLE val (textColor, backgroundColor) = if (appColors.isDarkTheme) { if (context != null) { - rootView!!.webcontent.setBackgroundColor( + binding.webcontent.setBackgroundColor( ContextCompat.getColor( - context!!, + requireContext(), R.color.dark_webview ) ) - Pair(ContextCompat.getColor(context!!, R.color.dark_webview_text), ContextCompat.getColor(context!!, R.color.dark_webview)) + Pair(ContextCompat.getColor(requireContext(), R.color.dark_webview_text), ContextCompat.getColor(requireContext(), R.color.dark_webview)) } else { Pair(null, null) } } else { if (context != null) { - rootView!!.webcontent.setBackgroundColor( + binding.webcontent.setBackgroundColor( ContextCompat.getColor( - context!!, + requireContext(), R.color.light_webview ) ) - Pair(ContextCompat.getColor(context!!, R.color.light_webview_text), ContextCompat.getColor(context!!, R.color.light_webview)) + Pair(ContextCompat.getColor(requireContext(), R.color.light_webview_text), ContextCompat.getColor(requireContext(), R.color.light_webview)) } else { Pair(null, null) } @@ -413,14 +417,14 @@ class ArticleFragment : Fragment() { "#FFFFFF" } - rootView!!.webcontent.settings.useWideViewPort = true - rootView!!.webcontent.settings.loadWithOverviewMode = true - rootView!!.webcontent.settings.javaScriptEnabled = false + binding.webcontent.settings.useWideViewPort = true + binding.webcontent.settings.loadWithOverviewMode = true + binding.webcontent.settings.javaScriptEnabled = false - rootView!!.webcontent.webViewClient = object : WebViewClient() { + binding.webcontent.webViewClient = object : WebViewClient() { override fun shouldOverrideUrlLoading(view: WebView?, url : String): Boolean { - if (rootView!!.webcontent.hitTestResult.type != WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) { - rootView!!.context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url))) + if (binding.webcontent.hitTestResult.type != WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) { + requireContext().startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url))) } return true } @@ -456,13 +460,13 @@ class ArticleFragment : Fragment() { } }) - rootView!!.webcontent.setOnTouchListener { _, event -> gestureDetector.onTouchEvent(event)} + binding.webcontent.setOnTouchListener { _, event -> gestureDetector.onTouchEvent(event)} if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - rootView!!.webcontent.settings.layoutAlgorithm = + binding.webcontent.settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING } else { - rootView!!.webcontent.settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN + binding.webcontent.settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN } var baseUrl: String? = null @@ -491,7 +495,7 @@ class ArticleFragment : Fragment() { "" } - rootView!!.webcontent.loadDataWithBaseURL( + binding.webcontent.loadDataWithBaseURL( baseUrl, """ | @@ -544,15 +548,15 @@ class ArticleFragment : Fragment() { } private fun openInBrowserAfterFailing(customTabsIntent: CustomTabsIntent) { - rootView!!.progressBar.visibility = View.GONE - activity!!.openItemUrl( + binding.progressBar.visibility = View.GONE + requireActivity().openItemUrl( allItems, pageNumber.toInt(), url, customTabsIntent, true, false, - activity!! + requireActivity() ) } @@ -574,10 +578,10 @@ class ArticleFragment : Fragment() { } fun performClick(): Boolean { - if (rootView!!.webcontent.hitTestResult.type == WebView.HitTestResult.IMAGE_TYPE || - rootView!!.webcontent.hitTestResult.type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) { + if (binding.webcontent.hitTestResult.type == WebView.HitTestResult.IMAGE_TYPE || + binding.webcontent.hitTestResult.type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) { - val position : Int = allImages.indexOf(rootView!!.webcontent.hitTestResult.extra) + val position : Int = allImages.indexOf(binding.webcontent.hitTestResult.extra) val intent = Intent(activity, ImageActivity::class.java) intent.putExtra("allImages", allImages) diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ImageFragment.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ImageFragment.kt index e8ea0c5..04ca538 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ImageFragment.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ImageFragment.kt @@ -4,15 +4,17 @@ import android.os.Bundle import android.view.* import androidx.fragment.app.Fragment import apps.amine.bou.readerforselfoss.R +import apps.amine.bou.readerforselfoss.databinding.FragmentImageBinding import com.bumptech.glide.Glide import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.request.RequestOptions -import kotlinx.android.synthetic.main.fragment_image.view.* 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 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -21,18 +23,24 @@ class ImageFragment : Fragment() { } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val view : View = inflater.inflate(R.layout.fragment_image, container, false) + _binding = FragmentImageBinding.inflate(inflater, container, false) + val view = binding?.root - view.photoView.visibility = View.VISIBLE + binding!!.photoView.visibility = View.VISIBLE Glide.with(activity) .asBitmap() .apply(glideOptions) .load(imageUrl) - .into(view.photoView) + .into(binding!!.photoView) return view } + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + companion object { private const val ARG_IMAGE = "imageUrl"