Combine view models

This commit is contained in:
Philipp Heckel 2021-10-26 14:35:51 -04:00
parent 18787d36e4
commit 1c6156c638
7 changed files with 34 additions and 72 deletions

View file

@ -27,7 +27,7 @@
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme">
<activity android:name="io.heckel.ntfy.list.TopicsListActivity"> <activity android:name="io.heckel.ntfy.MainActivity">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package io.heckel.ntfy.list package io.heckel.ntfy
import android.app.Activity import android.app.Activity
import android.app.NotificationChannel import android.app.NotificationChannel
@ -33,13 +33,14 @@ import androidx.recyclerview.widget.RecyclerView
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.google.gson.JsonSyntaxException import com.google.gson.JsonSyntaxException
import io.heckel.ntfy.R
import io.heckel.ntfy.add.AddTopicActivity import io.heckel.ntfy.add.AddTopicActivity
import io.heckel.ntfy.add.TOPIC_URL import io.heckel.ntfy.add.TOPIC_URL
import io.heckel.ntfy.data.Topic import io.heckel.ntfy.data.Topic
import io.heckel.ntfy.detail.TopicDetailActivity import io.heckel.ntfy.detail.TopicDetailActivity
import io.heckel.ntfy.list.TopicsAdapter
import io.heckel.ntfy.list.TopicsViewModelFactory
import io.heckel.ntfy.list.TopicsViewModel
import kotlinx.coroutines.* import kotlinx.coroutines.*
import java.io.BufferedReader
import java.io.IOException import java.io.IOException
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.URL import java.net.URL
@ -47,12 +48,12 @@ import kotlin.random.Random
const val TOPIC_ID = "topic id" const val TOPIC_ID = "topic id"
class TopicsListActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private val gson = GsonBuilder().create() private val gson = GsonBuilder().create()
private val jobs = mutableMapOf<Long, Job>() private val jobs = mutableMapOf<Long, Job>()
private val newTopicActivityRequestCode = 1 private val newTopicActivityRequestCode = 1
private val topicsListViewModel by viewModels<TopicsListViewModel> { private val topicsListViewModel by viewModels<TopicsViewModel> {
TopicsListViewModelFactory(this) TopicsViewModelFactory(this)
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {

View file

@ -23,19 +23,27 @@ import androidx.lifecycle.ViewModelProvider
import io.heckel.ntfy.data.DataSource import io.heckel.ntfy.data.DataSource
import io.heckel.ntfy.data.Topic import io.heckel.ntfy.data.Topic
class TopicsListViewModel(val dataSource: DataSource) : ViewModel() { class TopicsViewModel(val dataSource: DataSource) : ViewModel() {
val topics: LiveData<List<Topic>> = dataSource.getTopicList() val topics: LiveData<List<Topic>> = dataSource.getTopicList()
fun add(topic: Topic) { fun add(topic: Topic) {
dataSource.addTopic(topic) dataSource.add(topic)
}
fun get(id: Long) : Topic? {
return dataSource.get(id)
}
fun remove(topic: Topic) {
dataSource.remove(topic)
} }
} }
class TopicsListViewModelFactory(private val context: Context) : ViewModelProvider.Factory { class TopicsViewModelFactory(private val context: Context) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T { override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(TopicsListViewModel::class.java)) { if (modelClass.isAssignableFrom(TopicsViewModel::class.java)) {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
return TopicsListViewModel( return TopicsViewModel(
dataSource = DataSource.getDataSource(context.resources) dataSource = DataSource.getDataSource(context.resources)
) as T ) as T
} }

View file

@ -25,7 +25,7 @@ class DataSource(resources: Resources) {
private val topicsLiveData: MutableLiveData<List<Topic>> = MutableLiveData(mutableListOf()) private val topicsLiveData: MutableLiveData<List<Topic>> = MutableLiveData(mutableListOf())
/* Adds topic to liveData and posts value. */ /* Adds topic to liveData and posts value. */
fun addTopic(topic: Topic) { fun add(topic: Topic) {
val currentList = topicsLiveData.value val currentList = topicsLiveData.value
if (currentList == null) { if (currentList == null) {
topicsLiveData.postValue(listOf(topic)) topicsLiveData.postValue(listOf(topic))
@ -37,7 +37,7 @@ class DataSource(resources: Resources) {
} }
/* Removes topic from liveData and posts value. */ /* Removes topic from liveData and posts value. */
fun removeTopic(topic: Topic) { fun remove(topic: Topic) {
val currentList = topicsLiveData.value val currentList = topicsLiveData.value
if (currentList != null) { if (currentList != null) {
val updatedList = currentList.toMutableList() val updatedList = currentList.toMutableList()
@ -47,7 +47,7 @@ class DataSource(resources: Resources) {
} }
/* Returns topic given an ID. */ /* Returns topic given an ID. */
fun getTopicForId(id: Long): Topic? { fun get(id: Long): Topic? {
topicsLiveData.value?.let { topics -> topicsLiveData.value?.let { topics ->
return topics.firstOrNull{ it.id == id} return topics.firstOrNull{ it.id == id}
} }
@ -59,12 +59,12 @@ class DataSource(resources: Resources) {
} }
companion object { companion object {
private var INSTANCE: DataSource? = null private var instance: DataSource? = null
fun getDataSource(resources: Resources): DataSource { fun getDataSource(resources: Resources): DataSource {
return synchronized(DataSource::class) { return synchronized(DataSource::class) {
val newInstance = INSTANCE ?: DataSource(resources) val newInstance = instance ?: DataSource(resources)
INSTANCE = newInstance instance = newInstance
newInstance newInstance
} }
} }

View file

@ -22,11 +22,13 @@ import android.widget.TextView
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.list.TOPIC_ID import io.heckel.ntfy.TOPIC_ID
import io.heckel.ntfy.list.TopicsViewModel
import io.heckel.ntfy.list.TopicsViewModelFactory
class TopicDetailActivity : AppCompatActivity() { class TopicDetailActivity : AppCompatActivity() {
private val topicDetailViewModel by viewModels<TopicDetailViewModel> { private val topicDetailViewModel by viewModels<TopicsViewModel> {
TopicDetailViewModelFactory(this) TopicsViewModelFactory(this)
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -47,12 +49,12 @@ class TopicDetailActivity : AppCompatActivity() {
/* If currentTopicId is not null, get corresponding topic and set name, image and /* If currentTopicId is not null, get corresponding topic and set name, image and
description */ description */
currentTopicId?.let { currentTopicId?.let {
val currentTopic = topicDetailViewModel.getTopicForId(it) val currentTopic = topicDetailViewModel.get(it)
topicUrl.text = currentTopic?.url topicUrl.text = currentTopic?.url
removeTopicButton.setOnClickListener { removeTopicButton.setOnClickListener {
if (currentTopic != null) { if (currentTopic != null) {
topicDetailViewModel.removeTopic(currentTopic) topicDetailViewModel.remove(currentTopic)
} }
finish() finish()
} }

View file

@ -1,49 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.heckel.ntfy.detail
import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import io.heckel.ntfy.data.DataSource
import io.heckel.ntfy.data.Topic
class TopicDetailViewModel(private val datasource: DataSource) : ViewModel() {
/* Queries datasource to returns a topic that corresponds to an id. */
fun getTopicForId(id: Long) : Topic? {
return datasource.getTopicForId(id)
}
/* Queries datasource to remove a topic. */
fun removeTopic(topic: Topic) {
datasource.removeTopic(topic)
}
}
class TopicDetailViewModelFactory(private val context: Context) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(TopicDetailViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return TopicDetailViewModel(
datasource = DataSource.getDataSource(context.resources)
) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}