Why there is red line on myPhone.something1.something() ? -something1- - kotlin

fun main() {
val myPhone = Myphone()
myPhone.phoneOn()
myPhone.onClick()
myPhone.onTouch()
myPhone.openApp()
myPhone.closeApp()
myPhone.brightMax()
myPhone.Something1.something()
}
interface Application {
var appName: String
var x1: Int
fun something()
fun brightMax() {
println("Brightness level is on Max!")
}
fun openApp() {
println("$appName is opening!")
}
fun phoneOn() {
println("The phone is ON")
}
fun onClick() {
println("App is running")
}
fun closeApp() {
println("${Myphone.Something1.appName} App is closed!")
}
}
interface Button {
val x: Int
var helloMessage: String
fun brightMax() {
println("Brightness is on $x")
}
fun phoneOn() {
println("Power on button was pressed!")
}
fun onClick()
fun onTouch() {
println("The screen was touched!")
}
}
class Myphone: Button, Application {
override fun something() {
println("Doing something")
}
object Something1 : Application {
override var x1: Int = 100
override var appName: String = "Instagram"
override fun something() {
println("He wants to die!")
}
}
override var x1: Int = 12
override var appName: String = "Facebook"
override var x: Int = 100
override fun phoneOn() {
super<Application>.phoneOn()
}
override fun brightMax() {
super<Application>.brightMax()
super<Button>.brightMax()
}
override var helloMessage: String = "Hello"
override fun onClick() {
super.onClick()
}
}
I created object inside the class and I can't "call" it back in main function.
Once I did and I can't remember how to solve it again.
Don't blame me because of code. I made it for presentation.
on the 9th line, there is error, why? the something1 has red line in kotlin.
something1.appName - is working perfectly?

You get the error because it's not recommended to access nested objects via instance references. Use Myphone.Something1.something() instead of myPhone.Something1.something().

Related

Filter searchView from RecycleView with Adapter

Adapter class
class AppListAdapter(private val context: Context, initialChecked: ArrayList<String> = arrayListOf()) : RecyclerView.Adapter<AppListAdapter.AppViewHolder>() {
public val appList = arrayListOf<ApplicationInfo>()
private val checkedAppList = arrayListOf<Boolean>()
private val packageManager: PackageManager = context.packageManager
init {
context.packageManager.getInstalledApplications(PackageManager.GET_META_DATA).sortedBy { it.loadLabel(packageManager).toString() }.forEach { info ->
if (info.packageName != context.packageName) {
if (info.flags and ApplicationInfo.FLAG_SYSTEM == 0) {
appList.add(info)
checkedAppList.add(initialChecked.contains(info.packageName))
}
}
}
}
inner class AppViewHolder(private val item: ItemAppBinding) : RecyclerView.ViewHolder(item.root) {
fun bind(data: ApplicationInfo, position: Int) {
item.txApp.text = data.loadLabel(packageManager)
item.imgIcon.setImageDrawable(data.loadIcon(packageManager))
item.cbApp.isChecked = checkedAppList[position]
item.cbApp.setOnCheckedChangeListener { _, checked ->
checkedAppList[position] = checked
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppViewHolder {
return AppViewHolder(ItemAppBinding.inflate(LayoutInflater.from(context), parent, false))
}
override fun onBindViewHolder(holder: AppViewHolder, position: Int) {
holder.bind(appList[position], position)
}
override fun getItemCount(): Int {
return appList.size
}
on MainActivity
binding.searchView2.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String?): Boolean {
binding.searchView2.clearFocus()
// how to write code filtered by query?
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
// how to write code filtered by newText?
return false
}
})
I'm newbie in kotlin..anyone can help?
I believe you want to filter items with "ApplicationInfo.txApp", so i will write the code for it.
First you need your adapter class to extend Filterable like below, and add one more list to hold all items:
class AppListAdapter(private val context: Context, initialChecked: ArrayList<String> = arrayListOf()) : RecyclerView.Adapter<AppListAdapter.AppViewHolder>(), Filterable {
public val appList = arrayListOf<ApplicationInfo>()
public val appListFull = ArrayList<ApplicationInfo>(appList)
// This full list because of when you delete all the typing to searchView
// so it will get back to that full form.
Then override it's function and write your own filter to work, paste this code to your adapter:
override fun getFilter(): Filter {
return exampleFilter
}
private val exampleFilter = object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults? {
val filteredList: ArrayList<ApplicationInfo> = ArrayList()
if (constraint == null || constraint.isEmpty()) {
// when searchview is empty
filteredList.addAll(appListFull)
} else {
// when you type something
// it also uses Locale in case capital letters different.
val filterPattern = constraint.toString().lowercase(Locale.getDefault()).trim()
for (item in appListFull) {
val txApp = item.txApp
if (txApp.lowercase(Locale.getDefault()).contains(filterPattern)) {
filteredList.add(item)
}
}
}
val results = FilterResults()
results.values = filteredList
return results
}
#SuppressLint("NotifyDataSetChanged") #Suppress("UNCHECKED_CAST")
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
appList.clear()
appList.addAll(results!!.values as ArrayList<ApplicationInfo>)
notifyDataSetChanged()
}
}
And finally call this filter method in your searchview:
binding.searchView2.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String?): Boolean {
yourAdapter.filter.filter(query)
yourAdapter.notifyDataSetChanged()
binding.searchView2.clearFocus()
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
yourAdapter.filter.filter(newText)
yourAdapter.notifyDataSetChanged()
return false
}
})
These should work i'm using something similar to that, if not let me know with the problem.

