diff --git a/app/build.gradle b/app/build.gradle index ceaeca9..7d26422 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,7 +2,7 @@ plugins { id 'com.android.application' id 'kotlin-android' id 'kotlin-kapt' - id 'org.jetbrains.kotlin.android' + id 'dagger.hilt.android.plugin' } android { @@ -20,16 +20,20 @@ android { vectorDrawables { useSupportLibrary true } + + javaCompileOptions { + annotationProcessorOptions { + arguments += [ + "room.schemaLocation" : "$projectDir/schemas".toString(), + "room.incremental" : "true", + "room.expandProjection": "true" + ] + } + } } signingConfigs { - debug { - storeFile file(project.properties["PIXELIZED_DEBUG_STORE_FILE"]) - storePassword project.properties["PIXELIZED_DEBUG_STORE_PASSWORD"] - keyAlias project.properties["PIXELIZED_DEBUG_KEY_ALIAS"] - keyPassword project.properties["PIXELIZED_DEBUG_KEY_PASSWORD"] - } - release { + pixelized { storeFile file(project.properties["PIXELIZED_RELEASE_STORE_FILE"]) storePassword project.properties["PIXELIZED_RELEASE_STORE_PASSWORD"] keyAlias project.properties["PIXELIZED_RELEASE_KEY_ALIAS"] @@ -39,65 +43,81 @@ android { buildTypes { debug { - signingConfig signingConfigs.release + signingConfig signingConfigs.pixelized minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } release { - signingConfig signingConfigs.release - minifyEnabled false + signingConfig signingConfigs.pixelized + minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } - buildFeatures { - compose true - } - compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { - jvmTarget = "1.8" + jvmTarget = '1.8' + useIR = true + } + + buildFeatures { + compose true } composeOptions { - kotlinCompilerExtensionVersion '1.0.0' + kotlinCompilerExtensionVersion '1.1.0' } + + packagingOptions { + resources { + excludes += '/META-INF/{AL2.0,LGPL2.1}' + } + } + + } dependencies { + // Android core implementation 'androidx.core:core-ktx:1.7.0' - implementation 'androidx.appcompat:appcompat:1.4.0' - implementation 'com.google.android.material:material:1.4.0' + implementation 'androidx.appcompat:appcompat:1.4.1' + implementation 'com.google.android.material:material:1.5.0' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' + implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1" + implementation 'androidx.activity:activity-compose:1.4.0' + + // Android Compose + implementation "androidx.compose.ui:ui:1.2.0-alpha03" + implementation "androidx.compose.material:material:1.1.1" + implementation "androidx.compose.runtime:runtime-livedata:1.1.1" + implementation "androidx.compose.ui:ui-tooling-preview:1.1.1" + debugImplementation "androidx.compose.ui:ui-tooling:1.1.1" - // Android compose - implementation "androidx.compose.ui:ui:1.0.5" - // Tooling support (Previews, etc.) - implementation "androidx.compose.ui:ui-tooling:1.0.5" - // Foundation (Border, Background, Box, Image, Scroll, shapes, animations, etc.) - implementation "androidx.compose.foundation:foundation:1.0.5" - // Material Design - implementation "androidx.compose.material:material:1.0.5" // Material design icons - implementation "androidx.compose.material:material-icons-core:1.0.5" - implementation "androidx.compose.material:material-icons-extended:1.0.5" - // Integration with activities - implementation "androidx.activity:activity-compose:1.4.0" - // Integration with ViewModels - implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.4.0" - // Integration with observables - implementation "androidx.compose.runtime:runtime-livedata:1.0.5" - // ConstraintLayout - implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-rc02" + implementation "androidx.compose.material:material-icons-core:1.1.1" + implementation "androidx.compose.material:material-icons-extended:1.1.1" + + // Injection + implementation 'androidx.hilt:hilt-navigation-compose:1.0.0' + implementation "com.google.dagger:hilt-android:2.40.5" + kapt "com.google.dagger:hilt-compiler:2.40.5" + + // Accompanist + implementation "com.google.accompanist:accompanist-systemuicontroller:0.24.3-alpha" + implementation "com.google.accompanist:accompanist-insets:0.24.3-alpha" + + // Navigation + implementation "androidx.navigation:navigation-compose:2.4.2" + + // Splash Screen support prior to Android 12 + implementation "androidx.core:core-splashscreen:1.0.0-beta02" // Google sign in. - implementation "com.google.android.gms:play-services-auth:19.2.0" - - // Paging - implementation "androidx.paging:paging-compose:1.0.0-alpha14" + implementation "com.google.android.gms:play-services-auth:20.1.0" // RetroFit & Gson for webservice call implementation 'com.squareup.retrofit2:retrofit:2.9.0' @@ -108,18 +128,16 @@ dependencies { implementation "com.squareup.okhttp3:logging-interceptor:4.8.1" // Room - implementation "androidx.room:room-runtime:2.3.0" - implementation "androidx.room:room-ktx:2.3.0" - kapt "androidx.room:room-compiler:2.3.0" - - // Test - testImplementation 'junit:junit:4.13.2' - androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.0.5" + implementation "androidx.room:room-runtime:2.4.2" + implementation "androidx.room:room-ktx:2.4.2" + kapt "androidx.room:room-compiler:2.4.2" + implementation "androidx.paging:paging-compose:1.0.0-alpha14" } static def generateVersionCode() { def result = "git rev-list HEAD --count".execute().text.trim() //unix - if (result.empty) result = "PowerShell -Command git rev-list HEAD --count".execute().text.trim() //windows + if (result.empty) result = "PowerShell -Command git rev-list HEAD --count".execute().text.trim() + //windows if (result.empty) throw new RuntimeException("Could not generate versioncode on this platform? Cmd output: ${result.text}") return result.toInteger() } \ No newline at end of file diff --git a/app/schemas/com.pixelized.biblib.database.BibLibDatabase/1.json b/app/schemas/com.pixelized.biblib.database.BibLibDatabase/1.json new file mode 100644 index 0000000..f8763ef --- /dev/null +++ b/app/schemas/com.pixelized.biblib.database.BibLibDatabase/1.json @@ -0,0 +1,290 @@ +{ + "formatVersion": 1, + "database": { + "version": 1, + "identityHash": "ee46b997bb81036c29a482590e47e98c", + "entities": [ + { + "tableName": "AUTHOR", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`AUTHOR_ID` TEXT NOT NULL, `AUTHOR_NAME` TEXT NOT NULL, `AUTHOR_SORT` TEXT NOT NULL, PRIMARY KEY(`AUTHOR_ID`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "AUTHOR_ID", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "AUTHOR_NAME", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sort", + "columnName": "AUTHOR_SORT", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "AUTHOR_ID" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "BOOK", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`BOOK_ID` INTEGER NOT NULL, `BOOK_TITLE` TEXT NOT NULL, `BOOK_SORT` TEXT NOT NULL, `BOOK_HAVE_COVER` INTEGER NOT NULL, `BOOK_RELEASE_DATE` INTEGER NOT NULL, `BOOK_LANGUAGE_ID` TEXT, `BOOK_RATING` INTEGER, `BOOK_SERIES_ID` TEXT, `BOOK_SYNOPSIS` TEXT, `BOOK_ISNEW` INTEGER NOT NULL, `BOOK_NEW_ORDER` INTEGER, PRIMARY KEY(`BOOK_ID`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "BOOK_ID", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "BOOK_TITLE", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sort", + "columnName": "BOOK_SORT", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "haveCover", + "columnName": "BOOK_HAVE_COVER", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "releaseDate", + "columnName": "BOOK_RELEASE_DATE", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "language", + "columnName": "BOOK_LANGUAGE_ID", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "rating", + "columnName": "BOOK_RATING", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "series", + "columnName": "BOOK_SERIES_ID", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "synopsis", + "columnName": "BOOK_SYNOPSIS", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isNew", + "columnName": "BOOK_ISNEW", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "newOrder", + "columnName": "BOOK_NEW_ORDER", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "BOOK_ID" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "GENRE", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`GENRE_ID` TEXT NOT NULL, `GENRE_NAME` TEXT NOT NULL, PRIMARY KEY(`GENRE_ID`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "GENRE_ID", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "GENRE_NAME", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "GENRE_ID" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "LANGUAGE", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`LANGUAGE_ID` TEXT NOT NULL, `LANGUAGE_NAME` TEXT NOT NULL, PRIMARY KEY(`LANGUAGE_ID`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "LANGUAGE_ID", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "code", + "columnName": "LANGUAGE_NAME", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "LANGUAGE_ID" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "SERIES", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`SERIES_ID` TEXT NOT NULL, `SERIES_NAME` TEXT NOT NULL, `SERIES_SORT` TEXT NOT NULL, `SERIES_INDEX` INTEGER, PRIMARY KEY(`SERIES_ID`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "SERIES_ID", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "SERIES_NAME", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sort", + "columnName": "SERIES_SORT", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "index", + "columnName": "SERIES_INDEX", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "columnNames": [ + "SERIES_ID" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "BookAuthorCrossRef", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`BOOK_ID` INTEGER NOT NULL, `AUTHOR_ID` TEXT NOT NULL, PRIMARY KEY(`BOOK_ID`, `AUTHOR_ID`))", + "fields": [ + { + "fieldPath": "bookId", + "columnName": "BOOK_ID", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "authorId", + "columnName": "AUTHOR_ID", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "BOOK_ID", + "AUTHOR_ID" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_BookAuthorCrossRef_AUTHOR_ID", + "unique": false, + "columnNames": [ + "AUTHOR_ID" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_BookAuthorCrossRef_AUTHOR_ID` ON `${TABLE_NAME}` (`AUTHOR_ID`)" + } + ], + "foreignKeys": [] + }, + { + "tableName": "BookGenreCrossRef", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`BOOK_ID` INTEGER NOT NULL, `GENRE_ID` TEXT NOT NULL, PRIMARY KEY(`BOOK_ID`, `GENRE_ID`))", + "fields": [ + { + "fieldPath": "bookId", + "columnName": "BOOK_ID", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "genreId", + "columnName": "GENRE_ID", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "BOOK_ID", + "GENRE_ID" + ], + "autoGenerate": false + }, + "indices": [ + { + "name": "index_BookGenreCrossRef_GENRE_ID", + "unique": false, + "columnNames": [ + "GENRE_ID" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_BookGenreCrossRef_GENRE_ID` ON `${TABLE_NAME}` (`GENRE_ID`)" + } + ], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ee46b997bb81036c29a482590e47e98c')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/BibLibApplication.kt b/app/src/main/java/com/pixelized/biblib/BibLibApplication.kt index 3b34e94..788757d 100644 --- a/app/src/main/java/com/pixelized/biblib/BibLibApplication.kt +++ b/app/src/main/java/com/pixelized/biblib/BibLibApplication.kt @@ -1,52 +1,7 @@ package com.pixelized.biblib import android.app.Application -import android.content.Context -import android.content.SharedPreferences -import androidx.room.Room -import com.google.gson.Gson -import com.google.gson.GsonBuilder -import com.pixelized.biblib.database.BibLibDatabase -import com.pixelized.biblib.network.client.BibLibClient -import com.pixelized.biblib.network.client.IBibLibClient -import com.pixelized.biblib.repository.apiCache.APICacheRepository -import com.pixelized.biblib.repository.apiCache.IAPICacheRepository -import com.pixelized.biblib.repository.book.BookRepository -import com.pixelized.biblib.repository.book.IBookRepository -import com.pixelized.biblib.repository.credential.CredentialRepository -import com.pixelized.biblib.repository.credential.ICredentialRepository -import com.pixelized.biblib.repository.googleSignIn.GoogleSingInRepository -import com.pixelized.biblib.repository.googleSignIn.IGoogleSingInRepository -import com.pixelized.biblib.repository.user.IUserRepository -import com.pixelized.biblib.repository.user.UserRepository -import com.pixelized.biblib.utils.BitmapCache -import com.pixelized.biblib.utils.injection.ServiceLocator +import dagger.hilt.android.HiltAndroidApp -class BibLibApplication : Application() { - - override fun onCreate() { - super.onCreate() - - // Android. - ServiceLocator[BibLibDatabase::class] = - Room.databaseBuilder(this, BibLibDatabase::class.java, BibLibDatabase.DATABASE_NAME) - .fallbackToDestructiveMigration() - .build() - ServiceLocator[SharedPreferences::class] = getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE) - // Web service. - ServiceLocator[Gson::class] = GsonBuilder().create() - ServiceLocator[IBibLibClient::class] = BibLibClient() - // Bitmap cache. - ServiceLocator[BitmapCache::class] = BitmapCache(this) - // Repositories. - ServiceLocator[IGoogleSingInRepository::class] = GoogleSingInRepository(this) - ServiceLocator[ICredentialRepository::class] = CredentialRepository() - ServiceLocator[IAPICacheRepository::class] = APICacheRepository() - ServiceLocator[IBookRepository::class] = BookRepository() - ServiceLocator[IUserRepository::class] = UserRepository() - } - - companion object { - private const val SHARED_PREF = "BIB_LIB_SHARED_PREF" - } -} \ No newline at end of file +@HiltAndroidApp +class BibLibApplication : Application() \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/module/NetworkModule.kt b/app/src/main/java/com/pixelized/biblib/module/NetworkModule.kt new file mode 100644 index 0000000..83eb5b5 --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/module/NetworkModule.kt @@ -0,0 +1,32 @@ +package com.pixelized.biblib.module + +import com.google.gson.Gson +import com.google.gson.GsonBuilder +import com.pixelized.biblib.network.client.BibLibClient +import com.pixelized.biblib.network.client.IBibLibClient +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +class NetworkModule { + + @Provides + @Singleton + fun provideGsonParser(): Gson { + return GsonBuilder().create() + } + + @Provides + @Singleton + fun provideBibLibClient( + gson: Gson + ): IBibLibClient { + return BibLibClient( + gson = gson + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/module/PersistenceModule.kt b/app/src/main/java/com/pixelized/biblib/module/PersistenceModule.kt new file mode 100644 index 0000000..102bbad --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/module/PersistenceModule.kt @@ -0,0 +1,52 @@ +package com.pixelized.biblib.module + +import android.app.Application +import android.content.Context +import android.content.SharedPreferences +import androidx.room.Room +import com.pixelized.biblib.database.BibLibDatabase +import com.pixelized.biblib.utils.BitmapCache +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +class PersistenceModule { + + @Provides + @Singleton + fun provideDatabase( + @ApplicationContext context: Context, + ): BibLibDatabase { + val builder = Room.databaseBuilder( + context, + BibLibDatabase::class.java, + BibLibDatabase.DATABASE_NAME + ) + return builder.fallbackToDestructiveMigration().build() + } + + @Provides + @Singleton + fun provideBitmapCache( + @ApplicationContext context: Context, + ): BitmapCache { + return BitmapCache(context) + } + + @Provides + @Singleton + fun providePreferences( + @ApplicationContext context: Context, + ): SharedPreferences { + return context.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE) + } + + companion object { + private const val SHARED_PREF = "BIB_LIB_SHARED_PREF" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/module/RepositoryModule.kt b/app/src/main/java/com/pixelized/biblib/module/RepositoryModule.kt new file mode 100644 index 0000000..ad2cba0 --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/module/RepositoryModule.kt @@ -0,0 +1,80 @@ +package com.pixelized.biblib.module + +import android.app.Application +import android.content.SharedPreferences +import com.google.gson.Gson +import com.pixelized.biblib.database.BibLibDatabase +import com.pixelized.biblib.network.client.IBibLibClient +import com.pixelized.biblib.repository.apiCache.APICacheRepository +import com.pixelized.biblib.repository.apiCache.IAPICacheRepository +import com.pixelized.biblib.repository.book.BookRepository +import com.pixelized.biblib.repository.book.IBookRepository +import com.pixelized.biblib.repository.credential.CredentialRepository +import com.pixelized.biblib.repository.credential.ICredentialRepository +import com.pixelized.biblib.repository.googleSignIn.GoogleSingInRepository +import com.pixelized.biblib.repository.googleSignIn.IGoogleSingInRepository +import com.pixelized.biblib.repository.user.IUserRepository +import com.pixelized.biblib.repository.user.UserRepository +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +class RepositoryModule { + + @Provides + @Singleton + fun provideGoogleSingInRepository( + application: Application, + ): IGoogleSingInRepository { + return GoogleSingInRepository( + application = application + ) + } + + @Provides + @Singleton + fun provideCredentialRepository( + preferences: SharedPreferences, + ): ICredentialRepository { + return CredentialRepository( + preferences = preferences, + ) + } + + @Provides + @Singleton + fun provideAPICacheRepository( + gson: Gson, + preferences: SharedPreferences, + ): IAPICacheRepository { + return APICacheRepository( + gson = gson, + preferences = preferences, + ) + } + + @Provides + @Singleton + fun provideBookRepository( + database: BibLibDatabase + ): IBookRepository { + return BookRepository( + database = database, + ) + } + + @Provides + @Singleton + fun provideUserRepository( + client: IBibLibClient, + ): IUserRepository { + return UserRepository( + client = client + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/network/client/BibLibClient.kt b/app/src/main/java/com/pixelized/biblib/network/client/BibLibClient.kt index 5884c9d..e0bcaa8 100644 --- a/app/src/main/java/com/pixelized/biblib/network/client/BibLibClient.kt +++ b/app/src/main/java/com/pixelized/biblib/network/client/BibLibClient.kt @@ -2,15 +2,16 @@ package com.pixelized.biblib.network.client import com.google.gson.Gson import com.pixelized.biblib.network.client.IBibLibClient.Companion.BASE_URL -import com.pixelized.biblib.utils.injection.inject import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory +import javax.inject.Inject -class BibLibClient : IBibLibClient { - private val gson by inject() +class BibLibClient @Inject constructor( + gson: Gson, +) : IBibLibClient { private val bearerInterceptor = BearerInterceptor() private val httpInterceptor = HttpLoggingInterceptor().apply { this.level = HttpLoggingInterceptor.Level.BODY @@ -33,6 +34,4 @@ class BibLibClient : IBibLibClient { set(value) { bearerInterceptor.token = value } - - // endregion } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/repository/apiCache/APICacheRepository.kt b/app/src/main/java/com/pixelized/biblib/repository/apiCache/APICacheRepository.kt index 2a408c6..4c3776b 100644 --- a/app/src/main/java/com/pixelized/biblib/repository/apiCache/APICacheRepository.kt +++ b/app/src/main/java/com/pixelized/biblib/repository/apiCache/APICacheRepository.kt @@ -4,11 +4,12 @@ import android.content.SharedPreferences import androidx.core.content.edit import com.google.gson.Gson import com.pixelized.biblib.network.data.response.BookListResponse -import com.pixelized.biblib.utils.injection.inject +import javax.inject.Inject -class APICacheRepository : IAPICacheRepository { - private val gson: Gson by inject() - private val preferences: SharedPreferences by inject() +class APICacheRepository @Inject constructor( + private val gson: Gson, + private val preferences: SharedPreferences, +) : IAPICacheRepository { override var new: BookListResponse? get() = preferences.new?.let { gson.fromJson(it, BookListResponse::class.java) } diff --git a/app/src/main/java/com/pixelized/biblib/repository/book/BookRepository.kt b/app/src/main/java/com/pixelized/biblib/repository/book/BookRepository.kt index f294a12..6be6250 100644 --- a/app/src/main/java/com/pixelized/biblib/repository/book/BookRepository.kt +++ b/app/src/main/java/com/pixelized/biblib/repository/book/BookRepository.kt @@ -8,10 +8,11 @@ import com.pixelized.biblib.database.crossref.BookGenreCrossRef import com.pixelized.biblib.database.data.* import com.pixelized.biblib.database.relation.BookRelation import com.pixelized.biblib.model.book.* -import com.pixelized.biblib.utils.injection.inject +import javax.inject.Inject -class BookRepository : IBookRepository { - val database: BibLibDatabase by inject() +class BookRepository @Inject constructor( + private val database: BibLibDatabase +) : IBookRepository { override fun getAll(): List = database.bookDao().getAll().map { it.toBook() } diff --git a/app/src/main/java/com/pixelized/biblib/repository/credential/CredentialRepository.kt b/app/src/main/java/com/pixelized/biblib/repository/credential/CredentialRepository.kt index ac08dfb..276e041 100644 --- a/app/src/main/java/com/pixelized/biblib/repository/credential/CredentialRepository.kt +++ b/app/src/main/java/com/pixelized/biblib/repository/credential/CredentialRepository.kt @@ -2,11 +2,12 @@ package com.pixelized.biblib.repository.credential import android.content.SharedPreferences import androidx.core.content.edit -import com.pixelized.biblib.utils.injection.inject +import javax.inject.Inject -class CredentialRepository : ICredentialRepository { - private val preferences: SharedPreferences by inject() +class CredentialRepository @Inject constructor( + private val preferences: SharedPreferences, +) : ICredentialRepository { override var login get() = preferences.login diff --git a/app/src/main/java/com/pixelized/biblib/repository/user/UserRepository.kt b/app/src/main/java/com/pixelized/biblib/repository/user/UserRepository.kt index ee947f9..27008c6 100644 --- a/app/src/main/java/com/pixelized/biblib/repository/user/UserRepository.kt +++ b/app/src/main/java/com/pixelized/biblib/repository/user/UserRepository.kt @@ -3,10 +3,11 @@ package com.pixelized.biblib.repository.user import com.pixelized.biblib.model.user.User import com.pixelized.biblib.network.client.IBibLibClient import com.pixelized.biblib.network.factory.UserFactory -import com.pixelized.biblib.utils.injection.inject +import javax.inject.Inject -class UserRepository : IUserRepository { - private val client: IBibLibClient by inject() +class UserRepository @Inject constructor( + private val client: IBibLibClient, +) : IUserRepository { private var user: User? = null override suspend fun getUser(forceUpdate: Boolean): User { diff --git a/app/src/main/java/com/pixelized/biblib/ui/MainActivity.kt b/app/src/main/java/com/pixelized/biblib/ui/MainActivity.kt index 117c299..e716555 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/MainActivity.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/MainActivity.kt @@ -1,55 +1,32 @@ package com.pixelized.biblib.ui import android.os.Bundle -import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.activity.viewModels -import androidx.compose.animation.Crossfade -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.livedata.observeAsState -import androidx.lifecycle.viewmodel.compose.viewModel -import com.pixelized.biblib.ui.composable.screen.LoginScreen -import com.pixelized.biblib.ui.composable.screen.HomeScreen -import com.pixelized.biblib.ui.composable.screen.SplashScreen +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import com.pixelized.biblib.ui.navigation.FullScreenNavHost +import com.pixelized.biblib.ui.navigation.Screen import com.pixelized.biblib.ui.theme.BibLibTheme -import com.pixelized.biblib.ui.viewmodel.navigation.INavigationViewModel.Navigable.Screen -import com.pixelized.biblib.ui.viewmodel.navigation.NavigationViewModel +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint class MainActivity : ComponentActivity() { - private val navigationViewModel: NavigationViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { BibLibTheme { - ContentComposable() + Surface( + color = MaterialTheme.colors.background, + ) { + FullScreenNavHost( + startDestination = Screen.Authentication + ) + } } } } - - override fun onBackPressed() { - if (navigationViewModel.navigateBack().not()) { - super.onBackPressed() - } - } -} - -@Composable -fun ContentComposable() { - val navigationViewModel = viewModel() - val main by navigationViewModel.screen.observeAsState() - - Log.e("pouet", "Navigation State $main") - - Crossfade(targetState = main) { - when (it) { - is Screen.SplashScreen -> SplashScreen() - is Screen.LoginScreen -> LoginScreen() - is Screen.MainScreen -> HomeScreen() - } - } -} - +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/authentication/AuthenticationFormUIO.kt b/app/src/main/java/com/pixelized/biblib/ui/authentication/AuthenticationFormUIO.kt new file mode 100644 index 0000000..15e26f0 --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/ui/authentication/AuthenticationFormUIO.kt @@ -0,0 +1,16 @@ +package com.pixelized.biblib.ui.authentication + +import androidx.compose.runtime.Stable +import androidx.compose.runtime.State +import androidx.compose.runtime.getValue + +@Stable +class AuthenticationFormUIO( + login: State, + password: State, + remember: State, +) { + val login: String by login + val password: String by password + val remember: Boolean by remember +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/authentication/AuthenticationScreen.kt b/app/src/main/java/com/pixelized/biblib/ui/authentication/AuthenticationScreen.kt new file mode 100644 index 0000000..974a88a --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/ui/authentication/AuthenticationScreen.kt @@ -0,0 +1,378 @@ +package com.pixelized.biblib.ui.authentication + +import android.content.Intent +import android.content.res.Configuration +import android.net.Uri +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.sharp.Visibility +import androidx.compose.material.icons.sharp.VisibilityOff +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavHostController +import com.pixelized.biblib.R +import com.pixelized.biblib.network.client.IBibLibClient +import com.pixelized.biblib.ui.composable.* +import com.pixelized.biblib.ui.navigation.LocalFullScreenNavHostController +import com.pixelized.biblib.ui.navigation.Screen +import com.pixelized.biblib.ui.theme.BibLibTheme +import com.pixelized.biblib.ui.theme.color.GoogleColorPalette +import com.pixelized.biblib.utils.extention.bibLib + +@Composable +fun AuthenticationScreen( + viewModel: AuthenticationViewModel = hiltViewModel(), +) { + val navHostController = LocalFullScreenNavHostController.current + + AuthenticationScreenContent( + login = viewModel.form.login, + password = viewModel.form.password, + rememberPassword = viewModel.form.remember, + onLoginChange = { + viewModel.onLoginChange(it) + }, + onPasswordChange = { + viewModel.onPasswordChange(it) + }, + onRememberPasswordChange = { + viewModel.onRememberChange(it) + }, + onGoogleSignIn = { + viewModel.loginWithGoogle() + }, + onSignIn = { + viewModel.login() + }, + onRegister = { + navHostController.navigateToRegister() + }, + ) + + AuthenticationHandler( + onDismissRequest = { + if (it is StateUio.Failure) viewModel.dismissError() + }, + onSuccess = { + navHostController.navigateToHome() + } + ) +} + +@Composable +private fun AuthenticationScreenContent( + login: String, + onLoginChange: (String) -> Unit, + password: String, + onPasswordChange: (String) -> Unit, + rememberPassword: Boolean, + onRememberPasswordChange: (Boolean) -> Unit, + onGoogleSignIn: () -> Unit, + onSignIn: () -> Unit, + onRegister: () -> Unit, +) { + val scrollState = rememberScrollState() + val focusManager = LocalFocusManager.current + + AnimatedDelayer { + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(scrollState) + ) { + Spacer(modifier = Modifier.weight(1f)) + + AnimatedOffset( + modifier = Modifier + .padding(all = MaterialTheme.bibLib.dimen.medium) + .align(alignment = Alignment.CenterHorizontally), + ) { + Text( + style = MaterialTheme.typography.h4, + color = MaterialTheme.colors.onBackground, + text = stringResource(id = R.string.authentication_title), + ) + } + + Spacer(modifier = Modifier.weight(1f)) + + AnimatedOffset( + modifier = Modifier.padding(horizontal = MaterialTheme.bibLib.dimen.medium), + ) { + LoginField( + modifier = Modifier.fillMaxWidth(), + value = login, + onValueChange = onLoginChange, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next), + ) + } + + Spacer(modifier = Modifier.height(MaterialTheme.bibLib.dimen.small)) + + AnimatedOffset( + modifier = Modifier.padding(horizontal = MaterialTheme.bibLib.dimen.medium), + ) { + PasswordField( + modifier = Modifier.fillMaxWidth(), + value = password, + onValueChange = onPasswordChange, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), + keyboardActions = KeyboardActions { focusManager.clearFocus() }, + ) + } + + Spacer(modifier = Modifier.height(MaterialTheme.bibLib.dimen.medium)) + + AnimatedOffset( + modifier = Modifier.padding(horizontal = MaterialTheme.bibLib.dimen.medium), + ) { + CredentialRemember( + value = rememberPassword, + onValueChange = onRememberPasswordChange, + ) + } + + Spacer(modifier = Modifier.height(MaterialTheme.bibLib.dimen.medium)) + + AnimatedOffset( + modifier = Modifier + .padding(horizontal = MaterialTheme.bibLib.dimen.medium) + .align(Alignment.End), + ) { + Row { + Button( + colors = ButtonDefaults.outlinedButtonColors(), + onClick = onRegister, + ) { + Text(text = stringResource(id = R.string.action_register)) + } + + Spacer(modifier = Modifier.width(MaterialTheme.bibLib.dimen.small)) + + Button( + colors = ButtonDefaults.buttonColors(), + onClick = onSignIn, + ) { + Text(text = stringResource(id = R.string.action_login)) + } + } + } + + Spacer(modifier = Modifier.weight(2f)) + + AnimatedOffset { + Button( + modifier = Modifier + .padding(all = MaterialTheme.bibLib.dimen.medium) + .fillMaxWidth(), + colors = ButtonDefaults.outlinedButtonColors(), + onClick = onGoogleSignIn, + ) { + Text(text = googleStringResource()) + } + } + } + } +} + + +////////////////////////////////////// +// region: Authentication Handlers + +@Composable +fun AuthenticationHandler( + viewModel: AuthenticationViewModel = hiltViewModel(), + onDismissRequest: (StateUio) -> Unit = {}, + onSuccess: () -> Unit = { }, +) { + viewModel.PrepareLoginWithGoogle() + + val state by viewModel.authenticationProcess + StateUioHandler( + state = state, + onDismissRequest = onDismissRequest, + onSuccess = onSuccess, + ) +} + +////////////////////////////////////// +// region: Content Helper Composable + +@Composable +private fun LoginField( + modifier: Modifier = Modifier, + value: String, + onValueChange: (String) -> Unit, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + keyboardActions: KeyboardActions = KeyboardActions(), +) { + TextField( + modifier = modifier, + value = value, + onValueChange = onValueChange, + label = { Text(text = stringResource(id = R.string.authentication_login)) }, + colors = TextFieldDefaults.outlinedTextFieldColors(), + maxLines = 1, + singleLine = true, + keyboardOptions = keyboardOptions, + keyboardActions = keyboardActions, + ) +} + +@Composable +private fun PasswordField( + modifier: Modifier = Modifier, + value: String, + onValueChange: (String) -> Unit, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + keyboardActions: KeyboardActions = KeyboardActions(), +) { + var passwordVisibility by remember { mutableStateOf(false) } + TextField( + modifier = modifier, + value = value, + onValueChange = onValueChange, + label = { Text(text = stringResource(id = R.string.authentication_password)) }, + colors = TextFieldDefaults.outlinedTextFieldColors(), + maxLines = 1, + singleLine = true, + visualTransformation = if (passwordVisibility) VisualTransformation.None else PasswordVisualTransformation(), + trailingIcon = { + IconButton(onClick = { passwordVisibility = passwordVisibility.not() }) { + Icon( + imageVector = if (passwordVisibility) Icons.Sharp.VisibilityOff else Icons.Sharp.Visibility, + contentDescription = null, + ) + } + }, + keyboardOptions = keyboardOptions, + keyboardActions = keyboardActions, + ) +} + +@Composable +private fun CredentialRemember( + modifier: Modifier = Modifier, + value: Boolean, + onValueChange: (Boolean) -> Unit, +) { + Row( + modifier = modifier.clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + onClick = { onValueChange(value.not()) } + ) + ) { + Checkbox( + modifier = Modifier.align(Alignment.CenterVertically), + checked = value, + onCheckedChange = null + ) + + Spacer(modifier = Modifier.width(MaterialTheme.bibLib.dimen.small)) + + Text( + modifier = Modifier.align(Alignment.CenterVertically), + style = MaterialTheme.typography.caption, + color = MaterialTheme.colors.onBackground, + text = stringResource(id = R.string.authentication_credential_remember) + ) + } +} + +// endregion +////////////////////////////////////// +// region: Navigation Helper + +private fun NavHostController.navigateToHome() { + navigate(Screen.Home.route) { popUpTo(0) { inclusive = true } } +} + +private fun NavHostController.navigateToRegister() { + context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(IBibLibClient.REGISTER_URL))) +} + +// endregion +////////////////////////////////////// +// region: AnnotatedString + +@Composable +@ReadOnlyComposable +fun googleStringResource(): AnnotatedString = buildAnnotatedString { + val default = LocalTextStyle.current.toSpanStyle() + withStyle( + style = default + ) { + append(stringResource(id = R.string.action_google_sign_in)) + append(" ") + } + withStyle( + style = default.copy(color = GoogleColorPalette.blue, fontWeight = FontWeight.ExtraBold), + ) { + append("G") + } + withStyle( + style = default.copy(color = GoogleColorPalette.red, fontWeight = FontWeight.ExtraBold), + ) { + append("o") + } + withStyle( + style = default.copy(color = GoogleColorPalette.yellow, fontWeight = FontWeight.ExtraBold), + ) { + append("o") + } + withStyle( + style = default.copy(color = GoogleColorPalette.blue, fontWeight = FontWeight.ExtraBold), + ) { + append("g") + } + withStyle( + style = default.copy(color = GoogleColorPalette.green, fontWeight = FontWeight.ExtraBold), + ) { + append("l") + } + withStyle( + style = default.copy(color = GoogleColorPalette.red, fontWeight = FontWeight.ExtraBold), + ) { + append("e") + } +} + +@Composable +@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) +private fun AuthenticationScreenContentPreview() { + BibLibTheme { + AuthenticationScreenContent( + login = "", + onLoginChange = { }, + password = "", + onPasswordChange = { }, + rememberPassword = true, + onRememberPasswordChange = { }, + onGoogleSignIn = { }, + onSignIn = { }, + onRegister = { }, + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/authentication/AuthenticationViewModel.kt b/app/src/main/java/com/pixelized/biblib/ui/authentication/AuthenticationViewModel.kt new file mode 100644 index 0000000..962cfc0 --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/ui/authentication/AuthenticationViewModel.kt @@ -0,0 +1,220 @@ +package com.pixelized.biblib.ui.authentication + +import android.content.Intent +import android.util.Log +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.runtime.* +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.google.android.gms.auth.api.signin.GoogleSignIn +import com.google.android.gms.common.api.ApiException +import com.pixelized.biblib.network.client.IBibLibClient +import com.pixelized.biblib.network.data.query.AuthLoginQuery +import com.pixelized.biblib.repository.credential.ICredentialRepository +import com.pixelized.biblib.repository.googleSignIn.IGoogleSingInRepository +import com.pixelized.biblib.ui.composable.StateUio +import com.pixelized.biblib.utils.exception.MissingGoogleTokenException +import com.pixelized.biblib.utils.exception.MissingTokenException +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class AuthenticationViewModel @Inject constructor( + private val credentialRepository: ICredentialRepository, + private val googleSignIn: IGoogleSingInRepository, + private val client: IBibLibClient, +) : ViewModel() { + private var launcher: ActivityResultLauncher? = null + + private var authenticationJob: Job? = null + private val _authenticationProcess = mutableStateOf?>(null) + val authenticationProcess: State?> get() = _authenticationProcess + + private val _login: MutableState + private val _password: MutableState + private val _remember = mutableStateOf(credentialRepository.rememberCredential) + + val form: AuthenticationFormUIO + get() = AuthenticationFormUIO( + login = _login, + password = _password, + remember = _remember, + ) + + init { + if (credentialRepository.rememberCredential) { + _login = mutableStateOf(credentialRepository.login ?: "") + _password = mutableStateOf(credentialRepository.password ?: "") + } else { + _login = mutableStateOf("") + _password = mutableStateOf("") + } + } + + ////////////////////////////////////// + // region: Login with BibLibClient + + fun login( + login: String = _login.value, + password: String = _password.value, + ) { + authenticationJob?.cancel() + authenticationJob = viewModelScope.launch(Dispatchers.IO) { + val query = AuthLoginQuery(username = login, password = password) + _authenticationProcess.value = StateUio.Progress() + try { + val response = client.service.login(query) + val idToken = response.token ?: throw MissingTokenException() + client.token = idToken + _authenticationProcess.value = StateUio.Success(Unit) + } catch (exception: Exception) { + Log.e("AuthenticationViewModel", exception.message, exception) + _authenticationProcess.value = StateUio.Failure(exception) + } + } + } + + // endregion + ////////////////////////////////////// + // region: Login with Google + + @Composable + fun PrepareLoginWithGoogle() { + launcher = rememberLauncherForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { + authenticationJob?.cancel() + authenticationJob = viewModelScope.launch(Dispatchers.IO) { + try { + val task = GoogleSignIn.getSignedInAccountFromIntent(it.data) + val account = task.getResult(ApiException::class.java) + val googleToken = account?.idToken ?: throw MissingGoogleTokenException() + val response = client.service.loginWithGoogle(googleToken) + val token = response.token ?: throw MissingTokenException() + client.token = token + _authenticationProcess.value = StateUio.Success(Unit) + } catch (exception: Exception) { + Log.e("AuthenticationViewModel", exception.message, exception) + _authenticationProcess.value = StateUio.Failure(exception) + } + } + } + } + + fun loginWithGoogle() { + _authenticationProcess.value = StateUio.Progress() + launcher?.launch(googleSignIn.client.signInIntent) + } + + // endregion + ////////////////////////////////////// + // region: AutoLogin + + @Composable + fun AutoLogin() { + LaunchedEffect(key1 = "AuthenticationViewModel AutoLogin") { + authenticationJob?.cancel() + authenticationJob = launch(Dispatchers.IO) { + _authenticationProcess.value = StateUio.Progress() + try { + autoLoginWithGoogle() || autologinWithCredential() + _authenticationProcess.value = StateUio.Success(Unit) + } catch (exception: Exception) { + _authenticationProcess.value = StateUio.Failure(exception) + } + } + } + } + + private suspend fun autoLoginWithGoogle(): Boolean { + val googleToken = googleSignIn.lastGoogleToken + return if (googleToken != null) { + try { + client.service.loginWithGoogle(googleToken).let { response -> + if (response.token != null) { + client.token = response.token + true + } else { + false + } + } + } catch (e: Exception) { + false + } + } else { + false + } + } + + private suspend fun autologinWithCredential(): Boolean { + val login = credentialRepository.login + val password = credentialRepository.password + return if (login != null && password != null) { + try { + val query = AuthLoginQuery(login, password) + client.service.login(query).let { response -> + if (response.token != null) { + client.token = response.token + true + } else { + false + } + } + } catch (e: Exception) { + false + } + } else { + false + } + } + + // endregion + ////////////////////////////////////// + // region: OnDataChange callback. + + fun onLoginChange(login: String) { + // update login in the repository + if (_remember.value) { + credentialRepository.login = login + } + // update the UI State + _login.value = login + } + + fun onPasswordChange(password: String) { + // update password in the repository + if (_remember.value) { + credentialRepository.password = password + } + // update the UI State + _password.value = password + } + + fun onRememberChange(remember: Boolean) { + // save the remember state in the repository + credentialRepository.rememberCredential = remember + // update login & password in the repository + if (remember.not()) { + credentialRepository.login = null + credentialRepository.password = null + } else { + credentialRepository.login = _login.value + credentialRepository.password = _password.value + } + // update the UI State + _remember.value = remember + } + + // endregion + ////////////////////////////////////// + // region: Dialog + + fun dismissError() { + _authenticationProcess.value = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/AnimatedDelayer.kt b/app/src/main/java/com/pixelized/biblib/ui/composable/AnimatedDelayer.kt new file mode 100644 index 0000000..4184e14 --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/ui/composable/AnimatedDelayer.kt @@ -0,0 +1,15 @@ +package com.pixelized.biblib.ui.composable + +import androidx.compose.runtime.Composable + +@Composable +fun AnimatedDelayer( + content: @Composable AnimatedDelayerScope.() -> Unit +) { + val scope = AnimatedDelayerScope() + scope.content() +} + +class AnimatedDelayerScope( + var delay : Delay = Delay() +) \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/AnimatedOffset.kt b/app/src/main/java/com/pixelized/biblib/ui/composable/AnimatedOffset.kt new file mode 100644 index 0000000..531e19d --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/ui/composable/AnimatedOffset.kt @@ -0,0 +1,146 @@ +package com.pixelized.biblib.ui.composable + +import androidx.compose.animation.core.* +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.offset +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.Saver +import androidx.compose.runtime.saveable.SaverScope +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.platform.LocalInspectionMode +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + + +@Composable +fun AnimatedDelayerScope.AnimatedOffset( + modifier: Modifier = Modifier, + transitionLabel: String = "AnimatedOffset", + content: @Composable BoxScope.() -> Unit, +) { + AnimatedOffset( + modifier = modifier, + transitionLabel = transitionLabel, + delay = delay++, + content = content, + ) +} + +@Composable +fun AnimatedOffset( + modifier: Modifier = Modifier, + transitionLabel: String = "AnimatedOffset", + delay: Delay = Delay(), + content: @Composable BoxScope.() -> Unit, +) { + val displayed = rememberSavableMutableTransitionState( + initialState = LocalInspectionMode.current, + targetState = true, + ) + AnimatedOffset( + modifier = modifier, + transitionLabel = transitionLabel, + displayed = displayed, + delay = delay, + content = content, + ) +} + +@Composable +fun AnimatedOffset( + modifier: Modifier = Modifier, + displayed: MutableTransitionState, + transitionLabel: String = "AnimatedOffset", + delay: Delay = Delay(), + content: @Composable BoxScope.() -> Unit, +) { + val transition: TransitionData = updateTransition( + displayed = displayed, + label = transitionLabel, + delay = delay.value, + ) + Box( + modifier = modifier + .offset(y = transition.offset) + .graphicsLayer(alpha = transition.alpha, clip = false), + content = content + ) +} + +@Composable +private fun updateTransition( + displayed: MutableTransitionState, + label: String, + duration: Int = 600, + delay: Int = 0, + easing: CubicBezierEasing = CubicBezierEasing(0.25f, 1f, 0.5f, 1f), + fromAlpha: Float = 0f, + toAlpha: Float = 1f, + fromOffset: Dp = 64.dp, + toOffset: Dp = 0.dp, +): TransitionData { + val transition = updateTransition(transitionState = displayed, label = label) + val alpha = transition.animateFloat( + label = "$label :: alpha", + transitionSpec = { tween(durationMillis = duration, easing = easing, delayMillis = delay) }, + ) { + when (it) { + true -> toAlpha + else -> fromAlpha + } + } + val offset = transition.animateDp( + label = "$label :: offset", + transitionSpec = { tween(durationMillis = duration, easing = easing, delayMillis = delay) }, + ) { + when (it) { + true -> toOffset + else -> fromOffset + } + } + return remember(transition) { TransitionData(alpha, offset) } +} + +private class TransitionData( + alpha: State, + offset: State, +) { + val alpha by alpha + val offset by offset +} + +@JvmInline +value class Delay( + val value: Int = DELTA, +) { + operator fun inc(): Delay { + return Delay(value = value + DELTA) + } + + companion object { + private const val DELTA = 100 + } +} + +@Composable +private inline fun rememberSavableMutableTransitionState( + initialState: T, targetState: T +) = rememberSaveable(saver = saver()) { + MutableTransitionState(initialState).apply { this.targetState = targetState } +} + +private inline fun saver() = object : Saver, Pair> { + override fun restore(value: Pair): MutableTransitionState { + return MutableTransitionState(value.first).apply { targetState = value.second } + } + + override fun SaverScope.save(value: MutableTransitionState): Pair { + return value.currentState to value.targetState + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/StateUioHandler.kt b/app/src/main/java/com/pixelized/biblib/ui/composable/StateUioHandler.kt new file mode 100644 index 0000000..502bb97 --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/ui/composable/StateUioHandler.kt @@ -0,0 +1,74 @@ +package com.pixelized.biblib.ui.composable + +import androidx.compose.animation.* +import androidx.compose.animation.core.tween +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.window.Dialog +import com.pixelized.biblib.ui.old.composable.dialog.ErrorCard +import com.pixelized.biblib.ui.old.composable.dialog.LoadingCard + +sealed class StateUio { + class Progress(val progress: Float? = null) : StateUio() + class Failure(val exception: Exception) : StateUio() + class Success(val value: T) : StateUio() +} + +@OptIn(ExperimentalAnimationApi::class) +@Composable +fun StateUioHandler( + state: StateUio?, + onDismissRequest: (StateUio) -> Unit = {}, + onSuccess: () -> Unit = { }, +) { + val currentOnDismissRequest by rememberUpdatedState(onDismissRequest) + val currentOnSuccess by rememberUpdatedState(onSuccess) + + when (state) { + is StateUio.Progress, + is StateUio.Failure -> { + Dialog(onDismissRequest = { currentOnDismissRequest(state) }) { + Box( + modifier = Modifier + .fillMaxSize() + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + onClick = { onDismissRequest(state) } + ), + contentAlignment = Alignment.Center + ) { + AnimatedContent( + targetState = state, + contentAlignment = Alignment.Center, + transitionSpec = { + fadeIn(tween(delayMillis = 150)) + scaleIn( + initialScale = 0.85f, + animationSpec = tween(delayMillis = 150) + ) with fadeOut(tween()) + scaleOut( + targetScale = 0.85f, + animationSpec = tween() + ) + }, + ) { + when (it) { + is StateUio.Progress -> LoadingCard() + is StateUio.Failure -> ErrorCard(exception = it.exception) + else -> Unit // nothing to do. + } + } + } + } + } + is StateUio.Success -> currentOnSuccess() + null -> Unit // nothing to do. + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/navigation/FullScreenNavHost.kt b/app/src/main/java/com/pixelized/biblib/ui/navigation/FullScreenNavHost.kt new file mode 100644 index 0000000..35c42cf --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/ui/navigation/FullScreenNavHost.kt @@ -0,0 +1,34 @@ +package com.pixelized.biblib.ui.navigation + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.compositionLocalOf +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import com.pixelized.biblib.ui.authentication.AuthenticationScreen + +val LocalFullScreenNavHostController = compositionLocalOf { + error("LocalFullScreenNavHostController is not ready yet.") +} + +@Composable +fun FullScreenNavHost( + navHostController: NavHostController = rememberNavController(), + startDestination: Screen = Screen.Authentication +) { + CompositionLocalProvider(LocalFullScreenNavHostController provides navHostController) { + NavHost( + navController = navHostController, + startDestination = startDestination.route, + ) { + composable(Screen.Authentication.route) { + AuthenticationScreen() + } + composable(Screen.Home.route) { + + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/navigation/Screen.kt b/app/src/main/java/com/pixelized/biblib/ui/navigation/Screen.kt new file mode 100644 index 0000000..08e1554 --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/ui/navigation/Screen.kt @@ -0,0 +1,12 @@ +package com.pixelized.biblib.ui.navigation + +sealed class Screen( + val route: String, +) { + object Authentication : Screen( + route = "authentication" + ) + object Home : Screen( + route = "home" + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/common/BibLibDrawer.kt b/app/src/main/java/com/pixelized/biblib/ui/old/composable/common/BibLibDrawer.kt similarity index 97% rename from app/src/main/java/com/pixelized/biblib/ui/composable/common/BibLibDrawer.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/composable/common/BibLibDrawer.kt index 714ce18..9d28554 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/composable/common/BibLibDrawer.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/composable/common/BibLibDrawer.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.composable.common +package com.pixelized.biblib.ui.old.composable.common import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* @@ -22,7 +22,7 @@ import com.pixelized.biblib.BuildConfig import com.pixelized.biblib.R import com.pixelized.biblib.model.user.User import com.pixelized.biblib.ui.theme.BibLibTheme -import com.pixelized.biblib.ui.viewmodel.user.IUserViewModel +import com.pixelized.biblib.ui.old.viewmodel.user.IUserViewModel import java.util.* diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/common/BibLibToolbar.kt b/app/src/main/java/com/pixelized/biblib/ui/old/composable/common/BibLibToolbar.kt similarity index 97% rename from app/src/main/java/com/pixelized/biblib/ui/composable/common/BibLibToolbar.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/composable/common/BibLibToolbar.kt index b332c5f..8c5efc0 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/composable/common/BibLibToolbar.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/composable/common/BibLibToolbar.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.composable.common +package com.pixelized.biblib.ui.old.composable.common import androidx.compose.animation.Crossfade import androidx.compose.material.Icon diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/common/HtmlText.kt b/app/src/main/java/com/pixelized/biblib/ui/old/composable/common/HtmlText.kt similarity index 89% rename from app/src/main/java/com/pixelized/biblib/ui/composable/common/HtmlText.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/composable/common/HtmlText.kt index 17817cf..94c0466 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/composable/common/HtmlText.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/composable/common/HtmlText.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.composable.common +package com.pixelized.biblib.ui.old.composable.common import android.widget.TextView import androidx.compose.runtime.Composable diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/common/Image.kt b/app/src/main/java/com/pixelized/biblib/ui/old/composable/common/Image.kt similarity index 82% rename from app/src/main/java/com/pixelized/biblib/ui/composable/common/Image.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/composable/common/Image.kt index 66ab463..28662b2 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/composable/common/Image.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/composable/common/Image.kt @@ -1,5 +1,6 @@ -package com.pixelized.biblib.ui.composable.common +package com.pixelized.biblib.ui.old.composable.common +import android.content.Context import androidx.compose.animation.Crossfade import androidx.compose.runtime.* import androidx.compose.ui.Alignment @@ -10,8 +11,9 @@ import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.layout.ContentScale -import com.pixelized.biblib.utils.BitmapCache -import com.pixelized.biblib.utils.injection.get +import androidx.compose.ui.platform.LocalContext +import com.pixelized.biblib.module.PersistenceModule +import dagger.hilt.android.EntryPointAccessors import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import java.net.URL @@ -29,8 +31,9 @@ fun Image( alpha: Float = DefaultAlpha, colorFilter: ColorFilter? = null ) { + val context = LocalContext.current val coroutineScope = rememberCoroutineScope() - val cover by remember { download(placeHolder, coroutineScope, contentUrl) } + val cover by remember { download(context, placeHolder, coroutineScope, contentUrl) } Crossfade(modifier = modifier, targetState = cover) { if (it == placeHolder) { @@ -57,14 +60,17 @@ fun Image( } private fun download( + context: Context, placeHolder: Painter, coroutineScope: CoroutineScope, url: URL, ): State { val state = mutableStateOf(placeHolder) + val cache = EntryPointAccessors + .fromApplication(context, PersistenceModule::class.java) + .provideBitmapCache(context) coroutineScope.launch { - val cache: BitmapCache = get() val resource = cache.readFromDisk(url)?.let { BitmapPainter(it.asImageBitmap()) } if (resource != null) { state.value = resource diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/dialog/CrossFadeOverlay.kt b/app/src/main/java/com/pixelized/biblib/ui/old/composable/dialog/CrossFadeOverlay.kt similarity index 95% rename from app/src/main/java/com/pixelized/biblib/ui/composable/dialog/CrossFadeOverlay.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/composable/dialog/CrossFadeOverlay.kt index 881d7dc..1f079a7 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/composable/dialog/CrossFadeOverlay.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/composable/dialog/CrossFadeOverlay.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.composable.dialog +package com.pixelized.biblib.ui.old.composable.dialog import androidx.compose.animation.Crossfade import androidx.compose.foundation.background diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/dialog/ErrorCard.kt b/app/src/main/java/com/pixelized/biblib/ui/old/composable/dialog/ErrorCard.kt similarity index 84% rename from app/src/main/java/com/pixelized/biblib/ui/composable/dialog/ErrorCard.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/composable/dialog/ErrorCard.kt index 6915a03..0180ccd 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/composable/dialog/ErrorCard.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/composable/dialog/ErrorCard.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.composable.dialog +package com.pixelized.biblib.ui.old.composable.dialog import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.height @@ -44,19 +44,20 @@ fun ErrorCard( imageVector = Icons.Sharp.ErrorOutline, contentDescription = "error" ) - val typography = MaterialTheme.typography - Text( - modifier = Modifier.align(Alignment.CenterHorizontally), - style = typography.body1, - textAlign = TextAlign.Center, - text = message - ) + if (message.isNotEmpty()) { + Text( + modifier = Modifier.align(Alignment.CenterHorizontally), + style = MaterialTheme.typography.body1, + textAlign = TextAlign.Center, + text = message + ) + } if (exception != null) { Text( modifier = Modifier .padding(top = 8.dp) .align(Alignment.CenterHorizontally), - style = typography.caption, + style = MaterialTheme.typography.caption, textAlign = TextAlign.Center, text = exception.message ?: exception::class.java.simpleName ) diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/dialog/LoadingCard.kt b/app/src/main/java/com/pixelized/biblib/ui/old/composable/dialog/LoadingCard.kt similarity index 69% rename from app/src/main/java/com/pixelized/biblib/ui/composable/dialog/LoadingCard.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/composable/dialog/LoadingCard.kt index 0c82dc9..ce03e3e 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/composable/dialog/LoadingCard.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/composable/dialog/LoadingCard.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.composable.dialog +package com.pixelized.biblib.ui.old.composable.dialog import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding @@ -16,12 +16,14 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.pixelized.biblib.R import com.pixelized.biblib.ui.theme.BibLibTheme +import com.pixelized.biblib.utils.extention.bibLib @Composable fun LoadingCard( modifier: Modifier = Modifier, - message: String? = null + progress: Float? = null, + message: String? = null, ) { Card(elevation = 8.dp, modifier = modifier) { Column( @@ -29,11 +31,20 @@ fun LoadingCard( .width(250.dp) .padding(32.dp) ) { - CircularProgressIndicator( - modifier = Modifier - .align(Alignment.CenterHorizontally) - .padding(bottom = 16.dp) - ) + if (progress == null) { + CircularProgressIndicator( + modifier = Modifier + .align(Alignment.CenterHorizontally) + .padding(bottom = MaterialTheme.bibLib.dimen.medium) + ) + } else { + CircularProgressIndicator( + modifier = Modifier + .align(Alignment.CenterHorizontally) + .padding(bottom = MaterialTheme.bibLib.dimen.medium), + progress = progress, + ) + } if (message?.isNotEmpty() == true) { val typography = MaterialTheme.typography Text( diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/dialog/SuccesCard.kt b/app/src/main/java/com/pixelized/biblib/ui/old/composable/dialog/SuccesCard.kt similarity index 97% rename from app/src/main/java/com/pixelized/biblib/ui/composable/dialog/SuccesCard.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/composable/dialog/SuccesCard.kt index 99bcb74..4f57d02 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/composable/dialog/SuccesCard.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/composable/dialog/SuccesCard.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.composable.dialog +package com.pixelized.biblib.ui.old.composable.dialog import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.height diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/items/BookItem.kt b/app/src/main/java/com/pixelized/biblib/ui/old/composable/items/BookItem.kt similarity index 90% rename from app/src/main/java/com/pixelized/biblib/ui/composable/items/BookItem.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/composable/items/BookItem.kt index fd9b746..544a8cb 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/composable/items/BookItem.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/composable/items/BookItem.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.composable.items +package com.pixelized.biblib.ui.old.composable.items import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* @@ -12,19 +12,16 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.pixelized.biblib.R -import com.pixelized.biblib.ui.composable.common.Image -import com.pixelized.biblib.ui.data.BookThumbnailUio +import com.pixelized.biblib.ui.old.composable.common.Image +import com.pixelized.biblib.ui.old.data.BookThumbnailUio import com.pixelized.biblib.ui.theme.BibLibTheme -import com.pixelized.biblib.ui.theme.Teal200 -import com.pixelized.biblib.utils.BitmapCache -import com.pixelized.biblib.utils.injection.ServiceLocator +import com.pixelized.biblib.ui.theme.color.BibLibColorPalette import com.pixelized.biblib.utils.mock.BookThumbnailMock private val THUMBNAIL_WIDTH: Dp = 60.dp @@ -68,7 +65,7 @@ private fun FilledBookItem( placeHolder = painterResource(id = R.drawable.ic_launcher_foreground), contentScale = ContentScale.FillBounds, contentUrl = thumbnail.cover, - colorFilter = if (MaterialTheme.colors.isLight) ColorFilter.tint(Teal200) else null, + colorFilter = if (MaterialTheme.colors.isLight) ColorFilter.tint(BibLibColorPalette.Green) else null, contentDescription = thumbnail.title ) Column( @@ -158,7 +155,6 @@ private fun Placeholder(modifier: Modifier) = Surface(modifier = modifier, eleva @Preview @Composable fun BookItemLightPreview() { - ServiceLocator[BitmapCache::class] = BitmapCache(LocalContext.current) BibLibTheme { val mock = BookThumbnailMock() FilledBookItem(thumbnail = mock.bookThumbnail) @@ -168,7 +164,6 @@ fun BookItemLightPreview() { @Preview @Composable fun BookItemDarkPreview() { - ServiceLocator[BitmapCache::class] = BitmapCache(LocalContext.current) BibLibTheme(darkTheme = true) { val mock = BookThumbnailMock() FilledBookItem(thumbnail = mock.bookThumbnail) diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/pages/DetailPage.kt b/app/src/main/java/com/pixelized/biblib/ui/old/composable/pages/DetailPage.kt similarity index 92% rename from app/src/main/java/com/pixelized/biblib/ui/composable/pages/DetailPage.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/composable/pages/DetailPage.kt index 82018da..4cc69f3 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/composable/pages/DetailPage.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/composable/pages/DetailPage.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.composable.pages +package com.pixelized.biblib.ui.old.composable.pages import android.widget.Toast import androidx.compose.animation.ExperimentalAnimationApi @@ -32,18 +32,16 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import com.pixelized.biblib.R -import com.pixelized.biblib.ui.composable.common.HtmlText -import com.pixelized.biblib.ui.composable.common.Image -import com.pixelized.biblib.ui.data.BookUio -import com.pixelized.biblib.ui.data.MailUio +import com.pixelized.biblib.ui.old.composable.common.HtmlText +import com.pixelized.biblib.ui.old.composable.common.Image +import com.pixelized.biblib.ui.old.data.BookUio +import com.pixelized.biblib.ui.old.data.MailUio import com.pixelized.biblib.ui.theme.BibLibTheme -import com.pixelized.biblib.ui.theme.Teal200 -import com.pixelized.biblib.ui.viewmodel.book.BooksViewModel -import com.pixelized.biblib.ui.viewmodel.book.IBooksViewModel -import com.pixelized.biblib.ui.viewmodel.user.IUserViewModel -import com.pixelized.biblib.ui.viewmodel.user.UserViewModel -import com.pixelized.biblib.utils.BitmapCache -import com.pixelized.biblib.utils.injection.ServiceLocator +import com.pixelized.biblib.ui.theme.color.BibLibColorPalette +import com.pixelized.biblib.ui.old.viewmodel.book.BooksViewModel +import com.pixelized.biblib.ui.old.viewmodel.book.IBooksViewModel +import com.pixelized.biblib.ui.old.viewmodel.user.IUserViewModel +import com.pixelized.biblib.ui.old.viewmodel.user.UserViewModel import com.pixelized.biblib.utils.mock.BookMock import kotlinx.coroutines.launch @@ -134,7 +132,7 @@ fun DetailPage( contentScale = ContentScale.FillWidth, placeHolder = painterResource(id = R.drawable.ic_launcher_foreground), contentUrl = book.cover, - colorFilter = if (MaterialTheme.colors.isLight) ColorFilter.tint(Teal200) else null, + colorFilter = if (MaterialTheme.colors.isLight) ColorFilter.tint(BibLibColorPalette.Green) else null, contentDescription = book.title ) Row(modifier = Modifier.padding(bottom = 16.dp)) { @@ -296,7 +294,6 @@ private fun SendMailItem( @Preview @Composable fun DetailPageLightPreview() { - ServiceLocator[BitmapCache::class] = BitmapCache(LocalContext.current) BibLibTheme { val book = BookMock() DetailPage(book.book) diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/pages/HomePage.kt b/app/src/main/java/com/pixelized/biblib/ui/old/composable/pages/HomePage.kt similarity index 80% rename from app/src/main/java/com/pixelized/biblib/ui/composable/pages/HomePage.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/composable/pages/HomePage.kt index d276f43..5c30016 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/composable/pages/HomePage.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/composable/pages/HomePage.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.composable.pages +package com.pixelized.biblib.ui.old.composable.pages import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.scrollable @@ -13,11 +13,11 @@ import androidx.compose.ui.unit.dp import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems import androidx.paging.compose.items -import com.pixelized.biblib.ui.composable.items.BookItem -import com.pixelized.biblib.ui.data.BookThumbnailUio -import com.pixelized.biblib.ui.viewmodel.book.IBooksViewModel -import com.pixelized.biblib.ui.viewmodel.navigation.INavigationViewModel -import com.pixelized.biblib.ui.viewmodel.navigation.INavigationViewModel.Navigable.Page +import com.pixelized.biblib.ui.old.composable.items.BookItem +import com.pixelized.biblib.ui.old.data.BookThumbnailUio +import com.pixelized.biblib.ui.old.viewmodel.book.IBooksViewModel +import com.pixelized.biblib.ui.old.viewmodel.navigation.INavigationViewModel +import com.pixelized.biblib.ui.old.viewmodel.navigation.INavigationViewModel.Navigable.Page @Composable diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/screen/HomeScreen.kt b/app/src/main/java/com/pixelized/biblib/ui/old/composable/screen/HomeScreen.kt similarity index 81% rename from app/src/main/java/com/pixelized/biblib/ui/composable/screen/HomeScreen.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/composable/screen/HomeScreen.kt index becac09..8e2eeac 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/composable/screen/HomeScreen.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/composable/screen/HomeScreen.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.composable.screen +package com.pixelized.biblib.ui.old.composable.screen import android.widget.Toast import androidx.compose.animation.* @@ -12,19 +12,19 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.lifecycle.viewmodel.compose.viewModel import com.pixelized.biblib.R -import com.pixelized.biblib.ui.composable.common.BibLibDrawer -import com.pixelized.biblib.ui.composable.common.BibLibToolbar -import com.pixelized.biblib.ui.composable.pages.DetailPage -import com.pixelized.biblib.ui.composable.pages.HomePage -import com.pixelized.biblib.ui.theme.Animation +import com.pixelized.biblib.ui.old.composable.common.BibLibDrawer +import com.pixelized.biblib.ui.old.composable.common.BibLibToolbar +import com.pixelized.biblib.ui.old.composable.pages.DetailPage +import com.pixelized.biblib.ui.old.composable.pages.HomePage +import com.pixelized.biblib.ui.theme.animation.Animation import com.pixelized.biblib.ui.theme.BibLibTheme -import com.pixelized.biblib.ui.viewmodel.book.BooksViewModel -import com.pixelized.biblib.ui.viewmodel.book.IBooksViewModel -import com.pixelized.biblib.ui.viewmodel.navigation.INavigationViewModel -import com.pixelized.biblib.ui.viewmodel.navigation.INavigationViewModel.Navigable.Page -import com.pixelized.biblib.ui.viewmodel.navigation.NavigationViewModel -import com.pixelized.biblib.ui.viewmodel.user.IUserViewModel -import com.pixelized.biblib.ui.viewmodel.user.UserViewModel +import com.pixelized.biblib.ui.old.viewmodel.book.BooksViewModel +import com.pixelized.biblib.ui.old.viewmodel.book.IBooksViewModel +import com.pixelized.biblib.ui.old.viewmodel.navigation.INavigationViewModel +import com.pixelized.biblib.ui.old.viewmodel.navigation.INavigationViewModel.Navigable.Page +import com.pixelized.biblib.ui.old.viewmodel.navigation.NavigationViewModel +import com.pixelized.biblib.ui.old.viewmodel.user.IUserViewModel +import com.pixelized.biblib.ui.old.viewmodel.user.UserViewModel import kotlinx.coroutines.launch diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/screen/LoginScreen.kt b/app/src/main/java/com/pixelized/biblib/ui/old/composable/screen/LoginScreen.kt similarity index 92% rename from app/src/main/java/com/pixelized/biblib/ui/composable/screen/LoginScreen.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/composable/screen/LoginScreen.kt index 391b3c7..67abb92 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/composable/screen/LoginScreen.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/composable/screen/LoginScreen.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.composable.screen +package com.pixelized.biblib.ui.old.composable.screen import android.content.Intent @@ -37,19 +37,19 @@ import androidx.compose.ui.window.DialogProperties import androidx.lifecycle.viewmodel.compose.viewModel import com.pixelized.biblib.R import com.pixelized.biblib.network.client.IBibLibClient.Companion.REGISTER_URL -import com.pixelized.biblib.ui.composable.dialog.ErrorCard -import com.pixelized.biblib.ui.composable.dialog.LoadingCard -import com.pixelized.biblib.ui.composable.dialog.SuccessCard +import com.pixelized.biblib.ui.old.composable.dialog.ErrorCard +import com.pixelized.biblib.ui.old.composable.dialog.LoadingCard +import com.pixelized.biblib.ui.old.composable.dialog.SuccessCard import com.pixelized.biblib.ui.theme.BibLibTheme -import com.pixelized.biblib.ui.viewmodel.authentication.AuthenticationViewModel -import com.pixelized.biblib.ui.viewmodel.authentication.IAuthenticationViewModel -import com.pixelized.biblib.ui.viewmodel.book.BooksViewModel -import com.pixelized.biblib.ui.viewmodel.book.IBooksViewModel -import com.pixelized.biblib.ui.viewmodel.credential.CredentialViewModel -import com.pixelized.biblib.ui.viewmodel.credential.ICredentialViewModel -import com.pixelized.biblib.ui.viewmodel.navigation.INavigationViewModel -import com.pixelized.biblib.ui.viewmodel.navigation.INavigationViewModel.Navigable.Screen -import com.pixelized.biblib.ui.viewmodel.navigation.NavigationViewModel +import com.pixelized.biblib.ui.old.viewmodel.authentication.AuthenticationViewModel +import com.pixelized.biblib.ui.old.viewmodel.authentication.IAuthenticationViewModel +import com.pixelized.biblib.ui.old.viewmodel.book.BooksViewModel +import com.pixelized.biblib.ui.old.viewmodel.book.IBooksViewModel +import com.pixelized.biblib.ui.old.viewmodel.credential.CredentialViewModel +import com.pixelized.biblib.ui.old.viewmodel.credential.ICredentialViewModel +import com.pixelized.biblib.ui.old.viewmodel.navigation.INavigationViewModel +import com.pixelized.biblib.ui.old.viewmodel.navigation.INavigationViewModel.Navigable.Screen +import com.pixelized.biblib.ui.old.viewmodel.navigation.NavigationViewModel import kotlinx.coroutines.delay @@ -243,7 +243,8 @@ private fun SignIn( colors = outlinedButtonColors(), onClick = { authenticationViewModel.loginWithGoogle() - }) { + } + ) { Image( modifier = Modifier.padding(end = 8.dp), painter = painterResource(id = R.drawable.ic_google), contentDescription = "" @@ -329,8 +330,8 @@ private fun CredentialRemember( } } -@Preview @Composable +@Preview(showBackground = true) fun LoginScreenComposablePreview() { BibLibTheme { LoginScreen( diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/screen/SplashScreen.kt b/app/src/main/java/com/pixelized/biblib/ui/old/composable/screen/SplashScreen.kt similarity index 81% rename from app/src/main/java/com/pixelized/biblib/ui/composable/screen/SplashScreen.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/composable/screen/SplashScreen.kt index 6b7d054..91761a5 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/composable/screen/SplashScreen.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/composable/screen/SplashScreen.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.composable.screen +package com.pixelized.biblib.ui.old.composable.screen import androidx.compose.animation.* import androidx.compose.animation.core.tween @@ -17,19 +17,19 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import com.pixelized.biblib.BuildConfig import com.pixelized.biblib.R -import com.pixelized.biblib.ui.composable.dialog.CrossFadeOverlay -import com.pixelized.biblib.ui.composable.dialog.ErrorCard -import com.pixelized.biblib.ui.theme.Animation +import com.pixelized.biblib.ui.old.composable.dialog.CrossFadeOverlay +import com.pixelized.biblib.ui.old.composable.dialog.ErrorCard +import com.pixelized.biblib.ui.theme.animation.Animation import com.pixelized.biblib.ui.theme.BibLibTheme -import com.pixelized.biblib.ui.viewmodel.authentication.AuthenticationViewModel -import com.pixelized.biblib.ui.viewmodel.authentication.IAuthenticationViewModel -import com.pixelized.biblib.ui.viewmodel.book.BooksViewModel -import com.pixelized.biblib.ui.viewmodel.book.IBooksViewModel -import com.pixelized.biblib.ui.viewmodel.navigation.INavigationViewModel -import com.pixelized.biblib.ui.viewmodel.navigation.INavigationViewModel.Navigable.Screen -import com.pixelized.biblib.ui.viewmodel.navigation.NavigationViewModel -import com.pixelized.biblib.ui.viewmodel.user.IUserViewModel -import com.pixelized.biblib.ui.viewmodel.user.UserViewModel +import com.pixelized.biblib.ui.old.viewmodel.authentication.AuthenticationViewModel +import com.pixelized.biblib.ui.old.viewmodel.authentication.IAuthenticationViewModel +import com.pixelized.biblib.ui.old.viewmodel.book.BooksViewModel +import com.pixelized.biblib.ui.old.viewmodel.book.IBooksViewModel +import com.pixelized.biblib.ui.old.viewmodel.navigation.INavigationViewModel +import com.pixelized.biblib.ui.old.viewmodel.navigation.INavigationViewModel.Navigable.Screen +import com.pixelized.biblib.ui.old.viewmodel.navigation.NavigationViewModel +import com.pixelized.biblib.ui.old.viewmodel.user.IUserViewModel +import com.pixelized.biblib.ui.old.viewmodel.user.UserViewModel import kotlinx.coroutines.delay import java.util.* @@ -185,18 +185,10 @@ private fun AuthenticationError(state: IAuthenticationViewModel.State.Error?) { modifier = Modifier.clickable {}, visible = state != null ) { - AnimatedVisibility( - modifier = Modifier.align(Alignment.Center), - visible = true, - initiallyVisible = false, - enter = expandVertically(Alignment.CenterVertically), - exit = shrinkVertically(Alignment.CenterVertically), - ) { - ErrorCard( - message = stringResource(id = R.string.error_generic), - exception = state?.exception - ) - } + ErrorCard( + message = stringResource(id = R.string.error_generic), + exception = state?.exception + ) } } @@ -207,18 +199,10 @@ private fun BookError(state: IBooksViewModel.State.Error?) { modifier = Modifier.clickable {}, visible = state != null ) { - AnimatedVisibility( - modifier = Modifier.align(Alignment.Center), - visible = true, - initiallyVisible = false, - enter = expandVertically(Alignment.CenterVertically), - exit = shrinkVertically(Alignment.CenterVertically), - ) { - ErrorCard( - message = stringResource(id = R.string.error_generic), - exception = state?.exception - ) - } + ErrorCard( + message = stringResource(id = R.string.error_generic), + exception = state?.exception + ) } } diff --git a/app/src/main/java/com/pixelized/biblib/ui/data/BookThumbnailUio.kt b/app/src/main/java/com/pixelized/biblib/ui/old/data/BookThumbnailUio.kt similarity index 88% rename from app/src/main/java/com/pixelized/biblib/ui/data/BookThumbnailUio.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/data/BookThumbnailUio.kt index 7afaa95..5e5cffc 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/data/BookThumbnailUio.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/data/BookThumbnailUio.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.data +package com.pixelized.biblib.ui.old.data import com.pixelized.biblib.network.client.IBibLibClient.Companion.THUMBNAIL_URL import java.net.URL diff --git a/app/src/main/java/com/pixelized/biblib/ui/data/BookUio.kt b/app/src/main/java/com/pixelized/biblib/ui/old/data/BookUio.kt similarity index 89% rename from app/src/main/java/com/pixelized/biblib/ui/data/BookUio.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/data/BookUio.kt index 86509ab..8892b63 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/data/BookUio.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/data/BookUio.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.data +package com.pixelized.biblib.ui.old.data import com.pixelized.biblib.network.client.IBibLibClient.Companion.COVER_URL import java.net.URL diff --git a/app/src/main/java/com/pixelized/biblib/ui/data/MailUio.kt b/app/src/main/java/com/pixelized/biblib/ui/old/data/MailUio.kt similarity index 51% rename from app/src/main/java/com/pixelized/biblib/ui/data/MailUio.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/data/MailUio.kt index d9c17cc..d658fb2 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/data/MailUio.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/data/MailUio.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.data +package com.pixelized.biblib.ui.old.data data class MailUio( val mail: String, diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/authentication/AuthenticationViewModel.kt b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/authentication/AuthenticationViewModel.kt similarity index 91% rename from app/src/main/java/com/pixelized/biblib/ui/viewmodel/authentication/AuthenticationViewModel.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/authentication/AuthenticationViewModel.kt index 059b938..a51ab22 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/authentication/AuthenticationViewModel.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/authentication/AuthenticationViewModel.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.viewmodel.authentication +package com.pixelized.biblib.ui.old.viewmodel.authentication import android.content.Intent import android.util.Log @@ -16,17 +16,20 @@ import com.pixelized.biblib.network.client.IBibLibClient import com.pixelized.biblib.network.data.query.AuthLoginQuery import com.pixelized.biblib.repository.credential.ICredentialRepository import com.pixelized.biblib.repository.googleSignIn.IGoogleSingInRepository -import com.pixelized.biblib.ui.viewmodel.authentication.IAuthenticationViewModel.State +import com.pixelized.biblib.ui.old.viewmodel.authentication.IAuthenticationViewModel.State import com.pixelized.biblib.utils.exception.MissingGoogleTokenException import com.pixelized.biblib.utils.exception.MissingTokenException -import com.pixelized.biblib.utils.injection.inject +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import javax.inject.Inject -class AuthenticationViewModel : ViewModel(), IAuthenticationViewModel { - private val credentialRepository: ICredentialRepository by inject() - private val googleSignIn: IGoogleSingInRepository by inject() - private val client: IBibLibClient by inject() +@HiltViewModel +class AuthenticationViewModel @Inject constructor( + private val credentialRepository: ICredentialRepository, + private val googleSignIn: IGoogleSingInRepository, + private val client: IBibLibClient, +) : ViewModel(), IAuthenticationViewModel { private var launcher: ActivityResultLauncher? = null private val _state = MutableLiveData(State.Initial) diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/authentication/IAuthenticationViewModel.kt b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/authentication/IAuthenticationViewModel.kt similarity index 94% rename from app/src/main/java/com/pixelized/biblib/ui/viewmodel/authentication/IAuthenticationViewModel.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/authentication/IAuthenticationViewModel.kt index 99adf91..36f8a93 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/authentication/IAuthenticationViewModel.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/authentication/IAuthenticationViewModel.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.viewmodel.authentication +package com.pixelized.biblib.ui.old.viewmodel.authentication import androidx.compose.runtime.Composable import androidx.lifecycle.LiveData diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/book/BooksViewModel.kt b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/book/BooksViewModel.kt similarity index 85% rename from app/src/main/java/com/pixelized/biblib/ui/viewmodel/book/BooksViewModel.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/book/BooksViewModel.kt index e1c9686..017a2b7 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/book/BooksViewModel.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/book/BooksViewModel.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.viewmodel.book +package com.pixelized.biblib.ui.old.viewmodel.book import android.util.Log import androidx.lifecycle.LiveData @@ -14,23 +14,26 @@ import com.pixelized.biblib.network.client.IBibLibClient import com.pixelized.biblib.network.factory.BookFactory import com.pixelized.biblib.repository.apiCache.IAPICacheRepository import com.pixelized.biblib.repository.book.IBookRepository -import com.pixelized.biblib.ui.data.BookThumbnailUio -import com.pixelized.biblib.ui.data.BookUio -import com.pixelized.biblib.utils.injection.inject +import com.pixelized.biblib.ui.old.data.BookThumbnailUio +import com.pixelized.biblib.ui.old.data.BookUio +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch import java.text.SimpleDateFormat import java.util.* +import javax.inject.Inject /** * TODO: there is some book related code that should be inside a Repository // DataSource. */ -class BooksViewModel : ViewModel(), IBooksViewModel { - private val bookRepository: IBookRepository by inject() - private val client: IBibLibClient by inject() - private val apiCache: IAPICacheRepository by inject() +@HiltViewModel +class BooksViewModel @Inject constructor( + private val bookRepository: IBookRepository, + private val client: IBibLibClient, + private val apiCache: IAPICacheRepository, +) : ViewModel(), IBooksViewModel { private val formatterLong = SimpleDateFormat("MMMM yyyy", Locale.getDefault()) private val formatterShort = SimpleDateFormat("MMM yyyy", Locale.getDefault()) @@ -122,7 +125,7 @@ class BooksViewModel : ViewModel(), IBooksViewModel { date = if (releaseDate.time < 0) { null } else { - formatterLong.format(releaseDate).capitalize(Locale.getDefault()) + formatterLong.format(releaseDate).capitalize() }, isNew = isNew, ) @@ -132,16 +135,20 @@ class BooksViewModel : ViewModel(), IBooksViewModel { title = title, author = author.joinToString { it.name }, rating = rating?.toFloat() ?: 0.0f, - language = language?.displayLanguage?.capitalize(Locale.getDefault()) ?: "", + language = language?.displayLanguage?.capitalize() ?: "", date = if (releaseDate.time < 0) { null } else { - formatterShort.format(releaseDate).capitalize(Locale.getDefault()) + formatterShort.format(releaseDate).capitalize() }, series = series?.name, description = synopsis ?: "", ) + private fun String.capitalize() = this.replaceFirstChar { + if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() + } + companion object { private const val PAGING_SIZE = 30 } diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/book/IBooksViewModel.kt b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/book/IBooksViewModel.kt similarity index 88% rename from app/src/main/java/com/pixelized/biblib/ui/viewmodel/book/IBooksViewModel.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/book/IBooksViewModel.kt index fe44b6d..9b0a99b 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/book/IBooksViewModel.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/book/IBooksViewModel.kt @@ -1,10 +1,10 @@ -package com.pixelized.biblib.ui.viewmodel.book +package com.pixelized.biblib.ui.old.viewmodel.book import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.paging.PagingData -import com.pixelized.biblib.ui.data.BookThumbnailUio -import com.pixelized.biblib.ui.data.BookUio +import com.pixelized.biblib.ui.old.data.BookThumbnailUio +import com.pixelized.biblib.ui.old.data.BookUio import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/credential/CredentialViewModel.kt b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/credential/CredentialViewModel.kt similarity index 85% rename from app/src/main/java/com/pixelized/biblib/ui/viewmodel/credential/CredentialViewModel.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/credential/CredentialViewModel.kt index e3410f9..ea7527e 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/credential/CredentialViewModel.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/credential/CredentialViewModel.kt @@ -1,16 +1,19 @@ -package com.pixelized.biblib.ui.viewmodel.credential +package com.pixelized.biblib.ui.old.viewmodel.credential import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.pixelized.biblib.repository.credential.ICredentialRepository -import com.pixelized.biblib.utils.injection.inject +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import javax.inject.Inject -class CredentialViewModel : ViewModel(), ICredentialViewModel { - private val credentialRepository: ICredentialRepository by inject() +@HiltViewModel +class CredentialViewModel @Inject constructor( + private val credentialRepository: ICredentialRepository, +) : ViewModel(), ICredentialViewModel { private val _login = MutableLiveData() override val login: LiveData get() = _login diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/credential/ICredentialViewModel.kt b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/credential/ICredentialViewModel.kt similarity index 94% rename from app/src/main/java/com/pixelized/biblib/ui/viewmodel/credential/ICredentialViewModel.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/credential/ICredentialViewModel.kt index ae80ff5..bf25c18 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/credential/ICredentialViewModel.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/credential/ICredentialViewModel.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.viewmodel.credential +package com.pixelized.biblib.ui.old.viewmodel.credential import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/navigation/INavigationViewModel.kt b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/navigation/INavigationViewModel.kt similarity index 95% rename from app/src/main/java/com/pixelized/biblib/ui/viewmodel/navigation/INavigationViewModel.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/navigation/INavigationViewModel.kt index 15d3089..785c4cd 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/navigation/INavigationViewModel.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/navigation/INavigationViewModel.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.viewmodel.navigation +package com.pixelized.biblib.ui.old.viewmodel.navigation import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/navigation/NavigationViewModel.kt b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/navigation/NavigationViewModel.kt similarity index 82% rename from app/src/main/java/com/pixelized/biblib/ui/viewmodel/navigation/NavigationViewModel.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/navigation/NavigationViewModel.kt index c43430b..75ed5ea 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/navigation/NavigationViewModel.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/navigation/NavigationViewModel.kt @@ -1,11 +1,11 @@ -package com.pixelized.biblib.ui.viewmodel.navigation +package com.pixelized.biblib.ui.old.viewmodel.navigation import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import com.pixelized.biblib.ui.viewmodel.navigation.INavigationViewModel.Navigable -import com.pixelized.biblib.ui.viewmodel.navigation.INavigationViewModel.Navigable.Page -import com.pixelized.biblib.ui.viewmodel.navigation.INavigationViewModel.Navigable.Screen +import com.pixelized.biblib.ui.old.viewmodel.navigation.INavigationViewModel.Navigable +import com.pixelized.biblib.ui.old.viewmodel.navigation.INavigationViewModel.Navigable.Page +import com.pixelized.biblib.ui.old.viewmodel.navigation.INavigationViewModel.Navigable.Screen import java.util.* class NavigationViewModel : ViewModel(), INavigationViewModel { diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/user/IUserViewModel.kt b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/user/IUserViewModel.kt similarity index 80% rename from app/src/main/java/com/pixelized/biblib/ui/viewmodel/user/IUserViewModel.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/user/IUserViewModel.kt index a97e8b6..1534a68 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/user/IUserViewModel.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/user/IUserViewModel.kt @@ -1,12 +1,9 @@ -package com.pixelized.biblib.ui.viewmodel.user +package com.pixelized.biblib.ui.old.viewmodel.user import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.pixelized.biblib.R import com.pixelized.biblib.model.user.User -import com.pixelized.biblib.ui.viewmodel.credential.ICredentialViewModel import com.pixelized.biblib.utils.mock.UserMock -import java.util.* interface IUserViewModel { val state: LiveData diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/user/UserViewModel.kt b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/user/UserViewModel.kt similarity index 76% rename from app/src/main/java/com/pixelized/biblib/ui/viewmodel/user/UserViewModel.kt rename to app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/user/UserViewModel.kt index edd5ac1..cd3f869 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/user/UserViewModel.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/old/viewmodel/user/UserViewModel.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.viewmodel.user +package com.pixelized.biblib.ui.old.viewmodel.user import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData @@ -6,14 +6,16 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.pixelized.biblib.model.user.User import com.pixelized.biblib.repository.user.IUserRepository -import com.pixelized.biblib.ui.viewmodel.user.IUserViewModel.State -import com.pixelized.biblib.utils.injection.inject +import com.pixelized.biblib.ui.old.viewmodel.user.IUserViewModel.State +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import javax.inject.Inject -class UserViewModel : ViewModel(), IUserViewModel { - - private val userRepository: IUserRepository by inject() +@HiltViewModel +class UserViewModel @Inject constructor( + private val userRepository: IUserRepository, +) : ViewModel(), IUserViewModel { private val _state = MutableLiveData() override val state: LiveData get() = _state diff --git a/app/src/main/java/com/pixelized/biblib/ui/theme/BibLibTheme.kt b/app/src/main/java/com/pixelized/biblib/ui/theme/BibLibTheme.kt new file mode 100644 index 0000000..a88ef59 --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/ui/theme/BibLibTheme.kt @@ -0,0 +1,18 @@ +package com.pixelized.biblib.ui.theme + +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.compositionLocalOf +import com.pixelized.biblib.ui.theme.color.BibLibColor +import com.pixelized.biblib.ui.theme.dimen.BibLibDimen + +val LocalBibLibTheme = compositionLocalOf { + error("BibLibTheme not ready yet.") +} + +@Stable +@Immutable +data class BibLibTheme( + val dimen: BibLibDimen, + val color: BibLibColor, +) \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/theme/Color.kt b/app/src/main/java/com/pixelized/biblib/ui/theme/Color.kt deleted file mode 100644 index 808a6d1..0000000 --- a/app/src/main/java/com/pixelized/biblib/ui/theme/Color.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.pixelized.biblib.ui.theme - -import androidx.compose.ui.graphics.Color - -val Purple200 = Color(0xFFBB86FC) -val Purple500 = Color(0xFF6200EE) -val Purple700 = Color(0xFF3700B3) -val Teal200 = Color(0xFF03DAC5) - -val Green600 = Color(0xFF43a047) -val Green600L = Color(0xFF76d275) -val Green600D = Color(0xFF00701a) \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/theme/Theme.kt b/app/src/main/java/com/pixelized/biblib/ui/theme/Theme.kt index 5bc3c11..956c6c3 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/theme/Theme.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/theme/Theme.kt @@ -2,39 +2,29 @@ package com.pixelized.biblib.ui.theme import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material.MaterialTheme -import androidx.compose.material.Surface -import androidx.compose.material.darkColors -import androidx.compose.material.lightColors import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color - -private val DarkColorPalette = darkColors( - primary = Green600, - primaryVariant = Green600D, - onPrimary = Color.White, -) - -private val LightColorPalette = lightColors( - primary = Green600, - primaryVariant = Green600D, - onPrimary = Color.White, -) +import androidx.compose.runtime.CompositionLocalProvider +import com.pixelized.biblib.ui.theme.color.bibLibDarkColors +import com.pixelized.biblib.ui.theme.color.bibLibLightColors +import com.pixelized.biblib.ui.theme.dimen.BibLibDimen +import com.pixelized.biblib.ui.theme.shape.Shapes +import com.pixelized.biblib.ui.theme.typography.Typography @Composable -fun BibLibTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) { - val colors = if (darkTheme) { - DarkColorPalette - } else { - LightColorPalette - } +fun BibLibTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + content: @Composable () -> Unit +) { + val theme = BibLibTheme( + dimen = BibLibDimen(), + color = if (darkTheme) bibLibDarkColors() else bibLibLightColors() + ) - MaterialTheme( - colors = colors, - typography = Typography, - shapes = Shapes, - ) { - Surface( - color = MaterialTheme.colors.background, + CompositionLocalProvider(LocalBibLibTheme provides theme) { + MaterialTheme( + colors = theme.color.base, + typography = Typography, + shapes = Shapes, content = content ) } diff --git a/app/src/main/java/com/pixelized/biblib/ui/theme/Animation.kt b/app/src/main/java/com/pixelized/biblib/ui/theme/animation/Animation.kt similarity index 76% rename from app/src/main/java/com/pixelized/biblib/ui/theme/Animation.kt rename to app/src/main/java/com/pixelized/biblib/ui/theme/animation/Animation.kt index 6211db9..b2638fc 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/theme/Animation.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/theme/animation/Animation.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.theme +package com.pixelized.biblib.ui.theme.animation object Animation { diff --git a/app/src/main/java/com/pixelized/biblib/ui/theme/color/BibLibColor.kt b/app/src/main/java/com/pixelized/biblib/ui/theme/color/BibLibColor.kt new file mode 100644 index 0000000..3ad3968 --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/ui/theme/color/BibLibColor.kt @@ -0,0 +1,39 @@ +package com.pixelized.biblib.ui.theme.color + +import androidx.compose.material.Colors +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors +import androidx.compose.runtime.Stable +import androidx.compose.ui.graphics.Color +import javax.annotation.concurrent.Immutable + + +@Stable +@Immutable +data class BibLibColor( + val base: Colors +) + +fun bibLibDarkColors( + base: Colors = darkColors( + primary = BibLibColorPalette.Green, + secondary = BibLibColorPalette.VeryLightGreen, + onPrimary = Color.White, + onSecondary = Color.White, + error = BibLibColorPalette.Red, + ), +) = BibLibColor( + base = base, +) + +fun bibLibLightColors( + base: Colors = lightColors( + primary = BibLibColorPalette.Green, + secondary = BibLibColorPalette.VeryLightGreen, + onPrimary = Color.White, + onSecondary = Color.White, + error = BibLibColorPalette.Red, + ) +) = BibLibColor( + base = base, +) \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/theme/color/BibLibColorPalette.kt b/app/src/main/java/com/pixelized/biblib/ui/theme/color/BibLibColorPalette.kt new file mode 100644 index 0000000..4e0c6eb --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/ui/theme/color/BibLibColorPalette.kt @@ -0,0 +1,52 @@ +package com.pixelized.biblib.ui.theme.color + + +import androidx.compose.ui.graphics.Color +import javax.annotation.concurrent.Immutable + +@Immutable +object BibLibColorPalette { + val VeryDarkBlue: Color = Color(0xFF09179D) + val DarkBlue: Color = Color(0xFF1A2BDB) + val Blue: Color = Color(0xFF2970F2) + val LightBlue: Color = Color(0xFF1A91DB) + val VeryLightBlue: Color = Color(0xFF1EDDEF) + val VeryDarkPurple: Color = Color(0xFF5F0E9E) + val DarkPurple: Color = Color(0xFF8330DB) + val Purple: Color = Color(0xFF9B54C3) + val LightPurple: Color = Color(0xFFBC52D9) + val VeryLightPurple: Color = Color(0xFFC856D1) + val VeryDarkGreen: Color = Color(0xFF16544A) + val DarkGreen: Color = Color(0xFF207A6B) + val Green: Color = Color(0xFF269482) + val LightGreen: Color = Color(0xFF2AA18D) + val VeryLightGreen: Color = Color(0xFF3AE0C5) + val VeryDarkRed: Color = Color(0xFF631221) + val DarkRed: Color = Color(0xFFA21D36) + val Red: Color = Color(0xFFC92443) + val LightRed: Color = Color(0xFFE32849) + val VeryLightRed: Color = Color(0xFFF02B4F) + val VeryDarkPink: Color = Color(0xFF960064) + val DarkPink: Color = Color(0xFFBD007E) + val Pink: Color = Color(0xFFD6008F) + val LightPink: Color = Color(0xFFE35BB5) + val VeryLightPink: Color = Color(0xFFFF66CC) + val VeryDarkYellow: Color = Color(0xFFB76036) + val DarkYellow: Color = Color(0xFFD48341) + val Yellow: Color = Color(0xFFF3A850) + val LightYellow: Color = Color(0xFFF5BF63) + val VeryLightYellow: Color = Color(0xFFF9D679) + val VeryDarkGrey: Color = Color(0xFF1D1D1D) + val DarkGrey: Color = Color(0xFF727272) + val Grey: Color = Color(0xFF919195) + val LightGrey: Color = Color(0xFFDFDFDF) + val VeryLightGrey: Color = Color(0xFFF9F9F9) +} + +@Immutable +object GoogleColorPalette { + val blue: Color = Color(0xFF4285F4) + val red: Color = Color(0xFFEA4335) + val yellow: Color = Color(0xFFFBBC05) + val green: Color = Color(0xFF34A853) +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/theme/dimen/BibLibDimen.kt b/app/src/main/java/com/pixelized/biblib/ui/theme/dimen/BibLibDimen.kt new file mode 100644 index 0000000..c7d098f --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/ui/theme/dimen/BibLibDimen.kt @@ -0,0 +1,17 @@ +package com.pixelized.biblib.ui.theme.dimen + +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.Stable +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + +@Stable +@Immutable +data class BibLibDimen( + val default: Dp = 0.dp, + val extraSmall: Dp = 4.dp, + val small: Dp = 8.dp, + val medium: Dp = 16.dp, + val large: Dp = 32.dp, + val extraLarge: Dp = 64.dp, +) \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/theme/Shape.kt b/app/src/main/java/com/pixelized/biblib/ui/theme/shape/Shape.kt similarity index 74% rename from app/src/main/java/com/pixelized/biblib/ui/theme/Shape.kt rename to app/src/main/java/com/pixelized/biblib/ui/theme/shape/Shape.kt index df82238..8f03859 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/theme/Shape.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/theme/shape/Shape.kt @@ -1,11 +1,11 @@ -package com.pixelized.biblib.ui.theme +package com.pixelized.biblib.ui.theme.shape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Shapes import androidx.compose.ui.unit.dp val Shapes = Shapes( - small = RoundedCornerShape(4.dp), + small = RoundedCornerShape(50), medium = RoundedCornerShape(4.dp), large = RoundedCornerShape(0.dp) ) \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/theme/Type.kt b/app/src/main/java/com/pixelized/biblib/ui/theme/typography/Typography.kt similarity index 60% rename from app/src/main/java/com/pixelized/biblib/ui/theme/Type.kt rename to app/src/main/java/com/pixelized/biblib/ui/theme/typography/Typography.kt index 7dab69f..9f75f9c 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/theme/Type.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/theme/typography/Typography.kt @@ -1,4 +1,4 @@ -package com.pixelized.biblib.ui.theme +package com.pixelized.biblib.ui.theme.typography import androidx.compose.material.Typography diff --git a/app/src/main/java/com/pixelized/biblib/utils/extention/ContextEx.kt b/app/src/main/java/com/pixelized/biblib/utils/extention/ContextEx.kt new file mode 100644 index 0000000..96c312b --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/utils/extention/ContextEx.kt @@ -0,0 +1,7 @@ +package com.pixelized.biblib.utils.extention + +import android.content.Context +import android.widget.Toast + +fun Context.showToast(message: String, duration: Int = Toast.LENGTH_SHORT) = + Toast.makeText(this, message, duration).show() \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/utils/extention/MaterialThemeEx.kt b/app/src/main/java/com/pixelized/biblib/utils/extention/MaterialThemeEx.kt new file mode 100644 index 0000000..3d60e8b --- /dev/null +++ b/app/src/main/java/com/pixelized/biblib/utils/extention/MaterialThemeEx.kt @@ -0,0 +1,12 @@ +package com.pixelized.biblib.utils.extention + +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.ReadOnlyComposable +import com.pixelized.biblib.ui.theme.BibLibTheme +import com.pixelized.biblib.ui.theme.LocalBibLibTheme + +val MaterialTheme.bibLib : BibLibTheme + @Composable + @ReadOnlyComposable + get() = LocalBibLibTheme.current \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/utils/injection/ServiceLocator.kt b/app/src/main/java/com/pixelized/biblib/utils/injection/ServiceLocator.kt deleted file mode 100644 index ac66488..0000000 --- a/app/src/main/java/com/pixelized/biblib/utils/injection/ServiceLocator.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.pixelized.biblib.utils.injection - -import com.pixelized.biblib.utils.exception.InjectionException -import kotlin.reflect.KClass - -@Suppress("UNCHECKED_CAST") -object ServiceLocator { - private val components = hashMapOf, Any>() - - operator fun set(clazz: KClass, component: O) { - components[clazz] = component - } - - operator fun get(clazz: KClass<*>): T { - return components[clazz] as? T ?: throw InjectionException(clazz) - } -} - -inline fun get(): T = ServiceLocator[T::class] - -inline fun inject(): Lazy = lazy { ServiceLocator[T::class] } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/utils/mock/BookMock.kt b/app/src/main/java/com/pixelized/biblib/utils/mock/BookMock.kt index dad24e4..b8c29bf 100644 --- a/app/src/main/java/com/pixelized/biblib/utils/mock/BookMock.kt +++ b/app/src/main/java/com/pixelized/biblib/utils/mock/BookMock.kt @@ -1,6 +1,6 @@ package com.pixelized.biblib.utils.mock -import com.pixelized.biblib.ui.data.BookUio +import com.pixelized.biblib.ui.old.data.BookUio class BookMock { val book: BookUio = BookUio( diff --git a/app/src/main/java/com/pixelized/biblib/utils/mock/BookThumbnailMock.kt b/app/src/main/java/com/pixelized/biblib/utils/mock/BookThumbnailMock.kt index 9793227..6493200 100644 --- a/app/src/main/java/com/pixelized/biblib/utils/mock/BookThumbnailMock.kt +++ b/app/src/main/java/com/pixelized/biblib/utils/mock/BookThumbnailMock.kt @@ -1,6 +1,6 @@ package com.pixelized.biblib.utils.mock -import com.pixelized.biblib.ui.data.BookThumbnailUio +import com.pixelized.biblib.ui.old.data.BookThumbnailUio class BookThumbnailMock { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8b8efa4..a634932 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -9,7 +9,7 @@ EPUB MOBI SEND - Sign in with Google + Sign in with diff --git a/build.gradle b/build.gradle index ba2ff31..f9f287d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,15 +1,18 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { + ext { + kotlin_version = "1.6.10" + } + repositories { google() mavenCentral() } - dependencies { - classpath 'com.android.tools.build:gradle:7.0.4' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.10" - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files + dependencies { + classpath 'com.android.tools.build:gradle:7.1.3' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "com.google.dagger:hilt-android-gradle-plugin:2.40.5" } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 158286b..d4aa9c5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Wed Apr 28 21:29:33 CEST 2021 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME