From 44979c2daabf40ab516a71460f29f9c2f8be4582 Mon Sep 17 00:00:00 2001 From: Prem Nirmal Date: Sun, 26 Jun 2022 14:50:17 +0100 Subject: [PATCH] Fix crash in db viewer and some ui + injection tweaks --- .../premnirmal/ticker/base/BaseActivity.kt | 21 ++++++-- .../ticker/components/AppComponent.kt | 24 +++------ .../ticker/debug/DbViewerActivity.kt | 7 +-- .../ticker/debug/DbViewerViewModel.kt | 4 ++ .../premnirmal/ticker/home/MainActivity.kt | 2 + .../premnirmal/ticker/news/GraphActivity.kt | 3 -- .../ticker/news/QuoteDetailActivity.kt | 32 ++++++------ .../ticker/news/QuoteDetailViewModel.kt | 19 ++++--- .../ticker/portfolio/AddAlertsActivity.kt | 3 -- .../ticker/portfolio/AddNotesActivity.kt | 5 -- .../ticker/portfolio/AddPositionActivity.kt | 36 +++++-------- .../ticker/portfolio/AddPositionViewModel.kt | 52 +++++++++++++++++++ .../ticker/portfolio/search/SearchActivity.kt | 3 -- .../ticker/settings/WidgetSettingsActivity.kt | 3 -- app/version.properties | 4 +- 15 files changed, 124 insertions(+), 94 deletions(-) create mode 100644 app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/AddPositionViewModel.kt diff --git a/app/src/main/kotlin/com/github/premnirmal/ticker/base/BaseActivity.kt b/app/src/main/kotlin/com/github/premnirmal/ticker/base/BaseActivity.kt index 37592c83..368b7a7e 100644 --- a/app/src/main/kotlin/com/github/premnirmal/ticker/base/BaseActivity.kt +++ b/app/src/main/kotlin/com/github/premnirmal/ticker/base/BaseActivity.kt @@ -6,6 +6,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.lifecycleScope import androidx.viewbinding.ViewBinding import com.github.premnirmal.ticker.analytics.Analytics +import com.github.premnirmal.ticker.components.Injector import com.github.premnirmal.ticker.model.IStocksProvider import com.github.premnirmal.ticker.model.IStocksProvider.FetchState import com.github.premnirmal.ticker.showDialog @@ -23,10 +24,9 @@ abstract class BaseActivity : AppCompatActivity() { abstract val simpleName: String abstract val binding: T - @Inject internal lateinit var stocksProvider: IStocksProvider - @Inject internal lateinit var analytics: Analytics open val subscribeToErrorEvents = true private var isErrorDialogShowing = false + private val holder: InjectionHolder by lazy { InjectionHolder() } override fun attachBaseContext(newBase: Context) { super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase)) @@ -37,15 +37,19 @@ abstract class BaseActivity : AppCompatActivity() { ) { super.onCreate(savedInstanceState) setContentView(binding.root) - analytics.trackScreenView(simpleName, this) savedInstanceState?.let { isErrorDialogShowing = it.getBoolean(IS_ERROR_DIALOG_SHOWING, false) } } + override fun onPostCreate(savedInstanceState: Bundle?) { + super.onPostCreate(savedInstanceState) + holder.analytics.trackScreenView(simpleName, this) + } + override fun onResume() { super.onResume() if (subscribeToErrorEvents) { lifecycleScope.launch { - stocksProvider.fetchState.collect { state -> + holder.stocksProvider.fetchState.collect { state -> if (state is FetchState.Failure) { if (this.isActive && !isErrorDialogShowing && !isFinishing) { isErrorDialogShowing = true @@ -83,4 +87,13 @@ abstract class BaseActivity : AppCompatActivity() { companion object { private const val IS_ERROR_DIALOG_SHOWING = "IS_ERROR_DIALOG_SHOWING" } + + class InjectionHolder { + @Inject internal lateinit var analytics: Analytics + @Inject internal lateinit var stocksProvider: IStocksProvider + + init { + Injector.appComponent.inject(this) + } + } } diff --git a/app/src/main/kotlin/com/github/premnirmal/ticker/components/AppComponent.kt b/app/src/main/kotlin/com/github/premnirmal/ticker/components/AppComponent.kt index 66dfca03..fec23065 100644 --- a/app/src/main/kotlin/com/github/premnirmal/ticker/components/AppComponent.kt +++ b/app/src/main/kotlin/com/github/premnirmal/ticker/components/AppComponent.kt @@ -5,8 +5,8 @@ import com.github.premnirmal.ticker.AppPreferences import com.github.premnirmal.ticker.StocksApp import com.github.premnirmal.ticker.UpdateReceiver import com.github.premnirmal.ticker.analytics.GeneralProperties +import com.github.premnirmal.ticker.base.BaseActivity import com.github.premnirmal.ticker.base.BaseFragment -import com.github.premnirmal.ticker.debug.DbViewerActivity import com.github.premnirmal.ticker.debug.DbViewerViewModel import com.github.premnirmal.ticker.home.HomeFragment import com.github.premnirmal.ticker.home.HomeViewModel @@ -20,25 +20,21 @@ import com.github.premnirmal.ticker.model.StocksProvider import com.github.premnirmal.ticker.network.NewsProvider import com.github.premnirmal.ticker.network.StocksApi import com.github.premnirmal.ticker.network.UserAgentInterceptor -import com.github.premnirmal.ticker.news.GraphActivity import com.github.premnirmal.ticker.news.GraphViewModel import com.github.premnirmal.ticker.news.NewsFeedViewModel import com.github.premnirmal.ticker.news.QuoteDetailActivity import com.github.premnirmal.ticker.news.QuoteDetailViewModel import com.github.premnirmal.ticker.notifications.DailySummaryNotificationReceiver import com.github.premnirmal.ticker.portfolio.AddAlertsActivity -import com.github.premnirmal.ticker.portfolio.AddNotesActivity -import com.github.premnirmal.ticker.portfolio.AddPositionActivity +import com.github.premnirmal.ticker.portfolio.AddPositionViewModel import com.github.premnirmal.ticker.portfolio.AlertsViewModel import com.github.premnirmal.ticker.portfolio.NotesViewModel import com.github.premnirmal.ticker.portfolio.PortfolioViewModel import com.github.premnirmal.ticker.portfolio.StocksAdapter -import com.github.premnirmal.ticker.portfolio.search.SearchActivity import com.github.premnirmal.ticker.portfolio.search.SearchFragment import com.github.premnirmal.ticker.portfolio.search.SearchViewModel import com.github.premnirmal.ticker.repo.StocksStorage import com.github.premnirmal.ticker.settings.SettingsFragment -import com.github.premnirmal.ticker.settings.WidgetSettingsActivity import com.github.premnirmal.ticker.settings.WidgetSettingsFragment import com.github.premnirmal.ticker.widget.RefreshReceiver import com.github.premnirmal.ticker.widget.RemoteStockViewAdapter @@ -58,11 +54,9 @@ interface AppComponent { // Activities - fun inject(mainActivity: MainActivity) - - fun inject(addPositionActivity: AddPositionActivity) + fun inject(stocksApp: BaseActivity.InjectionHolder) - fun inject(addNotesActivity: AddNotesActivity) + fun inject(mainActivity: MainActivity) fun inject(addAlertsActivity: AddAlertsActivity) @@ -70,14 +64,6 @@ interface AppComponent { fun inject(newsFeedActivity: QuoteDetailActivity) - fun inject(graphActivity: GraphActivity) - - fun inject(searchActivity: SearchActivity) - - fun inject(widgetSettingsActivity: WidgetSettingsActivity) - - fun inject(dbViewerActivity: DbViewerActivity) - // Components fun inject(stocksApp: StocksApp.InjectionHolder) @@ -163,4 +149,6 @@ interface AppComponent { fun inject(searchViewModel: SearchViewModel) fun inject(viewModel: PortfolioViewModel) + + fun inject(viewModel: AddPositionViewModel) } diff --git a/app/src/main/kotlin/com/github/premnirmal/ticker/debug/DbViewerActivity.kt b/app/src/main/kotlin/com/github/premnirmal/ticker/debug/DbViewerActivity.kt index b24a38b4..4d38128e 100644 --- a/app/src/main/kotlin/com/github/premnirmal/ticker/debug/DbViewerActivity.kt +++ b/app/src/main/kotlin/com/github/premnirmal/ticker/debug/DbViewerActivity.kt @@ -4,22 +4,19 @@ import android.os.Bundle import android.view.View import androidx.activity.viewModels import com.github.premnirmal.ticker.base.BaseActivity -import com.github.premnirmal.ticker.components.Injector import com.github.premnirmal.ticker.viewBinding import com.github.premnirmal.tickerwidget.databinding.ActivityDbViewerBinding class DbViewerActivity : BaseActivity() { override val binding: (ActivityDbViewerBinding) by viewBinding(ActivityDbViewerBinding::inflate) - override val simpleName: String - get() = "DebugViewerActivity" + override val simpleName = "DebugViewerActivity" + override val subscribeToErrorEvents = false private val viewModel: DbViewerViewModel by viewModels() - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - Injector.appComponent.inject(this) binding.toolbar.setNavigationOnClickListener { finish() } diff --git a/app/src/main/kotlin/com/github/premnirmal/ticker/debug/DbViewerViewModel.kt b/app/src/main/kotlin/com/github/premnirmal/ticker/debug/DbViewerViewModel.kt index 380d09a4..3d4f30ac 100644 --- a/app/src/main/kotlin/com/github/premnirmal/ticker/debug/DbViewerViewModel.kt +++ b/app/src/main/kotlin/com/github/premnirmal/ticker/debug/DbViewerViewModel.kt @@ -69,7 +69,9 @@ class DbViewerViewModel(application: Application) : AndroidViewModel(application dividendDate earningsDate marketCap + marketState isTradeable + isTriggerable """ ) @@ -147,7 +149,9 @@ class DbViewerViewModel(application: Application) : AndroidViewModel(application .append("${quote.dividendDate}") .append("${quote.earningsDate}") .append("${quote.marketCap}") + .append("${quote.marketState}") .append("${quote.isTradeable}") + .append("${quote.isTriggerable}") .append("") val holdings = it.holdings diff --git a/app/src/main/kotlin/com/github/premnirmal/ticker/home/MainActivity.kt b/app/src/main/kotlin/com/github/premnirmal/ticker/home/MainActivity.kt index 4dfdb9df..e737734c 100644 --- a/app/src/main/kotlin/com/github/premnirmal/ticker/home/MainActivity.kt +++ b/app/src/main/kotlin/com/github/premnirmal/ticker/home/MainActivity.kt @@ -9,6 +9,7 @@ import androidx.appcompat.app.AlertDialog.Builder import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import com.github.premnirmal.ticker.AppPreferences +import com.github.premnirmal.ticker.analytics.Analytics import com.github.premnirmal.ticker.analytics.ClickEvent import com.github.premnirmal.ticker.base.BaseActivity import com.github.premnirmal.ticker.components.Injector @@ -49,6 +50,7 @@ class MainActivity : BaseActivity(), BottomNavigationView.O @Inject internal lateinit var appPreferences: AppPreferences @Inject internal lateinit var widgetDataProvider: WidgetDataProvider @Inject internal lateinit var commitsProvider: CommitsProvider + @Inject internal lateinit var analytics: Analytics private var currentChild: ChildFragment? = null private var rateDialogShown = false diff --git a/app/src/main/kotlin/com/github/premnirmal/ticker/news/GraphActivity.kt b/app/src/main/kotlin/com/github/premnirmal/ticker/news/GraphActivity.kt index ff4c6d12..9140d099 100644 --- a/app/src/main/kotlin/com/github/premnirmal/ticker/news/GraphActivity.kt +++ b/app/src/main/kotlin/com/github/premnirmal/ticker/news/GraphActivity.kt @@ -7,7 +7,6 @@ import com.github.mikephil.charting.animation.Easing import com.github.mikephil.charting.charts.LineChart import com.github.premnirmal.ticker.base.BaseGraphActivity import com.github.premnirmal.ticker.components.InAppMessage -import com.github.premnirmal.ticker.components.Injector import com.github.premnirmal.ticker.isNetworkOnline import com.github.premnirmal.ticker.model.IHistoryProvider.Range import com.github.premnirmal.ticker.network.data.Quote @@ -30,9 +29,7 @@ class GraphActivity : BaseGraphActivity() { private val viewModel: GraphViewModel by viewModels() override var range: Range = Range.THREE_MONTH - override fun onCreate(savedInstanceState: Bundle?) { - Injector.appComponent.inject(this) super.onCreate(savedInstanceState) setupGraphView() ticker = checkNotNull(intent.getStringExtra(TICKER)) diff --git a/app/src/main/kotlin/com/github/premnirmal/ticker/news/QuoteDetailActivity.kt b/app/src/main/kotlin/com/github/premnirmal/ticker/news/QuoteDetailActivity.kt index 91589e2d..898fb7e4 100644 --- a/app/src/main/kotlin/com/github/premnirmal/ticker/news/QuoteDetailActivity.kt +++ b/app/src/main/kotlin/com/github/premnirmal/ticker/news/QuoteDetailActivity.kt @@ -5,8 +5,6 @@ import android.app.Activity import android.content.Intent import android.content.res.Configuration import android.os.Build -import android.os.Build.VERSION -import android.os.Build.VERSION_CODES import android.os.Bundle import android.view.Surface import android.view.View @@ -24,6 +22,7 @@ import androidx.recyclerview.widget.StaggeredGridLayoutManager import com.github.mikephil.charting.charts.LineChart import com.github.premnirmal.ticker.AppPreferences import com.github.premnirmal.ticker.CustomTabs +import com.github.premnirmal.ticker.analytics.Analytics import com.github.premnirmal.ticker.analytics.ClickEvent import com.github.premnirmal.ticker.analytics.GeneralEvent import com.github.premnirmal.ticker.base.BaseGraphActivity @@ -66,6 +65,7 @@ class QuoteDetailActivity : BaseGraphActivity(), New } @Inject lateinit var appPreferences: AppPreferences + @Inject lateinit var analytics: Analytics override val simpleName: String = "NewsFeedActivity" override val binding: (ActivityQuoteDetailBinding) by viewBinding(ActivityQuoteDetailBinding::inflate) private lateinit var adapter: NewsFeedAdapter @@ -120,7 +120,7 @@ class QuoteDetailActivity : BaseGraphActivity(), New binding.appBarLayout.addOnOffsetChangedListener(offsetChangedListener) } else if (!resources.getBoolean(R.bool.isTablet) && resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) { binding.parentView.updateLayoutParams { - val rotation = if (VERSION.SDK_INT >= VERSION_CODES.R) { + val rotation = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { display?.rotation ?: Surface.ROTATION_90 } else { windowManager.defaultDisplay.rotation @@ -135,11 +135,11 @@ class QuoteDetailActivity : BaseGraphActivity(), New setupGraphView() updateToolbar() viewModel.quote.observe(this) { result -> - if (result?.wasSuccessful == true) { + if (result.wasSuccessful) { quote = result.data fetchNewsAndChartData() setupQuoteUi() - } else if (result?.wasSuccessful == false) { + } else { InAppMessage.showMessage(binding.parentView, R.string.error_fetching_stock, error = true) binding.progress.visibility = View.GONE binding.graphView.setNoDataText(getString(R.string.error_fetching_stock)) @@ -206,7 +206,7 @@ class QuoteDetailActivity : BaseGraphActivity(), New binding.price.text = quote.priceFormat.format(quote.lastTradePrice) binding.change.formatChange(quote.change) binding.changePercent.formatChangePercent(quote.changeInPercent) - updatePositionsUi() + updatePositionsNotesAlertsUi() binding.positionsHeader.setOnClickListener { positionOnClickListener() @@ -263,14 +263,14 @@ class QuoteDetailActivity : BaseGraphActivity(), New } else { addTickerToWidget(ticker, WidgetDataProvider.INVALID_WIDGET_ID) } - updatePositionsUi() + updatePositionsNotesAlertsUi() return@setOnMenuItemClickListener true } R.id.action_remove -> { removeMenuItem.isVisible = false addMenuItem.isVisible = true viewModel.removeStock(ticker) - updatePositionsUi() + updatePositionsNotesAlertsUi() return@setOnMenuItemClickListener true } } @@ -324,17 +324,17 @@ class QuoteDetailActivity : BaseGraphActivity(), New ) { if (requestCode == REQ_EDIT_POSITIONS) { if (resultCode == Activity.RESULT_OK) { - quote = checkNotNull(data?.getParcelableExtra(AddPositionActivity.QUOTE)) + viewModel.loadQuote(ticker) } } if (requestCode == REQ_EDIT_NOTES) { if (resultCode == Activity.RESULT_OK) { - quote = checkNotNull(data?.getParcelableExtra(AddNotesActivity.QUOTE)) + viewModel.loadQuote(ticker) } } if (requestCode == REQ_EDIT_ALERTS) { if (resultCode == Activity.RESULT_OK) { - quote = checkNotNull(data?.getParcelableExtra(AddAlertsActivity.QUOTE)) + viewModel.loadQuote(ticker) } } super.onActivityResult(requestCode, resultCode, data) @@ -352,12 +352,12 @@ class QuoteDetailActivity : BaseGraphActivity(), New override fun onResume() { super.onResume() if (this::quote.isInitialized) { - updatePositionsUi() + updatePositionsNotesAlertsUi() } } @SuppressLint("SetTextI18n") - private fun updatePositionsUi() { + private fun updatePositionsNotesAlertsUi() { if (!this::quote.isInitialized) { return } @@ -366,17 +366,17 @@ class QuoteDetailActivity : BaseGraphActivity(), New binding.positionsContainer.visibility = View.VISIBLE binding.positionsHeader.visibility = View.VISIBLE binding.notesHeader.visibility = View.VISIBLE + binding.notesContainer.visibility = View.VISIBLE binding.alertHeader.visibility = View.VISIBLE binding.numShares.text = quote.numSharesString() binding.equityValue.text = quote.priceFormat.format(quote.holdings()) val notesText = quote.properties?.notes + binding.notesContainer.visibility = View.VISIBLE if (notesText.isNullOrEmpty()) { - binding.notesContainer.visibility = View.GONE + binding.notesDisplay.text = "--" } else { - binding.notesContainer.visibility = View.VISIBLE binding.notesDisplay.text = notesText } - val alertAbove = quote.getAlertAbove() val alertBelow = quote.getAlertBelow() if (alertAbove > 0.0f || alertBelow > 0.0f) { diff --git a/app/src/main/kotlin/com/github/premnirmal/ticker/news/QuoteDetailViewModel.kt b/app/src/main/kotlin/com/github/premnirmal/ticker/news/QuoteDetailViewModel.kt index b6f28aaf..7d639a44 100644 --- a/app/src/main/kotlin/com/github/premnirmal/ticker/news/QuoteDetailViewModel.kt +++ b/app/src/main/kotlin/com/github/premnirmal/ticker/news/QuoteDetailViewModel.kt @@ -24,13 +24,12 @@ import com.github.premnirmal.ticker.widget.WidgetDataProvider import com.github.premnirmal.tickerwidget.R import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.flow.transform import kotlinx.coroutines.isActive import kotlinx.coroutines.launch -import timber.log.Timber import javax.inject.Inject class QuoteDetailViewModel(application: Application) : AndroidViewModel(application) { @@ -40,8 +39,8 @@ class QuoteDetailViewModel(application: Application) : AndroidViewModel(applicat @Inject internal lateinit var historyProvider: IHistoryProvider @Inject internal lateinit var widgetDataProvider: WidgetDataProvider - private val _quote = MutableStateFlow?>(null) - val quote: LiveData?> + private val _quote = MutableSharedFlow>() + val quote: LiveData> get() = _quote.asLiveData() private val _data = MutableLiveData>() val data: LiveData> @@ -57,7 +56,7 @@ class QuoteDetailViewModel(application: Application) : AndroidViewModel(applicat get() = _newsError val details: Flow> = _quote.transform { quote -> - if (quote?.wasSuccessful == true) { + if (quote.wasSuccessful) { quote.data.run { val details = mutableListOf() open?.let { @@ -141,13 +140,13 @@ class QuoteDetailViewModel(application: Application) : AndroidViewModel(applicat Injector.appComponent.inject(this) } + fun loadQuote(ticker: String) = viewModelScope.launch { + _quote.emit(FetchResult.success(checkNotNull(stocksProvider.getStock(ticker)))) + } + fun fetchQuote(ticker: String) { viewModelScope.launch { - if (_quote.value != null && _quote.value!!.wasSuccessful) { - _quote.emit(_quote.value) - return@launch - } - _quote.value = stocksProvider.fetchStock(ticker) + _quote.emit(stocksProvider.fetchStock(ticker)) } } diff --git a/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/AddAlertsActivity.kt b/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/AddAlertsActivity.kt index b6f8f14d..62a59087 100644 --- a/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/AddAlertsActivity.kt +++ b/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/AddAlertsActivity.kt @@ -20,7 +20,6 @@ class AddAlertsActivity : BaseActivity() { override val binding: (ActivityAlertsBinding) by viewBinding(ActivityAlertsBinding::inflate) companion object { - const val QUOTE = "QUOTE" const val TICKER = "TICKER" } @@ -116,9 +115,7 @@ class AddAlertsActivity : BaseActivity() { } private fun updateActivityResult() { - val quote = checkNotNull(viewModel.quote) val data = Intent() - data.putExtra(QUOTE, quote) setResult(Activity.RESULT_OK, data) } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/AddNotesActivity.kt b/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/AddNotesActivity.kt index 88bbcdf4..e478240f 100644 --- a/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/AddNotesActivity.kt +++ b/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/AddNotesActivity.kt @@ -6,7 +6,6 @@ import android.os.Bundle import androidx.activity.viewModels import com.github.premnirmal.ticker.base.BaseActivity import com.github.premnirmal.ticker.components.InAppMessage -import com.github.premnirmal.ticker.components.Injector import com.github.premnirmal.ticker.dismissKeyboard import com.github.premnirmal.ticker.viewBinding import com.github.premnirmal.tickerwidget.R @@ -16,7 +15,6 @@ class AddNotesActivity : BaseActivity() { override val binding: (ActivityNotesBinding) by viewBinding(ActivityNotesBinding::inflate) companion object { - const val QUOTE = "QUOTE" const val TICKER = "TICKER" } @@ -25,7 +23,6 @@ class AddNotesActivity : BaseActivity() { private val viewModel: NotesViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { - Injector.appComponent.inject(this) super.onCreate(savedInstanceState) binding.toolbar.setNavigationOnClickListener { finish() @@ -64,9 +61,7 @@ class AddNotesActivity : BaseActivity() { } private fun updateActivityResult() { - val quote = checkNotNull(viewModel.quote) val data = Intent() - data.putExtra(QUOTE, quote) setResult(Activity.RESULT_OK, data) } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/AddPositionActivity.kt b/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/AddPositionActivity.kt index e8585a68..90d43bf2 100644 --- a/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/AddPositionActivity.kt +++ b/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/AddPositionActivity.kt @@ -3,20 +3,18 @@ package com.github.premnirmal.ticker.portfolio import android.app.Activity import android.content.Intent import android.os.Bundle -import android.view.LayoutInflater +import androidx.activity.viewModels import androidx.appcompat.app.AlertDialog -import androidx.lifecycle.lifecycleScope import com.github.premnirmal.ticker.AppPreferences import com.github.premnirmal.ticker.base.BaseActivity import com.github.premnirmal.ticker.components.InAppMessage -import com.github.premnirmal.ticker.components.Injector import com.github.premnirmal.ticker.dismissKeyboard import com.github.premnirmal.ticker.network.data.Holding +import com.github.premnirmal.ticker.network.data.Quote import com.github.premnirmal.ticker.viewBinding import com.github.premnirmal.tickerwidget.R import com.github.premnirmal.tickerwidget.databinding.ActivityPositionsBinding import com.github.premnirmal.tickerwidget.databinding.LayoutPositionHoldingBinding -import kotlinx.coroutines.launch import java.text.NumberFormat /** @@ -26,16 +24,14 @@ class AddPositionActivity : BaseActivity() { override val binding: (ActivityPositionsBinding) by viewBinding(ActivityPositionsBinding::inflate) companion object { - const val QUOTE = "QUOTE" const val TICKER = "TICKER" } internal lateinit var ticker: String - override val simpleName: String = "AddPositionActivity" - + override val simpleName = "AddPositionActivity" + private val viewModel: AddPositionViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { - Injector.appComponent.inject(this) super.onCreate(savedInstanceState) binding.toolbar.setNavigationOnClickListener { finish() @@ -48,18 +44,21 @@ class AddPositionActivity : BaseActivity() { finish() return } + viewModel.loadQuote(ticker) + viewModel.quote.observe(this) { + updateTotal(it) + } binding.tickerName.text = ticker binding.addButton.setOnClickListener { onAddClicked() } binding.positionsHolder.removeAllViews() - val position = stocksProvider.getPosition(ticker) + val position = viewModel.getPosition(ticker) position?.let { for (holding in position.holdings) { addPositionView(holding) } } - updateTotal() } private fun onAddClicked() { @@ -97,12 +96,10 @@ class AddPositionActivity : BaseActivity() { if (success) { binding.priceInputLayout.error = null binding.sharesInputLayout.error = null - lifecycleScope.launch { - val holding = stocksProvider.addHolding(ticker, shares, price) + viewModel.addHolding(ticker, shares, price).observe(this) { holding -> priceView.setText("") sharesView.setText("") addPositionView(holding) - updateTotal() updateActivityResult() } } @@ -111,9 +108,7 @@ class AddPositionActivity : BaseActivity() { } private fun updateActivityResult() { - val quote = checkNotNull(stocksProvider.getStock(ticker)) val data = Intent() - data.putExtra(QUOTE, quote) setResult(Activity.RESULT_OK, data) } @@ -133,11 +128,9 @@ class AddPositionActivity : BaseActivity() { .setTitle(R.string.remove) .setMessage(getString(R.string.remove_holding, "${holding.shares}@${holding.price}")) .setPositiveButton(R.string.remove) { dialog, _ -> - lifecycleScope.launch { - stocksProvider.removePosition(ticker, holding) - binding.positionsHolder.removeView(positionBinding.root) - updateTotal() - } + viewModel.removePosition(ticker, holding) + binding.positionsHolder.removeView(positionBinding.root) + updateActivityResult() dialog.dismiss() } .setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() } @@ -145,8 +138,7 @@ class AddPositionActivity : BaseActivity() { } } - private fun updateTotal() { - val quote = checkNotNull(stocksProvider.getStock(ticker)) + private fun updateTotal(quote: Quote) { binding.totalShares.text = quote.numSharesString() binding.averagePrice.text = quote.averagePositionPrice() binding.totalValue.text = quote.totalSpentString() diff --git a/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/AddPositionViewModel.kt b/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/AddPositionViewModel.kt new file mode 100644 index 00000000..6da43127 --- /dev/null +++ b/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/AddPositionViewModel.kt @@ -0,0 +1,52 @@ +package com.github.premnirmal.ticker.portfolio + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.liveData +import androidx.lifecycle.viewModelScope +import com.github.premnirmal.ticker.components.Injector +import com.github.premnirmal.ticker.model.IStocksProvider +import com.github.premnirmal.ticker.network.data.Holding +import com.github.premnirmal.ticker.network.data.Position +import com.github.premnirmal.ticker.network.data.Quote +import kotlinx.coroutines.launch +import javax.inject.Inject + +class AddPositionViewModel : ViewModel() { + + @Inject internal lateinit var stocksProvider: IStocksProvider + + init { + Injector.appComponent.inject(this) + } + + val quote: LiveData + get() = _quote + private val _quote = MutableLiveData() + + fun getPosition(symbol: String): Position? { + return stocksProvider.getPosition(symbol) + } + + fun loadQuote(symbol: String) = viewModelScope.launch { + _quote.value = getQuote(symbol) + } + + fun removePosition(symbol: String, holding: Holding) { + viewModelScope.launch { + stocksProvider.removePosition(symbol, holding) + loadQuote(symbol) + } + } + + fun addHolding(symbol: String, shares: Float, price: Float) = liveData { + val holding = stocksProvider.addHolding(symbol, shares, price) + emit(holding) + loadQuote(symbol) + } + + private fun getQuote(symbol: String): Quote { + return checkNotNull(stocksProvider.getStock(symbol)) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/search/SearchActivity.kt b/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/search/SearchActivity.kt index 6bbe9c7e..196e0f13 100644 --- a/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/search/SearchActivity.kt +++ b/app/src/main/kotlin/com/github/premnirmal/ticker/portfolio/search/SearchActivity.kt @@ -5,7 +5,6 @@ import android.content.Context import android.content.Intent import android.os.Bundle import com.github.premnirmal.ticker.base.BaseActivity -import com.github.premnirmal.ticker.components.Injector import com.github.premnirmal.ticker.viewBinding import com.github.premnirmal.tickerwidget.R import com.github.premnirmal.tickerwidget.databinding.ActivitySearchBinding @@ -29,9 +28,7 @@ class SearchActivity : BaseActivity() { var widgetId: Int = -1 - override fun onCreate(savedInstanceState: Bundle?) { - Injector.appComponent.inject(this) super.onCreate(savedInstanceState) widgetId = intent.getIntExtra(ARG_WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID) if (savedInstanceState == null) { diff --git a/app/src/main/kotlin/com/github/premnirmal/ticker/settings/WidgetSettingsActivity.kt b/app/src/main/kotlin/com/github/premnirmal/ticker/settings/WidgetSettingsActivity.kt index 7770a357..de9bf3a1 100644 --- a/app/src/main/kotlin/com/github/premnirmal/ticker/settings/WidgetSettingsActivity.kt +++ b/app/src/main/kotlin/com/github/premnirmal/ticker/settings/WidgetSettingsActivity.kt @@ -7,7 +7,6 @@ import android.graphics.PorterDuff import android.os.Bundle import androidx.core.content.ContextCompat import com.github.premnirmal.ticker.base.BaseActivity -import com.github.premnirmal.ticker.components.Injector import com.github.premnirmal.ticker.portfolio.search.SearchActivity import com.github.premnirmal.ticker.viewBinding import com.github.premnirmal.tickerwidget.R @@ -23,9 +22,7 @@ class WidgetSettingsActivity : BaseActivity(), Wi internal var widgetId = 0 override val simpleName: String = "WidgetSettingsActivity" - override fun onCreate(savedInstanceState: Bundle?) { - Injector.appComponent.inject(this) super.onCreate(savedInstanceState) binding.toolbar.setNavigationOnClickListener { setOkResult() diff --git a/app/version.properties b/app/version.properties index f12d1777..6d22ef58 100644 --- a/app/version.properties +++ b/app/version.properties @@ -1,3 +1,3 @@ # this file is purely for f-droid because it cannot infer the version name/code from the git tag -versionName=3.9.789 -versionCode=300900789 +versionName=3.9.790 +versionCode=300900790