how to play audio offline by url?

i want to if i press play - the audio start playing, but if I will turn off the internet after some time, I can still listen to the audio to the end, how can i do this using andoid-mediaPlayer?
in kotlin
class MusicService:Service(),MediaPlayer.OnPreparedListener,MediaPlayer.OnCompletionListener,MediaPlayer.OnErrorListener {
override fun onBind(intent: Intent?): IBinder? {
return musicBind
}
override fun onCreate() {
super.onCreate()
player= MediaPlayer()
}
fun initMusic(){
player.setWakeMode(applicationContext,PowerManager.PARTIAL_WAKE_LOCK)
player.setAudioStreamType(AudioManager.STREAM_MUSIC)
player.setOnPreparedListener(this)
player.setOnCompletionListener(this)
player.setOnErrorListener(this)
}
override fun onUnbind(intent: Intent?): Boolean {
player.stop()
player.reset()
player.release()
return false
}
inner class MusicBinder:Binder(){
val service: MusicService
get() = this#MusicService
}
companion object{
const val STOPPED = 0
const val PAUSED =1
const val PLAYING = 2
}
override fun onPrepared(mp: MediaPlayer?) {
mp!!.start()
val duration=mp.duration
seekBar.max=duration
seekBar.postDelayed(progressRunner,instentval.toLong())
end_point.text= String.format("%d:%02d",TimeUnit.MILLISECONDS.toMinutes(duration.toLong()),
TimeUnit.MILLISECONDS.toSeconds(duration.toLong())-
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration.toLong())))
}
private fun playSong(){
try {
player.reset()
val playSong=songs
val uri = playSong.link
player=MediaPlayer.create(this, Uri.parse(uri))
try {
player.start()
progressRunner.run()
}catch (e:HttpException){
Toast.makeText(this,"Http went wrong!",Toast.LENGTH_SHORT).show()
}
} catch (e:Exception){
Toast.makeText(this,"something went wrong!",Toast.LENGTH_SHORT).show()
}
}
fun setUI(seekBar: SeekBar,start_int:TextView,end_int:TextView){
this.seekBar=seekBar
start_point=start_int
end_point=end_int
seekBar.setOnSeekBarChangeListener(object :SeekBar.OnSeekBarChangeListener
{
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
if (fromUser){
player.seekTo(progress)
}
start_point.text = String.format(
"%d:%02d",TimeUnit.MILLISECONDS.toMinutes(progress.toLong()),
TimeUnit.MILLISECONDS.toSeconds(progress.toLong())-
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(progress.toLong())))
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
TODO("Not yet implemented")
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
TODO("Not yet implemented")
}
}
)
}
private var progressRunner:Runnable = object :Runnable {
override fun run() {
if (seekBar!=null){
seekBar.progress=player.currentPosition
if (player.isPlaying){
seekBar.postDelayed(this,instentval.toLong())
}
}
}
}
fun setSong(result: Result){
songs=result
playerState= PLAYING
playSong()
}
fun setSongmp3(mp3: Mp3){
songsmp3=mp3
playerState= PLAYING
playSongmp3()
}
public fun puseSong()
{
player.pause()
playerState = PAUSED
}
public fun resumeSong(){
player.start()
playerState= PLAYING
}
override fun onCompletion(mp: MediaPlayer?) {
}
override fun onError(mp: MediaPlayer?, what: Int, extra: Int): Boolean {
return false
}
}

