0

I'm building a project using ViewModel, Compose and Hilt. I can't switch to BookListScreen because I am getting the error in the title. Points that I think are important:

  • onItemClick = { navController.navigate(Screen.BookListScreen.route) } in MainScreen.
  • composable(route = Screen.BookListScreen.route) { BookListScreen(navController) }

in MainActivity.

  • And @AndroidEntryPoint annotation. I've added this to MainActivity but do I need to add it elsewhere?

Main Activity:

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            LOTRTheme {
                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {
                    val navController = rememberNavController()
                    NavHost(
                        navController = navController,
                        startDestination = Screen.MainScreen.route
                    ) {
                        composable(
                            route = Screen.MainScreen.route
                        ) {
                            MainScreen(navController)
                        }
                        composable(
                            route = Screen.BookListScreen.route
                        ) {
                            BookListScreen(navController)
                        }
                    }
                }
            }
        }
    }
}

Main Screen:

@Composable
fun MainScreen(navController: NavController) {
    val configuration = LocalConfiguration.current
    when (configuration.orientation) {
        Configuration.ORIENTATION_LANDSCAPE -> {
            SectionsScreenRotate(navController)
        }
        else -> {
            SectionsScreen(navController)
        }
    }
}

@Composable
fun SectionsScreen(navController: NavController) {
    Column(
        modifier = Modifier.padding(10.dp)
    ) {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .weight(1f)
                .padding(10.dp)
        ) {
            SectionItem(
                section = Section("Characters", R.drawable.charachtersdraw),
                onItemClick = {}
            )
        }

        Column(
            modifier = Modifier
                .fillMaxHeight()
                .weight(1f)
                .padding(10.dp)
        ) {
            SectionItem(
                section = Section("Movies", R.drawable.moviesdraw),
                onItemClick = {}
            )
        }
        Column(
            modifier = Modifier
                .fillMaxHeight()
                .weight(1f)
                .padding(10.dp)
        ) {
            SectionItem(
                section = Section("Books", R.drawable.booksdraw),
                onItemClick = { navController.navigate(Screen.BookListScreen.route) }
            )
        }
    }
}

@Composable
fun SectionsScreenRotate(navController: NavController) {
    Row(
        modifier = Modifier.padding(10.dp)
    ) {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .weight(1f)
                .padding(10.dp)
        ) {
            SectionItem(
                section = Section("Characters", R.drawable.charachtersdraw),
                onItemClick = {}
            )
        }

        Column(
            modifier = Modifier
                .fillMaxHeight()
                .weight(1f)
                .padding(10.dp)
        ) {
            SectionItem(
                section = Section("Movies", R.drawable.moviesdraw),
                onItemClick = { navController.navigate(Screen.BookListScreen.route)}
            )
        }
        Column(
            modifier = Modifier
                .fillMaxHeight()
                .weight(1f)
                .padding(10.dp)
        ) {
            SectionItem(
                section = Section("Books", R.drawable.booksdraw),
                onItemClick = {}
            )
        }
    }

}

@Composable
fun SectionItem(section: Section, onItemClick: () -> Unit) {
    Card(
        modifier = Modifier
            .fillMaxSize()
            .clickable { onItemClick() },
        shape = RoundedCornerShape(15.dp),
        elevation = 5.dp,
    ) {
        Box(modifier = Modifier.fillMaxSize()) {
            Image(
                painter = painterResource(id = section.imageId),
                contentDescription = section.title,
                contentScale = ContentScale.Crop,
                modifier = Modifier.fillMaxSize()
            )
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .padding(12.dp),
                contentAlignment = Alignment.BottomCenter
            ) {
                Text(
                    section.title, style = TextStyle(
                        color = Color.White,
                        fontSize = 16.sp,
                        fontWeight = FontWeight.Bold,
                    )

                )
            }

        }

    }
}

BookListScreen:

@Composable
fun BookListScreen(
    navController: NavController,
    bookListViewModel: BookListViewModel = viewModel()
) {
    val state = bookListViewModel.state.value

    Box(modifier = Modifier.fillMaxSize()) {
        LazyColumn(modifier = Modifier.fillMaxSize()) {
            items(state.books) { book ->
                BookListItem(
                    book = book
                )
            }
        }
        if (state.error.isNotBlank()) {
            Text(
                text = state.error,
                color = MaterialTheme.colors.error,
                textAlign = TextAlign.Center,
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(horizontal = 20.dp)
                    .align(Alignment.Center)
            )
        }
        if (state.isLoading) {
            CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
        }
    }
}

ViewModel:

@HiltViewModel
class BookListViewModel @Inject constructor(
    private val bookRepository: BookRepository
) : ViewModel(){

    val state = mutableStateOf(BookListState())

    init {
        getBooks()
    }

    private fun getBooks() {
        bookRepository.getBooks().onEach { result ->
            when(result) {
                is Resource.Success -> {
                    state.value = BookListState(books = result.data ?: emptyList())
                }
                is Resource.Error -> {
                    state.value = BookListState(error = result.message ?: "Beklenmedik bir hata oluştu")
                }
                is Resource.Loading -> {
                    state.value = BookListState(isLoading = true)
                }
            }
        }.launchIn(viewModelScope)
    }

}

AppModule:

@Module
@InstallIn(SingletonComponent::class)
object AppModule {

    @Provides
    @Singleton
    fun getLotrApi() : LotrApi {
        return Retrofit.Builder()
            .baseUrl(Constants.BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(LotrApi::class.java)
    }

    @Provides
    @Singleton
    fun getBookRepository(api: LotrApi) : BookRepository {
        return BookRepository(api)
    }
}

BookRepository:

    class BookRepository @Inject constructor(
    private val api : LotrApi
){

    fun getBooks() : Flow<Resource<List<Book>>> = flow {
        try {
            emit(Resource.Loading<List<Book>>())
            val books = api.getBookList().BookListDtoToBookList()
            emit(Resource.Success<List<Book>>(books))
        }
        catch (e: HttpException) {
            emit(Resource.Error<List<Book>>(e.localizedMessage ?: "Beklenmedik hata"))
        }
        catch(e: IOException) {
            emit(Resource.Error<List<Book>>(e.localizedMessage ?: "Lütfen internet bağlantınızı kontrol edin"))
        }

    }
}

Screen:

sealed class Screen(val route : String){
    object BookListScreen : Screen("book_list")
    object BookChaptersScreen : Screen("book_chapters")
    object MainScreen : Screen("main_screen")
}
1
  • 3
    Replace viewModel() with hiltViewModel() Commented Oct 31, 2021 at 3:51

1 Answer 1

4

While using Hilt along with Navigation Library, you need to use hiltViewModel() instead of viewModel() to inject ViewModels. Check out documentation for more info.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.