diff --git a/app/build.gradle b/app/build.gradle index 236c79e6..e4c001ff 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -50,12 +50,15 @@ android { kotlinOptions { jvmTarget = "1.8" } + viewBinding { + enabled = true + } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "com.google.android.material:material:$material" - implementation "androidx.appcompat:appcompat:$supportLib" + implementation "androidx.appcompat:appcompat:$appCompat" implementation "androidx.legacy:legacy-support-v4:$supportLib" implementation "androidx.constraintlayout:constraintlayout:$constraintLayout" diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/AboutFragment.kt b/app/src/main/java/com/rtbishop/look4sat/ui/AboutFragment.kt index 767d7e42..3e286383 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/AboutFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/AboutFragment.kt @@ -24,31 +24,34 @@ import android.text.method.LinkMovementMethod import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.TextView import androidx.fragment.app.Fragment import com.rtbishop.look4sat.BuildConfig import com.rtbishop.look4sat.R +import com.rtbishop.look4sat.databinding.FragmentAboutBinding class AboutFragment : Fragment() { - private lateinit var textVersion: TextView - private lateinit var textThanks: TextView + private var _binding: FragmentAboutBinding? = null + private val binding get() = _binding!! override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { - return inflater.inflate(R.layout.fragment_about, container, false) + _binding = FragmentAboutBinding.inflate(inflater, container, false) + return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + binding.tvAboutVersion.text = + String.format(getString(R.string.app_version), BuildConfig.VERSION_NAME) + binding.tvAboutMessage.movementMethod = LinkMovementMethod.getInstance() + } - textVersion = view.findViewById(R.id.about_title_version) - textThanks = view.findViewById(R.id.about_thanks_to) - - textVersion.text = String.format(getString(R.string.app_version), BuildConfig.VERSION_NAME) - textThanks.movementMethod = LinkMovementMethod.getInstance() + override fun onDestroyView() { + _binding = null + super.onDestroyView() } } diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/MainActivity.kt b/app/src/main/java/com/rtbishop/look4sat/ui/MainActivity.kt index 3f0d10fe..a67e00e6 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/MainActivity.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/MainActivity.kt @@ -27,15 +27,10 @@ import android.content.pm.PackageManager import android.net.Uri import android.os.Bundle import android.view.View -import android.widget.Button -import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.widget.Toolbar -import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat -import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import androidx.navigation.findNavController @@ -43,9 +38,10 @@ import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.navigateUp import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupWithNavController -import com.google.android.material.navigation.NavigationView import com.rtbishop.look4sat.MainViewModel import com.rtbishop.look4sat.R +import com.rtbishop.look4sat.databinding.ActivityMainBinding +import com.rtbishop.look4sat.databinding.DrawerHeaderBinding class MainActivity : AppCompatActivity() { @@ -54,22 +50,17 @@ class MainActivity : AppCompatActivity() { private val permGranted = PackageManager.PERMISSION_GRANTED private val githubUrl = "https://github.com/rt-bishop/LookingSat" + private lateinit var mainBinding: ActivityMainBinding + private lateinit var drawerBinding: DrawerHeaderBinding private lateinit var viewModel: MainViewModel - private lateinit var timerLayout: ConstraintLayout - private lateinit var drawerLayout: DrawerLayout - private lateinit var drawerLat: TextView - private lateinit var drawerLon: TextView - private lateinit var drawerBtnLoc: Button - private lateinit var drawerBtnTle: Button - private lateinit var drawerBtnTrans: Button - private lateinit var drawerBtnGithub: Button - private lateinit var drawerBtnExit: Button private lateinit var appBarConfig: AppBarConfiguration override fun onCreate(savedInstanceState: Bundle?) { setTheme(R.style.AppTheme) super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + mainBinding = ActivityMainBinding.inflate(layoutInflater) + drawerBinding = DrawerHeaderBinding.inflate(layoutInflater, mainBinding.navView, true) + setContentView(mainBinding.root) viewModel = ViewModelProvider(this).get(MainViewModel::class.java) setupComponents() setupObservers() @@ -79,24 +70,13 @@ class MainActivity : AppCompatActivity() { @SuppressLint("SourceLockedOrientationActivity") private fun setupComponents() { val navController = findNavController(R.id.nav_host) - val navView: NavigationView = findViewById(R.id.nav_view) - val header = navView.getHeaderView(0) - val toolbar: Toolbar = findViewById(R.id.toolbar) + val navView = mainBinding.navView + val toolbar = mainBinding.includeAppBar.toolbar setSupportActionBar(toolbar) - timerLayout = findViewById(R.id.toolbar_layout) - drawerLayout = findViewById(R.id.drawer_layout) - drawerLat = header.findViewById(R.id.drawer_lat_value) - drawerLon = header.findViewById(R.id.drawer_lon_value) - drawerBtnLoc = header.findViewById(R.id.drawer_btn_loc) - drawerBtnTle = header.findViewById(R.id.drawer_btn_tle) - drawerBtnTrans = header.findViewById(R.id.drawer_btn_trans) - drawerBtnGithub = header.findViewById(R.id.drawer_btn_github) - drawerBtnExit = header.findViewById(R.id.drawer_btn_exit) - appBarConfig = AppBarConfiguration( setOf(R.id.nav_pass_list, R.id.nav_map_view, R.id.nav_settings, R.id.nav_about), - drawerLayout + mainBinding.drawerLayout ) setupActionBarWithNavController(navController, appBarConfig) @@ -107,7 +87,7 @@ class MainActivity : AppCompatActivity() { R.id.nav_pass_list -> { this.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT toolbar.visibility = View.VISIBLE - timerLayout.visibility = View.VISIBLE + mainBinding.includeAppBar.toolbarLayout.visibility = View.VISIBLE } R.id.nav_map_view -> { this.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE @@ -116,7 +96,7 @@ class MainActivity : AppCompatActivity() { else -> { this.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT toolbar.visibility = View.VISIBLE - timerLayout.visibility = View.GONE + mainBinding.includeAppBar.toolbarLayout.visibility = View.GONE } } } @@ -126,40 +106,45 @@ class MainActivity : AppCompatActivity() { viewModel.debugMessage.observe(this, Observer { message -> Toast.makeText(this, message, Toast.LENGTH_SHORT).show() when (message) { - getString(R.string.update_loc_success) -> drawerBtnLoc.isEnabled = true - getString(R.string.update_tle_success) -> drawerBtnTle.isEnabled = true - getString(R.string.update_trans_success) -> drawerBtnTrans.isEnabled = true + getString(R.string.update_loc_success) -> drawerBinding.drawerBtnLoc.isEnabled = + true + getString(R.string.update_tle_success) -> drawerBinding.drawerBtnTle.isEnabled = + true + getString(R.string.update_trans_success) -> drawerBinding.drawerBtnTrans.isEnabled = + true getString(R.string.update_failure) -> { - drawerBtnTle.isEnabled = true - drawerBtnTrans.isEnabled = true + drawerBinding.drawerBtnTle.isEnabled = true + drawerBinding.drawerBtnTrans.isEnabled = true } } }) viewModel.gsp.observe(this, Observer { gsp -> - drawerLat.text = String.format(getString(R.string.pat_location), gsp.latitude) - drawerLon.text = String.format(getString(R.string.pat_location), gsp.longitude) + drawerBinding.drawerLatValue.text = + String.format(getString(R.string.pat_location), gsp.latitude) + drawerBinding.drawerLonValue.text = + String.format(getString(R.string.pat_location), gsp.longitude) }) } private fun setupDrawer() { - drawerBtnLoc.setOnClickListener { + drawerBinding.drawerBtnLoc.setOnClickListener { it.isEnabled = false requestLocationUpdate() } - drawerBtnTle.setOnClickListener { + drawerBinding.drawerBtnTle.setOnClickListener { it.isEnabled = false viewModel.updateAndSaveTleFile() } - drawerBtnTrans.setOnClickListener { + drawerBinding.drawerBtnTrans.setOnClickListener { it.isEnabled = false viewModel.updateTransmittersDatabase() } - drawerBtnGithub.setOnClickListener { + drawerBinding.drawerBtnGithub.setOnClickListener { val githubIntent = Intent(Intent.ACTION_VIEW, Uri.parse(githubUrl)) startActivity(githubIntent) } - drawerBtnExit.setOnClickListener { finish() } + drawerBinding.drawerBtnExit.setOnClickListener { finish() } } private fun requestLocationUpdate() { diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/MapViewFragment.kt b/app/src/main/java/com/rtbishop/look4sat/ui/MapViewFragment.kt index 72c6e497..446b7be4 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/MapViewFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/MapViewFragment.kt @@ -25,8 +25,6 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.FrameLayout -import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.core.content.ContextCompat @@ -36,9 +34,9 @@ import com.github.amsacode.predict4java.GroundStationPosition import com.github.amsacode.predict4java.Position import com.github.amsacode.predict4java.SatPos import com.github.amsacode.predict4java.TLE -import com.google.android.material.floatingactionbutton.FloatingActionButton import com.rtbishop.look4sat.MainViewModel import com.rtbishop.look4sat.R +import com.rtbishop.look4sat.databinding.FragmentMapViewBinding import com.rtbishop.look4sat.predict4kotlin.PassPredictor import com.rtbishop.look4sat.repo.SatPass import java.util.* @@ -49,15 +47,13 @@ import kotlin.math.abs class MapViewFragment : Fragment() { + private var _binding: FragmentMapViewBinding? = null + private val binding get() = _binding!! + private lateinit var service: ScheduledExecutorService private lateinit var mainActivity: MainActivity private lateinit var viewModel: MainViewModel - private lateinit var mapFrame: FrameLayout - private lateinit var mapFab: FloatingActionButton private lateinit var mapView: MapView - private lateinit var mapLat: TextView - private lateinit var mapLon: TextView - private lateinit var mapRng: TextView private lateinit var predictor: PassPredictor private lateinit var selectedSat: TLE private lateinit var gsp: GroundStationPosition @@ -76,23 +72,15 @@ class MapViewFragment : Fragment() { container: ViewGroup?, savedInstanceState: Bundle? ): View? { - return inflater.inflate(R.layout.fragment_map_view, container, false) + _binding = FragmentMapViewBinding.inflate(layoutInflater, container, false) + return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - findViews(view) setupComponents() } - private fun findViews(view: View) { - mapFrame = view.findViewById(R.id.map_frame) - mapFab = view.findViewById(R.id.map_fab) - mapLat = view.findViewById(R.id.map_lat) - mapLon = view.findViewById(R.id.map_lon) - mapRng = view.findViewById(R.id.map_rng) - } - private fun setupComponents() { val delay = viewModel.delay gsp = viewModel.gsp.value ?: GroundStationPosition(0.0, 0.0, 0.0) @@ -101,11 +89,11 @@ class MapViewFragment : Fragment() { if (satPassList.isNotEmpty()) { satPassList = satPassList.distinctBy { it.tle } satPassList = satPassList.sortedBy { it.tle.name } - mapFab.setOnClickListener { showSelectSatDialog(satPassList) } + binding.fabMap.setOnClickListener { showSelectSatDialog(satPassList) } selectedSat = satPassList.first().tle predictor = satPassList.first().predictor mapView = MapView(mainActivity) - mapFrame.addView(mapView) + binding.frameMap.addView(mapView) service.scheduleAtFixedRate( { mapView.invalidate() }, delay, @@ -113,7 +101,7 @@ class MapViewFragment : Fragment() { TimeUnit.MILLISECONDS ) } else { - mapFab.setOnClickListener { + binding.fabMap.setOnClickListener { Toast.makeText( mainActivity, getString(R.string.err_no_sat_selected), @@ -209,9 +197,9 @@ class MapViewFragment : Fragment() { if (lon > 180f) lon -= 360f - mapLat.text = String.format(context.getString(R.string.pat_latitude), lat) - mapLon.text = String.format(context.getString(R.string.pat_longitude), lon) - mapRng.text = String.format(context.getString(R.string.pat_range), rng) + binding.tvMapLat.text = String.format(context.getString(R.string.pat_latitude), lat) + binding.tvMapLon.text = String.format(context.getString(R.string.pat_longitude), lon) + binding.tvMapRng.text = String.format(context.getString(R.string.pat_range), rng) } private fun drawGroundTrack( @@ -313,4 +301,9 @@ class MapViewFragment : Fragment() { return value * 180 / Math.PI } } + + override fun onDestroyView() { + _binding = null + super.onDestroyView() + } } diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/PassListFragment.kt b/app/src/main/java/com/rtbishop/look4sat/ui/PassListFragment.kt index 4bbc28eb..90e43653 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/PassListFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/PassListFragment.kt @@ -29,18 +29,15 @@ import android.widget.ImageButton import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AlertDialog -import androidx.constraintlayout.widget.ConstraintLayout import androidx.fragment.app.Fragment import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.SimpleItemAnimator -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import com.github.amsacode.predict4java.TLE -import com.google.android.material.floatingactionbutton.FloatingActionButton import com.rtbishop.look4sat.MainViewModel import com.rtbishop.look4sat.R +import com.rtbishop.look4sat.databinding.FragmentPassListBinding import com.rtbishop.look4sat.repo.SatEntry import com.rtbishop.look4sat.repo.SatPass import com.rtbishop.look4sat.ui.adapters.SatPassAdapter @@ -49,15 +46,14 @@ import java.util.concurrent.TimeUnit class PassListFragment : Fragment() { + private var _binding: FragmentPassListBinding? = null + private val binding get() = _binding!! + private lateinit var viewModel: MainViewModel - private lateinit var satPassRecycler: RecyclerView private lateinit var satPassAdapter: SatPassAdapter private lateinit var btnPassPrefs: ImageButton - private lateinit var passListFab: FloatingActionButton private lateinit var aosTimer: CountDownTimer private lateinit var aosTimerText: TextView - private lateinit var swipeLayout: SwipeRefreshLayout - private lateinit var infoLayout: ConstraintLayout private lateinit var mainActivity: MainActivity private lateinit var satPassList: MutableList private var isTimerSet: Boolean = false @@ -75,27 +71,20 @@ class PassListFragment : Fragment() { container: ViewGroup?, savedInstanceState: Bundle? ): View? { - return inflater.inflate(R.layout.fragment_pass_list, container, false) + _binding = FragmentPassListBinding.inflate(layoutInflater, container, false) + return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - findViews(view) + aosTimerText = mainActivity.findViewById(R.id.toolbar_timer) + btnPassPrefs = mainActivity.findViewById(R.id.toolbar_filter) setupComponents() setupObservers() } - private fun findViews(view: View) { - aosTimerText = mainActivity.findViewById(R.id.toolbar_timer) - btnPassPrefs = mainActivity.findViewById(R.id.toolbar_filter) - swipeLayout = view.findViewById(R.id.pass_list_refresh) - infoLayout = view.findViewById(R.id.pass_info_layout) - satPassRecycler = view.findViewById(R.id.pass_list_recycler) - passListFab = view.findViewById(R.id.pass_list_fab) - } - private fun setupComponents() { - satPassRecycler.apply { + binding.recPassList.apply { layoutManager = LinearLayoutManager(mainActivity) adapter = satPassAdapter isVerticalScrollBarEnabled = false @@ -104,13 +93,13 @@ class PassListFragment : Fragment() { satPassAdapter.setList(satPassList) setTimer() - swipeLayout.setProgressBackgroundColorSchemeResource(R.color.themeAccent) - swipeLayout.setColorSchemeResources(R.color.backgroundDark) - swipeLayout.setOnRefreshListener { calculatePasses() } + binding.refLayoutPassList.setProgressBackgroundColorSchemeResource(R.color.themeAccent) + binding.refLayoutPassList.setColorSchemeResources(R.color.backgroundDark) + binding.refLayoutPassList.setOnRefreshListener { calculatePasses() } btnPassPrefs.setOnClickListener { showSatPassPrefsDialog(viewModel.hoursAhead, viewModel.minEl) } - passListFab.setOnClickListener { + binding.fabSatSelect.setOnClickListener { showSelectSatDialog(viewModel.tleMainList, viewModel.tleSelection) } } @@ -120,19 +109,19 @@ class PassListFragment : Fragment() { satPassList = it satPassAdapter.setList(satPassList) if (satPassList.isNotEmpty()) { - infoLayout.visibility = View.INVISIBLE - satPassRecycler.visibility = View.VISIBLE + binding.layoutInfo.visibility = View.INVISIBLE + binding.recPassList.visibility = View.VISIBLE } else { - infoLayout.visibility = View.VISIBLE - satPassRecycler.visibility = View.INVISIBLE + binding.layoutInfo.visibility = View.VISIBLE + binding.recPassList.visibility = View.INVISIBLE } setTimer() - swipeLayout.isRefreshing = false + binding.refLayoutPassList.isRefreshing = false }) } private fun calculatePasses() { - swipeLayout.isRefreshing = true + binding.refLayoutPassList.isRefreshing = true viewModel.getPasses() } @@ -278,4 +267,9 @@ class PassListFragment : Fragment() { if (resetToNull) aosTimerText.text = String.format(getString(R.string.pat_timer), 0, 0, 0) } + + override fun onDestroyView() { + _binding = null + super.onDestroyView() + } } diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/PolarViewFragment.kt b/app/src/main/java/com/rtbishop/look4sat/ui/PolarViewFragment.kt index f9b16d59..8da12736 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/PolarViewFragment.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/PolarViewFragment.kt @@ -27,18 +27,16 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.FrameLayout -import android.widget.TextView import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView import com.github.amsacode.predict4java.SatPos import com.rtbishop.look4sat.MainViewModel import com.rtbishop.look4sat.R +import com.rtbishop.look4sat.databinding.FragmentPolarViewBinding import com.rtbishop.look4sat.repo.SatPass import com.rtbishop.look4sat.ui.adapters.TransmitterAdapter import kotlinx.coroutines.launch @@ -53,17 +51,13 @@ class PolarViewFragment : Fragment() { private val service = Executors.newSingleThreadScheduledExecutor() private val args: PolarViewFragmentArgs by navArgs() + private var _binding: FragmentPolarViewBinding? = null + private val binding get() = _binding!! + private lateinit var viewModel: MainViewModel private lateinit var satPass: SatPass private lateinit var polarView: PolarView - private lateinit var polarViewFrame: FrameLayout - private lateinit var transRecycler: RecyclerView private lateinit var transmitterAdapter: TransmitterAdapter - private lateinit var polarAzimuth: TextView - private lateinit var polarElevation: TextView - private lateinit var polarRange: TextView - private lateinit var polarAltitude: TextView - private lateinit var noTransFound: TextView private lateinit var mainActivity: MainActivity override fun onCreate(savedInstanceState: Bundle?) { @@ -77,27 +71,20 @@ class PolarViewFragment : Fragment() { container: ViewGroup?, savedInstanceState: Bundle? ): View? { - return inflater.inflate(R.layout.fragment_polar_view, container, false) + _binding = FragmentPolarViewBinding.inflate(layoutInflater, container, false) + return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - polarViewFrame = view.findViewById(R.id.polar_view_frame) - transRecycler = view.findViewById(R.id.polar_recycler) - polarAzimuth = view.findViewById(R.id.polar_azimuth) - polarElevation = view.findViewById(R.id.polar_elevation) - polarRange = view.findViewById(R.id.polar_range) - polarAltitude = view.findViewById(R.id.polar_altitude) - noTransFound = view.findViewById(R.id.polar_no_trans) - viewModel.satPassList.value?.let { val refreshRate = viewModel.delay satPass = it[args.satPassIndex] mainActivity.supportActionBar?.title = satPass.tle.name polarView = PolarView(mainActivity, refreshRate) - polarViewFrame.addView(polarView) + binding.framePolar.addView(polarView) service.scheduleAtFixedRate( { polarView.invalidate() }, refreshRate, @@ -111,7 +98,7 @@ class PolarViewFragment : Fragment() { private fun setupTransRecycler() { transmitterAdapter = TransmitterAdapter() - transRecycler.apply { + binding.recPolar.apply { layoutManager = LinearLayoutManager(mainActivity) adapter = transmitterAdapter } @@ -121,8 +108,8 @@ class PolarViewFragment : Fragment() { transmitterAdapter.setList(transList) transmitterAdapter.notifyDataSetChanged() } else { - transRecycler.visibility = View.INVISIBLE - noTransFound.visibility = View.VISIBLE + binding.recPolar.visibility = View.INVISIBLE + binding.tvPolarNoTrans.visibility = View.VISIBLE } } } @@ -178,13 +165,13 @@ class PolarViewFragment : Fragment() { private fun setPassText() { satPos = satPass.predictor.getSatPos(Date()) - polarAzimuth.text = + binding.tvPolarAz.text = String.format(context.getString(R.string.pat_azimuth), rad2Deg(satPos.azimuth)) - polarElevation.text = + binding.tvPolarEl.text = String.format(context.getString(R.string.pat_elevation), rad2Deg(satPos.elevation)) - polarRange.text = + binding.tvPolarRng.text = String.format(context.getString(R.string.pat_range), satPos.range) - polarAltitude.text = + binding.tvPolarAlt.text = String.format(context.getString(R.string.pat_altitude), satPos.altitude) } @@ -266,4 +253,9 @@ class PolarViewFragment : Fragment() { return value * 180 / Math.PI } } + + override fun onDestroyView() { + _binding = null + super.onDestroyView() + } } diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/SatEntryDialog.kt b/app/src/main/java/com/rtbishop/look4sat/ui/SatEntryDialog.kt index 93ea5763..2835338f 100755 --- a/app/src/main/java/com/rtbishop/look4sat/ui/SatEntryDialog.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/SatEntryDialog.kt @@ -24,33 +24,30 @@ import android.os.Bundle import android.view.ViewGroup import android.view.Window import android.widget.SearchView -import android.widget.TextView import androidx.appcompat.app.AppCompatDialogFragment import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import com.rtbishop.look4sat.R +import com.rtbishop.look4sat.databinding.DialogSatEntryBinding import com.rtbishop.look4sat.repo.SatEntry import com.rtbishop.look4sat.ui.adapters.SatEntryAdapter import java.util.* class SatEntryDialog : AppCompatDialogFragment(), SearchView.OnQueryTextListener { - private lateinit var searchView: SearchView - private lateinit var recyclerView: RecyclerView - private lateinit var dialogBtnPositive: TextView - private lateinit var dialogBtnNegative: TextView - private lateinit var dialogBtnNeutral: TextView private lateinit var satEntryAdapter: SatEntryAdapter private lateinit var entriesListener: EntriesSubmitListener + private var _binding: DialogSatEntryBinding? = null + private val binding get() = _binding!! + private var entriesList = mutableListOf() private var selectionList = mutableListOf() private var selectAllToggle = true override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + _binding = DialogSatEntryBinding.inflate(requireActivity().layoutInflater) val satEntryDialog = Dialog(requireActivity()).apply { window?.requestFeature(Window.FEATURE_NO_TITLE) - setContentView(R.layout.dialog_sat_entry) + setContentView(binding.root) window?.setLayout( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT @@ -60,20 +57,21 @@ class SatEntryDialog : AppCompatDialogFragment(), SearchView.OnQueryTextListener entriesList = checkSelectedEntries(entriesList, selectionList) satEntryAdapter = SatEntryAdapter(entriesList) - findViews(satEntryDialog) - setListeners() - - searchView.apply { + binding.dialogSearch.apply { setOnQueryTextListener(this@SatEntryDialog) onActionViewExpanded() clearFocus() } - recyclerView.apply { + binding.dialogRecycler.apply { layoutManager = LinearLayoutManager(activity) adapter = satEntryAdapter } + binding.dialogBtnPositive.setOnClickListener { onPositiveClicked() } + binding.dialogBtnNegative.setOnClickListener { onNegativeClicked() } + binding.dialogBtnNeutral.setOnClickListener { onNeutralClicked() } + return satEntryDialog } @@ -93,20 +91,6 @@ class SatEntryDialog : AppCompatDialogFragment(), SearchView.OnQueryTextListener return this } - private fun findViews(dialog: Dialog) { - searchView = dialog.findViewById(R.id.dialog_search) - recyclerView = dialog.findViewById(R.id.dialog_recycler) - dialogBtnPositive = dialog.findViewById(R.id.dialog_btn_positive) - dialogBtnNegative = dialog.findViewById(R.id.dialog_btn_negative) - dialogBtnNeutral = dialog.findViewById(R.id.dialog_btn_neutral) - } - - private fun setListeners() { - dialogBtnPositive.setOnClickListener { onPositiveClicked() } - dialogBtnNegative.setOnClickListener { onNegativeClicked() } - dialogBtnNeutral.setOnClickListener { onNeutralClicked() } - } - private fun checkSelectedEntries(entries: MutableList, selection: MutableList) : MutableList { selection.forEach { entries[it].isSelected = true } @@ -163,4 +147,9 @@ class SatEntryDialog : AppCompatDialogFragment(), SearchView.OnQueryTextListener interface EntriesSubmitListener { fun onEntriesSubmit(list: MutableList) } + + override fun onDestroyView() { + _binding = null + super.onDestroyView() + } } diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/adapters/SatEntryAdapter.kt b/app/src/main/java/com/rtbishop/look4sat/ui/adapters/SatEntryAdapter.kt index afcca097..ded8edf7 100755 --- a/app/src/main/java/com/rtbishop/look4sat/ui/adapters/SatEntryAdapter.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/adapters/SatEntryAdapter.kt @@ -22,19 +22,17 @@ package com.rtbishop.look4sat.ui.adapters import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.CheckBox import androidx.recyclerview.widget.RecyclerView -import com.rtbishop.look4sat.R +import com.rtbishop.look4sat.databinding.ItemSatEntryBinding import com.rtbishop.look4sat.repo.SatEntry internal class SatEntryAdapter(private var entriesList: MutableList) : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SatEntryHolder { - val view = LayoutInflater - .from(parent.context) - .inflate(R.layout.sat_entry_item, parent, false) - return SatEntryHolder(view) + val binding = ItemSatEntryBinding + .inflate(LayoutInflater.from(parent.context), parent, false) + return SatEntryHolder(binding.root, binding) } override fun onBindViewHolder(holder: SatEntryHolder, position: Int) { @@ -50,13 +48,13 @@ internal class SatEntryAdapter(private var entriesList: MutableList) : notifyDataSetChanged() } - internal inner class SatEntryHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - private val satEntryItem: CheckBox = itemView.findViewById(R.id.sat_entry_item) + internal inner class SatEntryHolder(itemView: View, private val binding: ItemSatEntryBinding) : + RecyclerView.ViewHolder(itemView) { fun bind(satEntry: SatEntry) { - satEntryItem.text = satEntry.name - satEntryItem.isChecked = satEntry.isSelected - itemView.setOnClickListener { satEntry.isSelected = satEntryItem.isChecked } + binding.satEntryCheckbox.text = satEntry.name + binding.satEntryCheckbox.isChecked = satEntry.isSelected + itemView.setOnClickListener { satEntry.isSelected = binding.satEntryCheckbox.isChecked } } } } diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/adapters/SatPassAdapter.kt b/app/src/main/java/com/rtbishop/look4sat/ui/adapters/SatPassAdapter.kt index 3147c52e..367663a8 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/adapters/SatPassAdapter.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/adapters/SatPassAdapter.kt @@ -23,13 +23,12 @@ import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.ImageView -import android.widget.ProgressBar -import android.widget.TextView import androidx.navigation.findNavController import androidx.recyclerview.widget.RecyclerView import com.rtbishop.look4sat.MainViewModel import com.rtbishop.look4sat.R +import com.rtbishop.look4sat.databinding.ItemPassGeoBinding +import com.rtbishop.look4sat.databinding.ItemPassLeoBinding import com.rtbishop.look4sat.repo.SatPass import com.rtbishop.look4sat.ui.PassListFragmentDirections import java.text.SimpleDateFormat @@ -80,60 +79,48 @@ class SatPassAdapter(val viewModel: MainViewModel) : override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return if (viewType == 0) { - val itemView = LayoutInflater - .from(parent.context) - .inflate(R.layout.card_pass, parent, false) - return SatPassHolder(itemView) + val bindingLeo = ItemPassLeoBinding + .inflate(LayoutInflater.from(parent.context), parent, false) + SatPassLeoHolder(bindingLeo.root, bindingLeo) } else { - val itemView = LayoutInflater - .from(parent.context) - .inflate(R.layout.card_pass_geo, parent, false) - SatPassGeoHolder(itemView) + val bindingGeo = ItemPassGeoBinding + .inflate(LayoutInflater.from(parent.context), parent, false) + SatPassGeoHolder(bindingGeo.root, bindingGeo) } } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { if (holder.itemViewType == 0) { - (holder as SatPassHolder).bind(satPassList[position]) + (holder as SatPassLeoHolder).bind(satPassList[position]) } else { (holder as SatPassGeoHolder).bind(satPassList[position]) } } - inner class SatPassHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - - private val context: Context = itemView.context - private val passImg = itemView.findViewById(R.id.pass_img) - private val satName = itemView.findViewById(R.id.pass_satName) - private val satId = itemView.findViewById(R.id.pass_satId) - private val maxEl = itemView.findViewById(R.id.pass_maxEl) - private val aosAz = itemView.findViewById(R.id.pass_aosAz) - private val losAz = itemView.findViewById(R.id.pass_losAz) - private val aosTime = itemView.findViewById(R.id.pass_aosTime) - private val losTime = itemView.findViewById(R.id.pass_losTime) - private var progressBar = itemView.findViewById(R.id.pass_progress) + inner class SatPassLeoHolder(itemView: View, private val binding: ItemPassLeoBinding) : + RecyclerView.ViewHolder(itemView) { fun bind(satPass: SatPass) { + val context: Context = itemView.context + if (satPass.active) binding.passLeoImg.setImageResource(R.drawable.ic_pass_active) + else binding.passLeoImg.setImageResource(R.drawable.ic_pass_inactive) - if (satPass.active) passImg.setImageResource(R.drawable.ic_pass_active) - else passImg.setImageResource(R.drawable.ic_pass_inactive) - - satName.text = satPass.tle.name - satId.text = + binding.passLeoSatName.text = satPass.tle.name + binding.passLeoSatId.text = String.format(context.getString(R.string.pass_satId), satPass.tle.catnum) - maxEl.text = + binding.passLeoMaxEl.text = String.format(context.getString(R.string.pass_maxEl), satPass.pass.maxEl) - aosAz.text = + binding.passLeoAosAz.text = String.format(context.getString(R.string.pass_aos_az), satPass.pass.aosAzimuth) - losAz.text = + binding.passLeoLosAz.text = String.format(context.getString(R.string.pass_los_az), satPass.pass.losAzimuth) - aosTime.text = + binding.passLeoAosTime.text = SimpleDateFormat(context.getString(R.string.pass_dateTime), Locale.getDefault()) .format(satPass.pass.startTime) - losTime.text = + binding.passLeoLosTime.text = SimpleDateFormat(context.getString(R.string.pass_dateTime), Locale.getDefault()) .format(satPass.pass.endTime) - progressBar.progress = satPass.progress + binding.passLeoProgress.progress = satPass.progress itemView.setOnClickListener { viewModel.satPassList.value?.let { @@ -145,22 +132,19 @@ class SatPassAdapter(val viewModel: MainViewModel) : } } - inner class SatPassGeoHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - - private val context: Context = itemView.context - private val satName = itemView.findViewById(R.id.pass_geo_name) - private val satId = itemView.findViewById(R.id.pass_geo_id) - private val satAz = itemView.findViewById(R.id.pass_geo_az) - private val satEl = itemView.findViewById(R.id.pass_geo_el) + inner class SatPassGeoHolder(itemView: View, private val binding: ItemPassGeoBinding) : + RecyclerView.ViewHolder(itemView) { fun bind(satPass: SatPass) { + val context: Context = itemView.context val satPos = satPass.predictor.getSatPos(satPass.pass.startTime) val azimuth = satPos.azimuth * 180 / Math.PI - satName.text = satPass.tle.name - satId.text = String.format(context.getString(R.string.pass_satId), satPass.tle.catnum) - satAz.text = String.format(context.getString(R.string.pat_azimuth), azimuth) - satEl.text = + binding.passGeoName.text = satPass.tle.name + binding.passGeoId.text = + String.format(context.getString(R.string.pass_satId), satPass.tle.catnum) + binding.passGeoAz.text = String.format(context.getString(R.string.pat_azimuth), azimuth) + binding.passGeoEl.text = String.format(context.getString(R.string.pat_elevation), satPass.pass.maxEl) itemView.setOnClickListener { diff --git a/app/src/main/java/com/rtbishop/look4sat/ui/adapters/TransmitterAdapter.kt b/app/src/main/java/com/rtbishop/look4sat/ui/adapters/TransmitterAdapter.kt index 19b08cf2..3af59189 100644 --- a/app/src/main/java/com/rtbishop/look4sat/ui/adapters/TransmitterAdapter.kt +++ b/app/src/main/java/com/rtbishop/look4sat/ui/adapters/TransmitterAdapter.kt @@ -23,9 +23,9 @@ import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import com.rtbishop.look4sat.R +import com.rtbishop.look4sat.databinding.ItemTransmitterBinding import com.rtbishop.look4sat.repo.Transmitter class TransmitterAdapter : RecyclerView.Adapter() { @@ -41,72 +41,69 @@ class TransmitterAdapter : RecyclerView.Adapter(R.id.trans_description) - private val downlink = itemView.findViewById(R.id.trans_downlink) - private val uplink = itemView.findViewById(R.id.trans_uplink) - private val mode = itemView.findViewById(R.id.trans_mode) - private val inverted = itemView.findViewById(R.id.trans_inverted) - private val freqDivider = 1000000f + inner class TransmitterHolder(itemView: View, private val binding: ItemTransmitterBinding) : + RecyclerView.ViewHolder(itemView) { fun bind(transmitter: Transmitter) { - description.text = transmitter.description + val context: Context = itemView.context + val freqDivider = 1000000f + + binding.transDescription.text = transmitter.description if (transmitter.downlinkLow != null && transmitter.downlinkHigh == null) { - downlink.text = String.format( - context.getString(R.string.trans_down_low), - transmitter.downlinkLow / freqDivider - ) + binding.transDownlink.text = String + .format( + context.getString(R.string.trans_down_low), + transmitter.downlinkLow / freqDivider + ) } else if (transmitter.downlinkLow != null && transmitter.downlinkHigh != null) { - downlink.text = String.format( - context.getString(R.string.trans_down_lowHigh), - transmitter.downlinkLow / freqDivider, - transmitter.downlinkHigh / freqDivider - ) + binding.transDownlink.text = String + .format( + context.getString(R.string.trans_down_lowHigh), + transmitter.downlinkLow / freqDivider, + transmitter.downlinkHigh / freqDivider + ) } else { - downlink.text = context.getString(R.string.no_downlink) + binding.transDownlink.text = context.getString(R.string.no_downlink) } if (transmitter.uplinkLow != null && transmitter.uplinkHigh == null) { - uplink.text = String.format( + binding.transUplink.text = String.format( context.getString(R.string.trans_up_low), transmitter.uplinkLow / freqDivider ) } else if (transmitter.uplinkLow != null && transmitter.uplinkHigh != null) { - uplink.text = String.format( + binding.transUplink.text = String.format( context.getString(R.string.trans_up_lowHigh), transmitter.uplinkLow / freqDivider, transmitter.uplinkHigh / freqDivider ) } else { - uplink.text = context.getString(R.string.no_uplink) + binding.transUplink.text = context.getString(R.string.no_uplink) } if (transmitter.mode != null) { - mode.text = + binding.transMode.text = String.format(context.getString(R.string.trans_mode), transmitter.mode) } else { - mode.text = context.getString(R.string.no_mode) + binding.transMode.text = context.getString(R.string.no_mode) } if (transmitter.isInverted) { - inverted.text = String.format( + binding.transInverted.text = String.format( context.getString(R.string.trans_inverted), context.getString(R.string.btn_yes) ) } else { - inverted.text = String.format( + binding.transInverted.text = String.format( context.getString(R.string.trans_inverted), context.getString(R.string.btn_no) ) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 9d78f793..81a29d70 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -27,6 +27,7 @@ tools:openDrawer="start"> diff --git a/app/src/main/res/layout/app_bar_main.xml b/app/src/main/res/layout/app_bar_main.xml index 2ba65ffa..084d2b76 100644 --- a/app/src/main/res/layout/app_bar_main.xml +++ b/app/src/main/res/layout/app_bar_main.xml @@ -64,6 +64,8 @@ - + diff --git a/app/src/main/res/layout/drawer_header.xml b/app/src/main/res/layout/drawer_header.xml index 64bbe2c2..6fcefad9 100644 --- a/app/src/main/res/layout/drawer_header.xml +++ b/app/src/main/res/layout/drawer_header.xml @@ -20,6 +20,7 @@ + app:layout_constraintStart_toStartOf="@+id/guidelineCenter" /> + app:layout_constraintStart_toEndOf="@+id/img_about" + app:layout_constraintTop_toTopOf="@+id/img_about" /> + app:layout_constraintTop_toBottomOf="@+id/tv_about_title" /> + app:layout_constraintTop_toBottomOf="@+id/tv_about_version" /> + app:layout_constraintEnd_toEndOf="@+id/tv_about_subtitle" + app:layout_constraintStart_toStartOf="@+id/tv_about_subtitle" + app:layout_constraintTop_toBottomOf="@+id/tv_about_subtitle" /> + app:layout_constraintTop_toBottomOf="@+id/tv_about_thanks" /> diff --git a/app/src/main/res/layout/fragment_map_view.xml b/app/src/main/res/layout/fragment_map_view.xml index ebc1aa2f..077a3f2e 100644 --- a/app/src/main/res/layout/fragment_map_view.xml +++ b/app/src/main/res/layout/fragment_map_view.xml @@ -25,7 +25,7 @@ tools:context=".ui.MapViewFragment"> @@ -28,7 +28,7 @@ android:layout_height="match_parent"> + app:layout_constraintTop_toBottomOf="@+id/imgInfoSwipe" /> + app:layout_constraintStart_toStartOf="@+id/frame_polar" + app:layout_constraintTop_toTopOf="@+id/frame_polar" /> + app:layout_constraintEnd_toEndOf="@+id/frame_polar" + app:layout_constraintTop_toTopOf="@+id/frame_polar" /> + app:layout_constraintBottom_toBottomOf="@+id/frame_polar" + app:layout_constraintStart_toStartOf="@+id/frame_polar" /> + app:layout_constraintBottom_toBottomOf="@+id/frame_polar" + app:layout_constraintEnd_toEndOf="@+id/frame_polar" /> + app:layout_constraintTop_toBottomOf="@+id/frame_polar" /> + app:layout_constraintTop_toBottomOf="@+id/frame_polar" /> diff --git a/app/src/main/res/layout/card_pass_geo.xml b/app/src/main/res/layout/item_pass_geo.xml similarity index 98% rename from app/src/main/res/layout/card_pass_geo.xml rename to app/src/main/res/layout/item_pass_geo.xml index e3e0ba27..374088d3 100644 --- a/app/src/main/res/layout/card_pass_geo.xml +++ b/app/src/main/res/layout/item_pass_geo.xml @@ -19,7 +19,7 @@ + app:layout_constraintStart_toEndOf="@+id/pass_leo_maxEl" /> + app:layout_constraintTop_toBottomOf="@+id/pass_leo_satId" /> + app:layout_constraintStart_toEndOf="@+id/pass_leo_img" + app:layout_constraintTop_toTopOf="@+id/pass_leo_satId" /> + app:layout_constraintStart_toStartOf="@+id/pass_leo_progress" /> + app:layout_constraintStart_toStartOf="@+id/pass_leo_progress" /> + app:layout_constraintStart_toEndOf="@+id/pass_leo_aosTime" + app:layout_constraintTop_toBottomOf="@+id/pass_leo_progress" /> + app:layout_constraintTop_toBottomOf="@+id/pass_leo_maxEl" /> diff --git a/app/src/main/res/layout/sat_entry_item.xml b/app/src/main/res/layout/item_sat_entry.xml similarity index 96% rename from app/src/main/res/layout/sat_entry_item.xml rename to app/src/main/res/layout/item_sat_entry.xml index 73e2b687..3d40aa1f 100644 --- a/app/src/main/res/layout/sat_entry_item.xml +++ b/app/src/main/res/layout/item_sat_entry.xml @@ -18,7 +18,7 @@ -->