Android SearchView onQueryTextChange doesn't work with ObservableOnSubscribe

I've got such code for searching streams by their name.
compositeDisposable.add(Observable.create(ObservableOnSubscribe<String> { subscriber ->
binding.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextChange(newText: String?): Boolean {
subscriber.onNext(newText!!)
return false
}
override fun onQueryTextSubmit(query: String?): Boolean {
subscriber.onNext(query!!)
return false
}
})
})
.debounce(250, TimeUnit.MILLISECONDS)
.distinct()
.subscribe { text ->
val pagerPos = binding.streamsPager.currentItem
val currentFragment =
activity?.supportFragmentManager?.findFragmentByTag("f${pagerAdapter.getItemId(pagerPos)}")
(currentFragment as StreamFragment).onSearchHolder.onSearch(text)
}
)
It works fine with onQueryTextSubmit, but ignores setOnQueryTextListener. So when I want to erase symbols and "reset" search I get nothing
How to fix this?
use a wrapper class for your ObservableOnSubscribe and sealed class for your search events. Like this:
class SearchViewWrapper(private val searchView: SearchView) : ObservableOnSubscribe<SearchViewEvent> {
override fun subscribe(emitter: ObservableEmitter<SearchViewEvent>) {
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
emitter.onNext(SearchViewEvent.onQueryTextSumbit(query))
return true
}
override fun onQueryTextChange(newText: String?): Boolean {
emitter.onNext(SearchViewEvent.onQueryChanged(newText))
return true
}
})
}
}
Sealed class for events:
sealed class SearchViewEvent {
data class onQueryChanged(val text: String?): SearchViewEvent()
data class onQueryTextSumbit(val query: String?): SearchViewEvent()
}
Try to use it where you need(just example):
fun useIt(searchView: SearchView) {
Observable.create(SearchViewWrapper(searchView))
.subscribe(::handleSearchViewEvent)
.addTo(yourCompositeDisposable)
}
private fun handleSearchViewEvent(event: SearchViewEvent) {
when (event) {
is SearchViewEvent.onQueryChanged -> TODO()
is SearchViewEvent.onQueryTextSumbit -> TODO()
}
}

Listening to coroutine from view cant be done from the views init

I am trying to listen to my ViewModels MutableStateFlow from my FlutterSceneView. But I get the following error when trying to set the listener from the views init:
Suspend function 'listenToBackgroundColor' should be called only from a coroutine or another suspend function
class FlutterSceneView(context: Context, private val viewModel: FlutterSceneViewModelType): PlatformView {
private val context = context
private val sceneView = SceneView(context)
init {
listenToBackgroundColor() // Error here
}
private suspend fun listenToBackgroundColor() {
viewModel.colorFlow.collect {
val newColor = Color.parseColor(it)
sceneView.setBackgroundColor(newColor)
}
}
}
My ViewModel:
interface FlutterSceneViewModelType {
var colorFlow: MutableStateFlow<String>
}
class FlutterSceneViewModel(private val database: Database): FlutterSceneViewModelType, ViewModel() {
override var colorFlow = MutableStateFlow<String>("#FFFFFF")
init {
listenToBackgroundColorFlow()
}
private fun listenToBackgroundColorFlow() {
database.backgroundColorFlow.watch {
colorFlow.value = it.hex
}
}
}
the .watch call is a helper I have added so that this can be exposed to iOS using Kotlin multi-platform, it looks as follows but I can use collect instead if necessary:
fun <T> Flow<T>.asCommonFlow(): CommonFlow<T> = CommonFlow(this)
class CommonFlow<T>(private val origin: Flow<T>) : Flow<T> by origin {
fun watch(block: (T) -> Unit): Closeable {
val job = Job()
onEach {
block(it)
}.launchIn(CoroutineScope(Dispatchers.Main + job))
return object : Closeable {
override fun close() {
job.cancel()
}
}
}
}
I resolved this by using viewModel context:
private fun listenToBackgroundColor() {
viewModel.colorFlow.onEach {
val newColor = Color.parseColor(it)
sceneView.setBackgroundColor(newColor)
}.launchIn(viewModel.viewModelScope)
}
I had to import the following into my ViewModel:
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
from:
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0")

