Skip to content

Commit

Permalink
Merge pull request #22 from adrielcafe/fix/custom-view-context
Browse files Browse the repository at this point in the history
fix: find activity when inside compose custom view in legacy code
  • Loading branch information
adrielcafe authored Dec 16, 2021
2 parents adfacbf + 169278f commit eb3a6c0
Show file tree
Hide file tree
Showing 11 changed files with 251 additions and 12 deletions.
1 change: 1 addition & 0 deletions sample/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<activity android:name=".kodeinIntegration.KodeinIntegrationActivity"/>
<activity android:name=".koinIntegration.KoinIntegrationActivity"/>
<activity android:name=".hiltIntegration.HiltMainActivity"/>
<activity android:name=".androidLegacy.LegacyActivity"/>
</application>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.sample.androidLegacy.LegacyActivity
import cafe.adriel.voyager.sample.androidViewModel.AndroidViewModelActivity
import cafe.adriel.voyager.sample.basicNavigation.BasicNavigationActivity
import cafe.adriel.voyager.sample.bottomSheetNavigation.BottomSheetNavigationActivity
Expand Down Expand Up @@ -60,6 +61,7 @@ class SampleActivity : ComponentActivity() {
StartSampleButton<RxJavaIntegrationActivity>("RxJava Integration")
StartSampleButton<LiveDataIntegrationActivity>("LiveData Integration")
StartSampleButton<HiltMainActivity>("Hilt Integration")
StartSampleButton<LegacyActivity>("Legacy Integration")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package cafe.adriel.voyager.sample.androidLegacy

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.ui.platform.ComposeView
import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.sample.R
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class LegacyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_legacy)
val composeView = findViewById<ComposeView>(R.id.composeView)
composeView.setContent {
Navigator(LegacyScreenOne())
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package cafe.adriel.voyager.sample.androidLegacy

import cafe.adriel.voyager.core.model.ScreenModel
import cafe.adriel.voyager.hilt.ScreenModelKey
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityComponent
import dagger.multibindings.IntoMap

@Module
@InstallIn(ActivityComponent::class)
abstract class LegacyModule {
@Binds
@IntoMap
@ScreenModelKey(LegacyOneScreenModel::class)
abstract fun bindLegacyOneScreenModel(legacyOneScreenModel: LegacyOneScreenModel): ScreenModel

@Binds
@IntoMap
@ScreenModelKey(LegacyTwoScreenModel::class)
abstract fun bindLegacyTwoScreenModel(legacyTwoScreenModel: LegacyTwoScreenModel): ScreenModel
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package cafe.adriel.voyager.sample.androidLegacy

import cafe.adriel.voyager.core.model.ScreenModel
import javax.inject.Inject

class LegacyOneScreenModel @Inject constructor() : ScreenModel {
val text = "I'm legacy one screen model"

override fun onDispose() {
println(">>>> disposing $this")
super.onDispose()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package cafe.adriel.voyager.sample.androidLegacy

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.androidx.AndroidScreen
import cafe.adriel.voyager.hilt.getScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow

class LegacyScreenOne : AndroidScreen() {

@Composable
override fun Content() {
val navigator = LocalNavigator.currentOrThrow
val model: LegacyOneScreenModel = getScreenModel()

Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize()
) {
Text(
text = model.text,
style = MaterialTheme.typography.h5
)

Spacer(modifier = Modifier.height(16.dp))

Text(
text = model.toString().substringAfterLast('.'),
style = MaterialTheme.typography.body2
)

Spacer(modifier = Modifier.height(16.dp))

Button(
onClick = { navigator.push(LegacyScreenTwo()) },
content = { Text(text = "Go to Two") }
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package cafe.adriel.voyager.sample.androidLegacy

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.androidx.AndroidScreen
import cafe.adriel.voyager.hilt.getScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow

class LegacyScreenTwo : AndroidScreen() {

@Composable
override fun Content() {
val navigator = LocalNavigator.currentOrThrow
val model: LegacyTwoScreenModel = getScreenModel()

Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize()
) {
Text(
text = model.text,
style = MaterialTheme.typography.h5
)

Spacer(modifier = Modifier.height(16.dp))

Text(
text = model.toString().substringAfterLast('.'),
style = MaterialTheme.typography.body2
)

Spacer(modifier = Modifier.height(16.dp))

Button(
onClick = navigator::pop,
content = { Text(text = "Go to One") }
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package cafe.adriel.voyager.sample.androidLegacy

import cafe.adriel.voyager.core.model.ScreenModel
import javax.inject.Inject

class LegacyTwoScreenModel @Inject constructor() : ScreenModel {
val text = "I'm legacy two screen model"

override fun onDispose() {
println(">>>> disposing $this")
super.onDispose()
}
}
43 changes: 43 additions & 0 deletions sample/src/main/res/layout/activity_legacy.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".androidLegacy.LegacyActivity">

<View
android:id="@+id/emptyView"
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_centerInParent="true" />

<FrameLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_above="@id/emptyView"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:background="#FF888888">

<TextView
style="@style/TextAppearance.AppCompat.Display3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/compose_view_title" />

</FrameLayout>

<androidx.compose.ui.platform.ComposeView
android:id="@+id/composeView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_below="@id/emptyView"
android:layout_alignParentStart="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true" />

</RelativeLayout>
7 changes: 4 additions & 3 deletions sample/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<resources>
<string name="app_name">Voyager</string>
</resources>
<resources>
<string name="app_name">Voyager</string>
<string name="compose_view_title">This is a legacy content</string>
</resources>
Original file line number Diff line number Diff line change
@@ -1,9 +1,28 @@
package cafe.adriel.voyager.hilt.internal

import android.content.Context
import androidx.activity.ComponentActivity

@PublishedApi
internal val Context.componentActivity: ComponentActivity
get() = this as? ComponentActivity
?: error("Invalid local context. It must be a ComponentActivity")
package cafe.adriel.voyager.hilt.internal

import android.content.Context
import android.content.ContextWrapper
import androidx.activity.ComponentActivity
import androidx.lifecycle.ViewModelProvider

// Unfortunately findOwner function is internal in activity-compose
// TODO: Maybe move to androidx module because we'll need this function when implement onCloseRequest support
internal inline fun <reified T> findOwner(context: Context): T? {
var innerContext = context
while (innerContext is ContextWrapper) {
if (innerContext is T) {
return innerContext
}
innerContext = innerContext.baseContext
}
return null
}

@PublishedApi
internal val Context.componentActivity: ComponentActivity
get() = findOwner<ComponentActivity>(this)
?: error("Context must be a androidx.activity.ComponentActivity. Current is $this")

@PublishedApi
internal val Context.defaultViewModelProviderFactory: ViewModelProvider.Factory
get() = componentActivity.defaultViewModelProviderFactory

0 comments on commit eb3a6c0

Please sign in to comment.