diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index 217e5c5..fe63bb6 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index ff17fc7..f0cb1fa 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,8 +1,8 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
- id 'kotlin-kapt'
id 'com.google.dagger.hilt.android'
+ id 'com.google.devtools.ksp'
}
android {
@@ -55,7 +55,7 @@ android {
buildConfig true
}
composeOptions {
- kotlinCompilerExtensionVersion '1.4.7'
+ kotlinCompilerExtensionVersion '1.5.11'
}
packagingOptions {
resources {
@@ -73,7 +73,7 @@ dependencies {
implementation 'androidx.core:core-ktx:1.12.0'
implementation platform('org.jetbrains.kotlin:kotlin-bom:1.8.0')
- implementation 'androidx.activity:activity-compose:1.8.1'
+ implementation 'androidx.activity:activity-compose:1.8.2'
implementation platform('androidx.compose:compose-bom:2023.06.01')
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.ui:ui-graphics'
@@ -90,12 +90,12 @@ dependencies {
//Dagger-Hilt
def hilt_version = "2.47"
implementation "com.google.dagger:hilt-android:$hilt_version"
- kapt "com.google.dagger:hilt-compiler:$hilt_version"
- kapt "androidx.hilt:hilt-compiler:1.1.0"
- implementation "androidx.hilt:hilt-navigation-compose:1.1.0"
+ ksp "com.google.dagger:hilt-compiler:$hilt_version"
+ ksp "androidx.hilt:hilt-compiler:1.2.0"
+ implementation "androidx.hilt:hilt-navigation-compose:1.2.0"
// Coroutines
- def coroutine_version = "1.5.2"
+ def coroutine_version = "1.8.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutine_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutine_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutine_version"
@@ -109,18 +109,27 @@ dependencies {
//Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
- implementation 'com.squareup.okhttp3:okhttp:4.11.0'
+ implementation 'com.squareup.okhttp3:okhttp:4.12.0'
//Coil
- implementation "io.coil-kt:coil-compose:2.4.0"
+ implementation "io.coil-kt:coil-compose:2.6.0"
+
+ //Glide
+ implementation("com.github.bumptech.glide:compose:1.0.0-beta01")
//Extended Icons
- implementation "androidx.compose.material:material-icons-extended:1.5.0"
+ implementation "androidx.compose.material:material-icons-extended:1.6.4"
//Browser View
- implementation 'androidx.browser:browser:1.7.0'
+ implementation 'androidx.browser:browser:1.8.0'
//Permissions
implementation "com.google.accompanist:accompanist-permissions:0.23.1"
+// Room
+ def roomVersion = "2.6.1"
+ implementation "androidx.room:room-runtime:$roomVersion"
+ implementation "androidx.room:room-ktx:$roomVersion"
+ ksp "androidx.room:room-compiler:$roomVersion"
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/bera/josaahelpertool/di/AppModule.kt b/app/src/main/java/com/bera/josaahelpertool/di/AppModule.kt
index 9e67346..1531e9b 100644
--- a/app/src/main/java/com/bera/josaahelpertool/di/AppModule.kt
+++ b/app/src/main/java/com/bera/josaahelpertool/di/AppModule.kt
@@ -3,10 +3,12 @@ package com.bera.josaahelpertool.di
import android.content.Context
import com.bera.josaahelpertool.network.CutoffApi
import com.bera.josaahelpertool.network.QuotesApi
+import com.bera.josaahelpertool.network.UnsplashApi
import com.bera.josaahelpertool.network.connectivity.ConnectivityObserver
import com.bera.josaahelpertool.network.okhttp.CacheInterceptor
import com.bera.josaahelpertool.network.okhttp.ForceCacheInterceptor
import com.bera.josaahelpertool.repository.CutoffRepository
+import com.bera.josaahelpertool.repository.UniversityImageRepository
import com.bera.josaahelpertool.utils.Constants
import dagger.Module
import dagger.Provides
@@ -28,6 +30,10 @@ object AppModule {
@Provides
fun provideCutoffRepository(api: CutoffApi) = CutoffRepository(api)
+ @Singleton
+ @Provides
+ fun provideUniversityImageRepository(api: UnsplashApi) = UniversityImageRepository(api)
+
@Singleton
@Provides
fun provideCutoffApi(@ApplicationContext appContext: Context, connectivityObserver: ConnectivityObserver): CutoffApi {
@@ -56,6 +62,16 @@ object AppModule {
.create(QuotesApi::class.java)
}
+ @Singleton
+ @Provides
+ fun provideUnsplashApi(): UnsplashApi {
+ return Retrofit.Builder()
+ .baseUrl(Constants.BASE_URL_UNSPLASH)
+ .addConverterFactory(GsonConverterFactory.create())
+ .build()
+ .create(UnsplashApi::class.java)
+ }
+
@Singleton
@Provides
fun provideConnectivityObserver(@ApplicationContext appContext: Context): ConnectivityObserver =
diff --git a/app/src/main/java/com/bera/josaahelpertool/models/UniversityImage.kt b/app/src/main/java/com/bera/josaahelpertool/models/UniversityImage.kt
new file mode 100644
index 0000000..f5a2261
--- /dev/null
+++ b/app/src/main/java/com/bera/josaahelpertool/models/UniversityImage.kt
@@ -0,0 +1,28 @@
+package com.bera.josaahelpertool.models
+
+import com.bera.josaahelpertool.models.ui.TopHalfItem
+import com.google.gson.annotations.SerializedName
+
+data class UniversityImageResponse(
+ val results: List
+)
+
+data class UniversityImage(
+ val description: String?,
+ @SerializedName("alt_description")
+ val altDescription: String,
+ val urls: Urls,
+)
+
+data class Urls(
+ val raw: String,
+ val full: String,
+ val regular: String,
+ val small: String,
+ val thumb: String,
+ @SerializedName("small_s3")
+ val smallS3: String
+)
+
+fun UniversityImage.toModel() =
+ TopHalfItem(imageUrl = urls.regular, name = description ?: altDescription)
\ No newline at end of file
diff --git a/app/src/main/java/com/bera/josaahelpertool/models/ui/TopHalfItem.kt b/app/src/main/java/com/bera/josaahelpertool/models/ui/TopHalfItem.kt
new file mode 100644
index 0000000..8b0ae7b
--- /dev/null
+++ b/app/src/main/java/com/bera/josaahelpertool/models/ui/TopHalfItem.kt
@@ -0,0 +1,6 @@
+package com.bera.josaahelpertool.models.ui
+
+data class TopHalfItem(
+ val imageUrl: String,
+ val name: String
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/bera/josaahelpertool/network/UnsplashApi.kt b/app/src/main/java/com/bera/josaahelpertool/network/UnsplashApi.kt
new file mode 100644
index 0000000..d991704
--- /dev/null
+++ b/app/src/main/java/com/bera/josaahelpertool/network/UnsplashApi.kt
@@ -0,0 +1,19 @@
+package com.bera.josaahelpertool.network
+
+import com.bera.josaahelpertool.models.UniversityImageResponse
+import com.bera.josaahelpertool.utils.Constants.API_KEY_UNSPLASH
+import com.bera.josaahelpertool.utils.Constants.QUERY
+import retrofit2.http.GET
+import retrofit2.http.Query
+import javax.inject.Singleton
+
+@Singleton
+interface UnsplashApi {
+ @GET("search/photos")
+ suspend fun getUniversityImages(
+ @Query("page") page: Int = 1,
+ @Query("client_id") clientId: String = API_KEY_UNSPLASH,
+ @Query("query") query: String = QUERY,
+ @Query("per_page") perPage: Int = 30
+ ): UniversityImageResponse
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/bera/josaahelpertool/repository/QuotesRepository.kt b/app/src/main/java/com/bera/josaahelpertool/repository/QuotesRepository.kt
index 0ad9864..1bc935c 100644
--- a/app/src/main/java/com/bera/josaahelpertool/repository/QuotesRepository.kt
+++ b/app/src/main/java/com/bera/josaahelpertool/repository/QuotesRepository.kt
@@ -1,6 +1,7 @@
package com.bera.josaahelpertool.repository
import com.bera.josaahelpertool.models.Quotes
+import com.bera.josaahelpertool.models.UniversityImageResponse
import com.bera.josaahelpertool.network.QuotesApi
import javax.inject.Inject
diff --git a/app/src/main/java/com/bera/josaahelpertool/repository/UniversityImageRepository.kt b/app/src/main/java/com/bera/josaahelpertool/repository/UniversityImageRepository.kt
new file mode 100644
index 0000000..b555694
--- /dev/null
+++ b/app/src/main/java/com/bera/josaahelpertool/repository/UniversityImageRepository.kt
@@ -0,0 +1,14 @@
+package com.bera.josaahelpertool.repository
+
+import android.util.Log
+import com.bera.josaahelpertool.models.UniversityImageResponse
+import com.bera.josaahelpertool.network.UnsplashApi
+import javax.inject.Inject
+import kotlin.random.Random
+
+class UniversityImageRepository @Inject constructor(private val unsplashApi: UnsplashApi) {
+ suspend fun getUniversityImages(): UniversityImageResponse {
+ val page = Random.nextInt(1, 4)
+ return unsplashApi.getUniversityImages(page)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/bera/josaahelpertool/screens/home/HomeScreen.kt b/app/src/main/java/com/bera/josaahelpertool/screens/home/HomeScreen.kt
index 0ced892..8f17aab 100644
--- a/app/src/main/java/com/bera/josaahelpertool/screens/home/HomeScreen.kt
+++ b/app/src/main/java/com/bera/josaahelpertool/screens/home/HomeScreen.kt
@@ -1,6 +1,11 @@
+@file:OptIn(ExperimentalGlideComposeApi::class, ExperimentalGlideComposeApi::class,
+ ExperimentalGlideComposeApi::class
+)
+
package com.bera.josaahelpertool.screens.home
import android.net.Uri
+import android.util.Log
import androidx.browser.customtabs.CustomTabsIntent
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
@@ -42,6 +47,8 @@ import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -57,10 +64,14 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
+import coil.compose.AsyncImage
+import com.bera.josaahelpertool.models.ui.TopHalfItem
import com.bera.josaahelpertool.navigation.Routes
import com.bera.josaahelpertool.ui.theme.rubikFamily
import com.bera.josaahelpertool.utils.CustomDivider
import com.bera.josaahelpertool.utils.ShimmerListItem
+import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi
+import com.bumptech.glide.integration.compose.GlideImage
import kotlinx.coroutines.launch
import kotlin.reflect.KSuspendFunction2
@@ -70,6 +81,10 @@ fun HomeScreen(
navController: NavController,
viewModel: HomeViewModel
) {
+
+
+ val slideImages by viewModel.slideImages.collectAsState()
+
Surface(modifier = Modifier.fillMaxSize()) {
LazyColumn(
@@ -153,8 +168,7 @@ fun HomeScreen(
.height(380.dp)
.padding(6.dp),
navController,
- viewModel.slideImage,
- viewModel.imageTexts,
+ slideImages,
viewModel::changeImagePage,
)
}
@@ -316,8 +330,7 @@ fun QuoteBox(modifier: Modifier, quote: String, author: String, isLoading: Boole
fun TopHalf(
modifier: Modifier = Modifier,
navController: NavController,
- slideImage: Array,
- imageText: Array,
+ topHalfItems: List,
changeImage: KSuspendFunction2
) {
@@ -326,79 +339,81 @@ fun TopHalf(
initialPage = 0,
initialPageOffsetFraction = 0f
) {
- 4
+ topHalfItems.size
}
Box(
modifier = modifier
.clip(RoundedCornerShape(16.dp))
) {
- HorizontalPager(state = pagerState, key = { slideImage[it] }) { index ->
- Image(
- painter = painterResource(id = slideImage[index]),
- contentDescription = imageText[index],
- contentScale = ContentScale.Crop,
- modifier = Modifier.fillMaxSize()
- )
- }
+ if (topHalfItems.isNotEmpty()) {
+ HorizontalPager(state = pagerState, key = { topHalfItems[it].imageUrl }) { index ->
+ GlideImage(
+ model = topHalfItems[index].imageUrl,
+ contentDescription = topHalfItems[index].toString(),
+ contentScale = ContentScale.Crop,
+ modifier = Modifier.fillMaxSize()
+ )
+ }
- FilledTonalIconButton(
- onClick = { scope.launch { changeImage(pagerState, false) } },
- modifier = Modifier
- .align(Alignment.CenterStart)
- .alpha(0.6f)
- ) {
- Icon(
- imageVector = Icons.Default.KeyboardArrowLeft,
- contentDescription = "Previous Image",
- modifier = modifier.size(24.dp),
- )
- }
+ FilledTonalIconButton(
+ onClick = { scope.launch { changeImage(pagerState, false) } },
+ modifier = Modifier
+ .align(Alignment.CenterStart)
+ .alpha(0.6f)
+ ) {
+ Icon(
+ imageVector = Icons.Default.KeyboardArrowLeft,
+ contentDescription = "Previous Image",
+ modifier = modifier.size(24.dp),
+ )
+ }
- FilledTonalIconButton(
- onClick = { scope.launch { changeImage(pagerState, true) } },
- modifier = Modifier
- .align(Alignment.CenterEnd)
- .alpha(0.6f),
- ) {
- Icon(
- imageVector = Icons.Default.KeyboardArrowRight,
- contentDescription = "Next Image",
- modifier = modifier.size(24.dp),
- )
- }
+ FilledTonalIconButton(
+ onClick = { scope.launch { changeImage(pagerState, true) } },
+ modifier = Modifier
+ .align(Alignment.CenterEnd)
+ .alpha(0.6f),
+ ) {
+ Icon(
+ imageVector = Icons.Default.KeyboardArrowRight,
+ contentDescription = "Next Image",
+ modifier = modifier.size(24.dp),
+ )
+ }
+
+ OutlinedButton(
+ colors = ButtonDefaults.outlinedButtonColors(
+ containerColor = Color.Black.copy(0.6f)
+ ),
+ onClick = { navController.navigate(Routes.CBRScreen.route) },
+ modifier = Modifier
+ .align(Alignment.BottomCenter)
+ .offset(y = (-60).dp),
+ ) {
+ Text(
+ modifier = Modifier
+ .padding(10.dp),
+ text = "NEW COLLEGE PREDICTOR",
+ fontFamily = rubikFamily,
+ fontSize = 15.sp,
+ fontWeight = FontWeight.Bold,
+ textAlign = TextAlign.Center,
+ color = Color(0xFF81D5FC)
+ )
+ }
- OutlinedButton(
- colors = ButtonDefaults.outlinedButtonColors(
- containerColor = Color.Black.copy(0.6f)
- ),
- onClick = { navController.navigate(Routes.CBRScreen.route) },
- modifier = Modifier
- .align(Alignment.BottomCenter)
- .offset(y = (-60).dp),
- ) {
Text(
modifier = Modifier
- .padding(10.dp),
- text = "NEW COLLEGE PREDICTOR",
+ .padding(10.dp)
+ .align(Alignment.BottomEnd),
+ text = topHalfItems[pagerState.currentPage].name,
+ fontSize = 10.sp,
fontFamily = rubikFamily,
- fontSize = 15.sp,
- fontWeight = FontWeight.Bold,
- textAlign = TextAlign.Center,
- color = Color(0xFF81D5FC)
+ fontWeight = FontWeight.Thin,
+ color = Color.White.copy(alpha = 0.8f)
)
}
-
- Text(
- modifier = Modifier
- .padding(10.dp)
- .align(Alignment.BottomEnd),
- text = imageText[pagerState.currentPage],
- fontSize = 10.sp,
- fontFamily = rubikFamily,
- fontWeight = FontWeight.Thin,
- color = Color.White.copy(alpha = 0.8f)
- )
}
}
diff --git a/app/src/main/java/com/bera/josaahelpertool/screens/home/HomeViewModel.kt b/app/src/main/java/com/bera/josaahelpertool/screens/home/HomeViewModel.kt
index 96b1c8e..d9aa05c 100644
--- a/app/src/main/java/com/bera/josaahelpertool/screens/home/HomeViewModel.kt
+++ b/app/src/main/java/com/bera/josaahelpertool/screens/home/HomeViewModel.kt
@@ -9,17 +9,25 @@ import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.bera.josaahelpertool.R
+import com.bera.josaahelpertool.models.ui.TopHalfItem
import com.bera.josaahelpertool.use_cases.GetQuotesUseCase
+import com.bera.josaahelpertool.use_cases.GetUniversityImagesUseCase
import com.bera.josaahelpertool.utils.Resource
import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import javax.inject.Inject
@OptIn(ExperimentalFoundationApi::class)
@HiltViewModel
class HomeViewModel @Inject constructor(
- private val getQuotesUseCase: GetQuotesUseCase
+ private val getQuotesUseCase: GetQuotesUseCase,
+ private val getUniversityImagesUseCase: GetUniversityImagesUseCase
) : ViewModel() {
val drawableIds =
@@ -29,14 +37,8 @@ class HomeViewModel @Inject constructor(
R.drawable.img_6,
R.drawable.img_1
)
-
- val slideImage =
- arrayOf(
- R.drawable.ogc,
- R.drawable.iit,
- R.drawable.nit,
- R.drawable.iitbombay
- )
+ private val _slideImages = MutableStateFlow>(emptyList())
+ val slideImages get() = _slideImages.asStateFlow()
data class Link(
val link: String,
@@ -74,6 +76,16 @@ class HomeViewModel @Inject constructor(
"IIT Bombay"
)
+ private fun fetchUniversityCampusImages() {
+ viewModelScope.launch {
+ withContext(Dispatchers.IO) {
+ val allImages = getUniversityImagesUseCase.getAllImages()
+
+ _slideImages.value = allImages
+ }
+ }
+ }
+
suspend fun changeImagePage(pagerState: PagerState, next: Boolean) {
pagerState
.animateScrollToPage(
@@ -117,4 +129,8 @@ class HomeViewModel @Inject constructor(
}
}.launchIn(viewModelScope)
}
+
+ init {
+ fetchUniversityCampusImages()
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/bera/josaahelpertool/use_cases/GetUniversityImagesUseCase.kt b/app/src/main/java/com/bera/josaahelpertool/use_cases/GetUniversityImagesUseCase.kt
new file mode 100644
index 0000000..45064f4
--- /dev/null
+++ b/app/src/main/java/com/bera/josaahelpertool/use_cases/GetUniversityImagesUseCase.kt
@@ -0,0 +1,35 @@
+package com.bera.josaahelpertool.use_cases
+
+import com.bera.josaahelpertool.models.UniversityImage
+import com.bera.josaahelpertool.models.toModel
+import com.bera.josaahelpertool.models.ui.TopHalfItem
+import com.bera.josaahelpertool.repository.UniversityImageRepository
+import javax.inject.Inject
+
+class GetUniversityImagesUseCase @Inject constructor(private val repository: UniversityImageRepository) {
+ suspend fun getAllImages(): List {
+ try {
+ val response = repository.getUniversityImages()
+ val universities = response.results
+ val keywords = listOf("student", "university", "college")
+ val filtered = filterImagesByKeywords(universities, keywords)
+
+ return filtered.map { it.toModel() }
+
+ } catch (e: Exception) {
+
+ }
+ return emptyList()
+ }
+}
+
+fun filterImagesByKeywords(
+ images: List,
+ keywords: List
+): List {
+ return images.filter { image ->
+ val description = image.description ?: image.altDescription
+ val hasKeyword = keywords.any { keyword -> description.lowercase().contains(keyword) }
+ description.length < 100 && hasKeyword
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/bera/josaahelpertool/utils/Constants.kt b/app/src/main/java/com/bera/josaahelpertool/utils/Constants.kt
index 8d2dd71..9dc2a91 100644
--- a/app/src/main/java/com/bera/josaahelpertool/utils/Constants.kt
+++ b/app/src/main/java/com/bera/josaahelpertool/utils/Constants.kt
@@ -6,13 +6,16 @@ import com.bera.josaahelpertool.models.CutoffItem
object Constants {
const val BASE_URL_CUTOFF = "https://api.npoint.io/"
const val BASE_URL_QUOTES = "https://api.api-ninjas.com/"
+ const val BASE_URL_UNSPLASH = "https://api.unsplash.com/"
const val API_KEY_CUTOFF = BuildConfig.API_KEY_CUTOFF
const val API_KEY_QUOTES = BuildConfig.API_KEY_QUOTES
+ const val API_KEY_UNSPLASH = "6nlmANUApAAm_Kqer-xedtHQ61JRnzuZD3AmBaHhjoQ"
const val IIT_STRING = "Indian Institute of Technology"
const val IIT_STRING_1 = "Indian Institute of Technology"
const val NIT_STRING = "National Institute of Technology"
const val IIIT_STRING = "Indian Institute of Information Technology"
+ const val QUERY = "university campus"
val FakeCutoffItem = CutoffItem(
"",
"",
diff --git a/build.gradle b/build.gradle
index 76eb646..409e1d6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,6 +2,7 @@
plugins {
id 'com.android.application' version '8.2.0' apply false
id 'com.android.library' version '8.2.0' apply false
- id 'org.jetbrains.kotlin.android' version '1.8.21' apply false
- id 'com.google.dagger.hilt.android' version '2.44' apply false
+ id 'com.google.dagger.hilt.android' version '2.47' apply false
+ id("org.jetbrains.kotlin.android") version "1.9.23" apply false
+ id("com.google.devtools.ksp") version "1.9.23-1.0.19" apply false
}
\ No newline at end of file