Kotlin Coroutine Unit Test Flow collection with viewModelScope

I want to test a method of my ViewModel that collects a Flow. Inside the collector a LiveData object is mutated, which I want to check in the end. This is roughly how the setup looks:
//Outside viewmodel
val f = flow { emit("Test") }.flowOn(Dispatchers.IO)
//Inside viewmodel
val liveData = MutableLiveData<String>()
fun action() {
viewModelScope.launch { privateAction() }
}
suspend fun privateAction() {
f.collect {
liveData.value = it
}
}
When I now call the action() method in my unit test, the test finishes before the flow is collected. This is how the test might look:
#Test
fun example() = runBlockingTest {
viewModel.action()
assertEquals(viewModel.liveData.value, "Test")
}
I am using the TestCoroutineDispatcher via this Junit5 extension and also the instant executor extension for LiveData:
class TestCoroutineDispatcherExtension : BeforeEachCallback, AfterEachCallback, ParameterResolver {
#SuppressLint("NewApi") // Only used in unit tests
override fun supportsParameter(parameterContext: ParameterContext?, extensionContext: ExtensionContext?): Boolean {
return parameterContext?.parameter?.type === testDispatcher.javaClass
}
override fun resolveParameter(parameterContext: ParameterContext?, extensionContext: ExtensionContext?): Any {
return testDispatcher
}
private val testDispatcher = TestCoroutineDispatcher()
override fun beforeEach(context: ExtensionContext?) {
Dispatchers.setMain(testDispatcher)
}
override fun afterEach(context: ExtensionContext?) {
Dispatchers.resetMain()
testDispatcher.cleanupTestCoroutines()
}
}
class InstantExecutorExtension : BeforeEachCallback, AfterEachCallback {
override fun beforeEach(context: ExtensionContext?) {
ArchTaskExecutor.getInstance()
.setDelegate(object : TaskExecutor() {
override fun executeOnDiskIO(runnable: Runnable) = runnable.run()
override fun postToMainThread(runnable: Runnable) = runnable.run()
override fun isMainThread(): Boolean = true
})
}
override fun afterEach(context: ExtensionContext?) {
ArchTaskExecutor.getInstance().setDelegate(null)
}
}
You can try either,
fun action() = viewModelScope.launch { privateAction() }
suspend fun privateAction() {
f.collect {
liveData.value = it
}
}
#Test
fun example() = runBlockingTest {
viewModel.action().join()
assertEquals(viewModel.liveData.value, "Test")
}
or
fun action() {
viewModelScope.launch { privateAction()
}
suspend fun privateAction() {
f.collect {
liveData.value = it
}
}
#Test
fun example() = runBlockingTest {
viewModel.action()
viewModel.viewModelScope.coroutineContext[Job]!!.join()
assertEquals(viewModel.liveData.value, "Test")
}
You could also try this,
suspend fun <T> LiveData<T>.awaitValue(): T? {
return suspendCoroutine { cont ->
val observer = object : Observer<T> {
override fun onChanged(t: T?) {
removeObserver(this)
cont.resume(t)
}
}
observeForever(observer)
}
}
#Test
fun example() = runBlockingTest {
viewModel.action()
assertEquals(viewModel.liveData.awaitValue(), "Test")
}
So what I ended up doing is just passing the Dispatcher to the viewmodel constructor:
class MyViewModel(..., private val dispatcher = Dispatchers.Main)
and then using it like this:
viewModelScope.launch(dispatcher) {}
So now I can override this when I instantiate the ViewModel in my test with a TestCoroutineDispatcher and then advance the time, use testCoroutineDispatcher.runBlockingTest {}, etc.