diff --git a/README.md b/README.md index 9a0f094..95e8ae5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,40 @@ -This is gallery app +

Gallery App


+

+GalleryApp is application show image from Unsplash API, based on MVVM architecture. +

-# GalleryApp +

+ +

+ +## Download +Go to the [Releases](https://github.com/LNMCode/GalleryApp/releases) to download the latest APK. + +## UI Application + +[UI Application](https://www.figma.com/file/abtgGeg11LmHEAgyWqTfTg/Art-gallery-app-UI-(Community)?node-id=0%3A1) - UI of application based on ui shared in Figma. + +## Screenshots +

+ + + +

+ +## Tech stack & Open-source libraries +- Minimum SDK level 21 +- 100% [Kotlin](https://kotlinlang.org/) based + [Coroutines](https://github.com/Kotlin/kotlinx.coroutines) + [Flow](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/) for asynchronous. +- JetPack + - [Lifecycle](https://developer.android.com/topic/libraries/architecture/lifecycle) - perform action when lifecycle state changes. + - [ViewModel](https://developer.android.com/topic/libraries/architecture/viewmodel) - store and manage UI-related data in a lifecycle conscious way. + - [Room](https://developer.android.com/topic/libraries/architecture/room) - a persistence library provides an abstraction layer over SQLite. +- Architecture + - MVVM Architecture (View - DataBinding - ViewModel - Model) + - Repository pattern + - [Koin](https://github.com/InsertKoinIO/koin) - dependency injection +- Material Design & Animations +- [Retrofit2 & Gson](https://github.com/square/retrofit) - constructing the REST API +- [OkHttp3](https://github.com/square/okhttp) - implementing interceptor, logging and mocking web server +- [Glide](https://github.com/bumptech/glide) - loading images +- [Timber](https://github.com/JakeWharton/timber) - logging +- Shared element container transform/transition between fragments diff --git a/app/README.md b/app/README.md new file mode 100644 index 0000000..e69de29 diff --git a/app/README.rm b/app/README.rm new file mode 100644 index 0000000..e69de29 diff --git a/app/build.gradle b/app/build.gradle index ed3e46a..24b604f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -40,10 +40,13 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:1.6.10" + implementation "org.jetbrains.kotlin:kotlin-reflect:1.6.21" + implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'com.google.android.material:material:1.5.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.3' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' @@ -55,6 +58,7 @@ dependencies { def retrofit2_version = "2.9.0" implementation "com.squareup.retrofit2:retrofit:$retrofit2_version" implementation "com.squareup.retrofit2:converter-gson:$retrofit2_version" + implementation "com.squareup.okhttp3:logging-interceptor:4.9.3" // -- Room def room_version = "2.4.2" @@ -67,13 +71,13 @@ dependencies { def nav_version = "2.4.2" implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" implementation "androidx.navigation:navigation-ui-ktx:$nav_version" - implementation "androidx.navigation:navigation-runtime:$nav_version" + implementation "androidx.navigation:navigation-runtime-ktx:$nav_version" def material_version = "1.5.0" implementation "com.google.android.material:material:$material_version" //glide - def glide_version = "4.12.0" + def glide_version = "4.13.0" implementation "com.github.bumptech.glide:glide:$glide_version" kapt "com.github.bumptech.glide:compiler:$glide_version" @@ -91,6 +95,11 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines" implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core-common:1.3.2' - implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1' + // architecture components + def lifecycle_version = "2.4.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" + implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version" + // debugging + implementation "com.jakewharton.timber:timber:5.0.1" } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8201d2b..a73485a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,8 +2,10 @@ + + diff --git a/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingActivity.kt b/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingActivity.kt new file mode 100644 index 0000000..d784725 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingActivity.kt @@ -0,0 +1,44 @@ +package com.lnmcode.galleryapp.bindables + +import androidx.annotation.LayoutRes +import androidx.appcompat.app.AppCompatActivity +import androidx.databinding.DataBindingComponent +import androidx.databinding.DataBindingUtil +import androidx.databinding.ViewDataBinding + +abstract class BindingActivity constructor( + @LayoutRes private val contentLayoutId: Int +) : AppCompatActivity() { + + /** This interface is generated during compilation to contain getters for all used instance `BindingAdapters`. */ + protected var bindingComponent: DataBindingComponent? = DataBindingUtil.getDefaultComponent() + + /** + * A data-binding property will be initialized before being called [onCreate]. + * And inflates using the [contentLayoutId] as a content view for activities. + */ + @BindingOnly + protected val binding: T by lazy(LazyThreadSafetyMode.NONE) { + DataBindingUtil.setContentView(this, contentLayoutId, bindingComponent) + } + + /** + * An executable inline binding function that receives a binding receiver in lambda. + * + * @param block A lambda block will be executed with the binding receiver. + * @return T A generic class that extends [ViewDataBinding] and generated by DataBinding on compile time. + */ + @BindingOnly + protected inline fun binding(block: T.() -> Unit): T { + return binding.apply(block) + } + + /** + * Ensures the [binding] property should be executed before being called [onCreate]. + */ + init { + addOnContextAvailableListener { + binding.notifyChange() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingExtensions.kt b/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingExtensions.kt new file mode 100644 index 0000000..13287f0 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingExtensions.kt @@ -0,0 +1,67 @@ +package com.lnmcode.galleryapp.bindables + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.annotation.LayoutRes +import androidx.databinding.DataBindingUtil +import androidx.databinding.ViewDataBinding +import kotlin.reflect.KFunction +import kotlin.reflect.KProperty + +/** + * + * A binding extension for inflating a [layoutRes] and returns a DataBinding type [T]. + * + * @param layoutRes The layout resource ID of the layout to inflate. + * @param attachToParent Whether the inflated hierarchy should be attached to the parent parameter. + * + * @return T A DataBinding class that inflated using the [layoutRes]. + */ +@BindingOnly +fun ViewGroup.binding( + @LayoutRes layoutRes: Int, + attachToParent: Boolean = false +): T { + return DataBindingUtil.inflate( + LayoutInflater.from(context), layoutRes, this, attachToParent + ) +} + +/** + * + * A binding extension for inflating a [layoutRes] and returns a DataBinding type [T] with a receiver. + * + * @param layoutRes The layout resource ID of the layout to inflate. + * @param attachToParent Whether the inflated hierarchy should be attached to the parent parameter. + * @param block A DataBinding receiver lambda. + * + * @return T A DataBinding class that inflated using the [layoutRes]. + */ +@BindingOnly +fun ViewGroup.binding( + @LayoutRes layoutRes: Int, + attachToParent: Boolean = false, + block: T.() -> Unit +): T { + return binding(layoutRes, attachToParent).apply(block) +} + +/** + * + * Returns a binding ID by a [KProperty]. + * + * @return A binding resource ID. + */ +internal fun KProperty<*>.bindingId(): Int { + return BindingManager.getBindingIdByProperty(this) +} + +/** + * + * Returns a binding ID by a [KFunction]. + * + * @return A binding resource ID. + */ +internal fun KFunction<*>.bindingId(): Int { + return BindingManager.getBindingIdByFunction(this) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingFragment.kt b/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingFragment.kt new file mode 100644 index 0000000..18cfe1e --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingFragment.kt @@ -0,0 +1,65 @@ +package com.lnmcode.galleryapp.bindables + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.annotation.CallSuper +import androidx.annotation.LayoutRes +import androidx.databinding.DataBindingComponent +import androidx.databinding.DataBindingUtil +import androidx.databinding.ViewDataBinding +import androidx.fragment.app.Fragment + +abstract class BindingFragment constructor( + @LayoutRes private val contentLayoutId: Int +) : Fragment() { + + /** This interface is generated during compilation to contain getters for all used instance `BindingAdapters`. */ + protected var bindingComponent: DataBindingComponent? = DataBindingUtil.getDefaultComponent() + + /** A backing field for providing an immutable [binding] property. */ + private var _binding: T? = null + + /** + * A data-binding property will be initialized in [onCreateView]. + * And provide the inflated view which depends on [contentLayoutId]. + */ + @BindingOnly + protected val binding: T + get() = checkNotNull(_binding) { + "Fragment $this binding cannot be accessed before onCreateView() or after onDestroyView()" + } + + /** + * An executable inline binding function that receives a binding receiver in lambda. + * + * @param block A lambda block will be executed with the binding receiver. + * @return T A generic class that extends [ViewDataBinding] and generated by DataBinding on compile time. + */ + @BindingOnly + protected inline fun binding(block: T.() -> Unit): T { + return binding.apply(block) + } + + /** + * Ensures the [binding] property should be executed and provide the inflated view which depends on [contentLayoutId]. + */ + @CallSuper + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = DataBindingUtil.inflate(inflater, contentLayoutId, container, false, bindingComponent) + return binding.root + } + + /** + * Destroys the [_binding] backing property for preventing leaking the [ViewDataBinding] that references the Context. + */ + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingManager.kt b/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingManager.kt new file mode 100644 index 0000000..e651d02 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingManager.kt @@ -0,0 +1,81 @@ +package com.lnmcode.galleryapp.bindables + +import androidx.databinding.Bindable +import java.util.* +import kotlin.reflect.KFunction +import kotlin.reflect.KProperty +import kotlin.reflect.full.hasAnnotation +import androidx.databinding.library.baseAdapters.BR + +object BindingManager { + + /** A map for holding information of the generated fields in the BR class. */ + @PublishedApi + internal var bindingFieldsMap: Map = emptyMap() + + /** Java Bean conventions for presenting a boolean. */ + private const val JAVA_BEANS_BOOLEAN: String = "is" + + /** Java Bean conventions for presenting a getter. */ + private const val JAVA_BEANS_GETTER: String = "get" + + /** Java Bean conventions for presenting a setter. */ + private const val JAVA_BEANS_SETTER: String = "set" + + /** + * Binds the `BR` class into the [BindingManager]. + * This method only needs to be called once in the application. + * The `BR` class will be disassembled by the [BindingManager], binding fields will be used + * for finding the proper binding ID of properties. + * + * @param T The `BR` class that generated by the DataBinding processor. + * @return The size of the stored fields. + */ + inline fun bind(): Int { + synchronized(this) { + if (bindingFieldsMap.isNotEmpty()) return@synchronized + bindingFieldsMap = BR::class.java.fields.asSequence() + .map { it.name to it.getInt(null) }.toMap() + } + + return bindingFieldsMap.size + } + + /** + * Returns proper binding ID by property. + * + * @param property A kotlin [androidx.databinding.Bindable] property for finding proper binding ID. + */ + internal fun getBindingIdByProperty(property: KProperty<*>): Int { + val bindingProperty = property.takeIf { + it.getter.hasAnnotation() + } + ?: throw IllegalArgumentException("KProperty: ${property.name} must be annotated with the `@Bindable` annotation on the getter.") + val propertyName = bindingProperty.name.decapitalize(Locale.ENGLISH) + val bindingPropertyName = propertyName + .takeIf { it.startsWith(JAVA_BEANS_BOOLEAN) } + ?.replaceFirst(JAVA_BEANS_BOOLEAN, String()) + ?.decapitalize(Locale.ENGLISH) ?: propertyName + return bindingFieldsMap[bindingPropertyName] ?: BR._all + } + + /** + * Returns proper binding ID by function. + * + * @param function A kotlin [androidx.databinding.Bindable] function for finding proper binding ID. + */ + internal fun getBindingIdByFunction(function: KFunction<*>): Int { + val bindingFunction = function.takeIf { + it.hasAnnotation() + } + ?: throw IllegalArgumentException("KFunction: ${function.name} must be annotated with the `@Bindable` annotation.") + val functionName = bindingFunction.name.decapitalize(Locale.ENGLISH) + val bindingFunctionName = when { + functionName.startsWith(JAVA_BEANS_GETTER) -> functionName.replaceFirst(JAVA_BEANS_GETTER, String()) + functionName.startsWith(JAVA_BEANS_SETTER) -> functionName.replaceFirst(JAVA_BEANS_SETTER, String()) + functionName.startsWith(JAVA_BEANS_BOOLEAN) -> functionName.replaceFirst(JAVA_BEANS_BOOLEAN, String()) + else -> throw IllegalArgumentException("@Bindable associated with method must follow JavaBeans convention $functionName") + }.decapitalize(Locale.ENGLISH) + return bindingFieldsMap[bindingFunctionName] ?: BR._all + } +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingObservable.kt b/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingObservable.kt new file mode 100644 index 0000000..ddc72e9 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingObservable.kt @@ -0,0 +1,46 @@ +package com.lnmcode.galleryapp.bindables + +import androidx.databinding.Observable +import androidx.databinding.PropertyChangeRegistry +import kotlin.reflect.KFunction +import kotlin.reflect.KProperty + +interface BindingObservable: Observable { + + /** + * Notifies a specific property has changed that matches in [PropertyChangeRegistry]. + * This function receives a [androidx.databinding.Bindable] property and if there is a change notification of any of the + * listed properties, this value will be refreshed. + * + * @param property A [androidx.databinding.Bindable] property that should be changed. + */ + fun notifyPropertyChanged(property: KProperty<*>) + + /** + * Notifies a specific property has changed that matches in [PropertyChangeRegistry]. + * This function receives a [androidx.databinding.Bindable] function and if there is a change notification of any of the + * listed properties, this value will be refreshed. + * + * @param function A [androidx.databinding.Bindable] function that should be changed. + */ + fun notifyPropertyChanged(property: KFunction<*>) + + /** + * Notifies a specific property has changed that matches in [PropertyChangeRegistry]. + * This function receives a data-binding id depending on its property name and if there is a change + * notification of any of the listed properties, this value will be refreshed. + * + * @param bindingId A specific data-binding id (generated BR id) that should be changed. + */ + fun notifyPropertyChanged(bindingId: Int) + + /** + * Notifies listeners that all properties of this instance have changed. + */ + fun notifyAllPropertiesChanged() + + /** + * Clears all binding properties from the callback registry. + */ + fun clearAllProperties() +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingProperty.kt b/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingProperty.kt new file mode 100644 index 0000000..a49b312 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingProperty.kt @@ -0,0 +1,72 @@ +package com.lnmcode.galleryapp.bindables + +import androidx.databinding.PropertyChangeRegistry +import androidx.lifecycle.SavedStateHandle +import kotlin.reflect.KProperty + +/** + * + * A property for notifying a specific has changed that matches in [PropertyChangeRegistry]. + * The getter for the property that changes should be marked with [androidx.databinding.Bindable]. + * + * @param defaultValue A default value should be initialized. + * + * @return A delegation property [BindingPropertyIdWithDefaultValue]. + */ +@BindingPropertyDelegate +fun bindingProperty(defaultValue: T) = + BindingPropertyIdWithDefaultValue(defaultValue) + +/** + * + * A delegate class for holding value and notifying changed value on a property. + * + * @param value A default value should be initialized. + */ +class BindingPropertyIdWithDefaultValue( + private var value: T +) { + operator fun getValue(bindingObservable: BindingObservable, property: KProperty<*>): T = value + + operator fun setValue(bindingObservable: BindingObservable, property: KProperty<*>, value: T) { + if (this.value != value) { + this.value = value + bindingObservable.notifyPropertyChanged(property.bindingId()) + } + } +} + + +/** + * + * A [SavedStateHandle] property for notifying a specific has changed that matches in [PropertyChangeRegistry]. + * We can set and get value that matches with [key] from the [SavedStateHandle]. + * Android associate the given value with the key. The value must have a type that could be stored in [android.os.Build]. + * The getter for the property that changes should be marked with [androidx.databinding.Bindable]. + * + * @param key A key for finding saved value. + * + * @return A delegation property [SavedStateHandleBindingProperty]. + */ +@BindingPropertyDelegate +fun SavedStateHandle.asBindingProperty(key: String) = + SavedStateHandleBindingProperty(this, key) + +/** + * + * A delegate class for persisting key-value map and notifying changed value on a property. + * + * @param savedStateHandle A handle to saved state passed down to [androidx.lifecycle.ViewModel]. + * @param key A key for finding saved value. + */ +class SavedStateHandleBindingProperty( + private val savedStateHandle: SavedStateHandle, + private var key: String +) { + operator fun getValue(bindingObservable: BindingObservable, property: KProperty<*>): T? = savedStateHandle.get(key) + + operator fun setValue(bindingObservable: BindingObservable, property: KProperty<*>, value: T?) { + savedStateHandle.set(key, value) + bindingObservable.notifyPropertyChanged(property.bindingId()) + } +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingPropertyDelegate.kt b/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingPropertyDelegate.kt new file mode 100644 index 0000000..755bba3 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingPropertyDelegate.kt @@ -0,0 +1,23 @@ +package com.lnmcode.galleryapp.bindables + +/** Specifies that this annotation should be used to mark binding delegate properties and functions. */ + +@Target( + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY, + AnnotationTarget.PROPERTY_GETTER, + AnnotationTarget.PROPERTY_SETTER +) +@DslMarker +@Retention(AnnotationRetention.BINARY) +internal annotation class BindingPropertyDelegate + +@Target( + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY, + AnnotationTarget.PROPERTY_GETTER, + AnnotationTarget.PROPERTY_SETTER +) +@DslMarker +@Retention(AnnotationRetention.BINARY) +internal annotation class BindingOnly diff --git a/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingViewModel.kt b/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingViewModel.kt new file mode 100644 index 0000000..0593e1c --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/bindables/BindingViewModel.kt @@ -0,0 +1,72 @@ +package com.lnmcode.galleryapp.bindables + +import androidx.databinding.Observable +import androidx.databinding.PropertyChangeRegistry +import androidx.lifecycle.ViewModel +import kotlin.reflect.KFunction +import kotlin.reflect.KProperty +import androidx.databinding.library.baseAdapters.BR + +abstract class BindingViewModel : ViewModel(), BindingObservable { + + private val lock: Any = Any() + + private var propertyCallbacks: PropertyChangeRegistry? = null + + + override fun addOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback?) { + synchronized(lock) lock@{ + val propertyCallbacks = + propertyCallbacks ?: PropertyChangeRegistry().also { propertyCallbacks = it } + propertyCallbacks.add(callback) + } + } + + override fun removeOnPropertyChangedCallback(callback: Observable.OnPropertyChangedCallback?) { + synchronized(lock) lock@{ + val propertyCallbacks = propertyCallbacks ?: return@lock + propertyCallbacks.remove(callback) + } + } + + override fun notifyPropertyChanged(property: KProperty<*>) { + synchronized(lock) lock@{ + val propertyCallbacks = propertyCallbacks ?: return@lock + propertyCallbacks.notifyCallbacks(this, property.bindingId(), null) + } + } + + override fun notifyPropertyChanged(function: KFunction<*>) { + synchronized(lock) lock@{ + val propertyCallbacks = propertyCallbacks ?: return@lock + propertyCallbacks.notifyCallbacks(this, function.bindingId(), null) + } + } + + override fun notifyPropertyChanged(bindingId: Int) { + synchronized(lock) lock@{ + val propertyCallbacks = propertyCallbacks ?: return@lock + propertyCallbacks.notifyCallbacks(this, bindingId, null) + } + } + + override fun notifyAllPropertiesChanged() { + synchronized(lock) lock@{ + val propertyCallbacks = propertyCallbacks ?: return@lock + propertyCallbacks.notifyCallbacks(this, BR._all, null) + } + } + + override fun clearAllProperties() { + synchronized(lock) lock@{ + val propertyCallbacks = propertyCallbacks ?: return@lock + propertyCallbacks.clear() + } + } + + override fun onCleared() { + super.onCleared() + clearAllProperties() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/bindables/FlowBindingProperty.kt b/app/src/main/java/com/lnmcode/galleryapp/bindables/FlowBindingProperty.kt new file mode 100644 index 0000000..34c6b24 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/bindables/FlowBindingProperty.kt @@ -0,0 +1,212 @@ +package com.lnmcode.galleryapp.bindables + +import androidx.databinding.PropertyChangeRegistry +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.launch +import kotlin.reflect.KProperty + + +/** + * + * A [Flow] property for notifying a specific has changed that matches in [PropertyChangeRegistry]. + * This property only collect the flow data on the [androidx.lifecycle.viewModelScope] and notify them. + * So this property is read-only, we can't set a value directly. + * + * The getter for the property that changes should be marked with [androidx.databinding.Bindable]. + * + * @param defaultValue A default value for initializing the property value before flow emitting. + * + * @return A flow delegation property [FlowBindingPropertyIdWithDefaultValue]. + */ +@BindingPropertyDelegate +fun Flow.asBindingProperty(defaultValue: T) = + FlowBindingPropertyIdWithDefaultValue(this, defaultValue) + + +/** + * + * A flow delegate class for collecting value and notifying changed value on a property. + * + * @param flow A flow for providing data. + * @param defaultValue A default value for initializing the property value before flow emitting. + */ +class FlowBindingPropertyIdWithDefaultValue constructor( + private val flow: Flow, + private val defaultValue: T, +) { + + operator fun provideDelegate(bindingViewModel: BindingViewModel, property: KProperty<*>): Delegate { + val bindingId = BindingManager.getBindingIdByProperty(property) + val delegate = Delegate(defaultValue, bindingId) + delegate.collect(flow, bindingViewModel) + return delegate + } + + class Delegate(private var value: T, private val bindingId: Int) { + fun collect(flow: Flow, bindingViewModel: BindingViewModel) { + bindingViewModel.viewModelScope.launch { + flow.distinctUntilChanged().collect { + value = it + bindingViewModel.notifyPropertyChanged(bindingId) + } + } + } + + operator fun getValue(thisRef: Any, property: KProperty<*>): T = value + } + +} + +/** + * + * A [Flow] property for notifying a specific has changed that matches in [PropertyChangeRegistry]. + * This property only collect the flow data on the [androidx.lifecycle.viewModelScope] and notify them. + * So this property is read-only, we can't set a value directly. + * + * The getter for the property that changes should be marked with [androidx.databinding.Bindable]. + * + * @param coroutineScope A [CoroutineScope] where the collecting should be lunched. + * @param defaultValue A default value for initializing the property value before flow emitting. + * + * @return A flow delegation property [FlowBindingPropertyIdWithDefaultValue]. + */ +@BindingPropertyDelegate +fun Flow.asBindingProperty(coroutineScope: CoroutineScope, defaultValue: T) = + FlowBindingPropertyIdWithDefaultValueOnScope(this, coroutineScope, defaultValue) + +/** + * + * A flow delegate class for collecting value and notifying changed value on a property. + * + * @param flow A flow for providing data. + * @param coroutineScope A [CoroutineScope] where the collecting should be lunched. + * @param defaultValue A default value for initializing the property value before flow emitting. + */ +class FlowBindingPropertyIdWithDefaultValueOnScope constructor( + private val flow: Flow, + private val coroutineScope: CoroutineScope, + private val defaultValue: T +) { + operator fun provideDelegate(bindingObservable: BindingObservable, property: KProperty<*>): Delegate { + val bindingId = BindingManager.getBindingIdByProperty(property) + val delegate = Delegate(defaultValue, coroutineScope, bindingId) + delegate.collect(flow, bindingObservable) + return delegate + } + + class Delegate( + private var value: T, + private val coroutineScope: CoroutineScope, + private val bindingId: Int + ) { + fun collect(flow: Flow, bindingObservable: BindingObservable) { + coroutineScope.launch { + flow.distinctUntilChanged().collect { + value = it + bindingObservable.notifyPropertyChanged(bindingId) + } + } + } + + operator fun getValue(thisRef: Any, property: KProperty<*>): T = value + } +} + +/** + * + * A [StateFlow] property for notifying a specific has changed that matches in [PropertyChangeRegistry]. + * This property only collect the flow data on the [androidx.lifecycle.viewModelScope] and notify them. + * So this property is read-only, we can't set a value directly. + * + * The getter for the property that changes should be marked with [androidx.databinding.Bindable]. + * + * @return A flow delegation property [StateFlowBindingPropertyId]. + */ +@BindingPropertyDelegate +fun StateFlow.asBindingProperty() = + StateFlowBindingPropertyId(this) + +/** + * + * A state flow delegate class for collecting value and notifying changed value on a property. + * + * @param stateFlow A state flow for providing data. + */ +class StateFlowBindingPropertyId constructor( + private val stateFlow: StateFlow, +) { + + operator fun provideDelegate(bindingViewModel: BindingViewModel, property: KProperty<*>): Delegate { + val delegate = Delegate(stateFlow, property.bindingId()) + delegate.collect(bindingViewModel) + return delegate + } + + class Delegate(private val stateFlow: StateFlow, private val bindingId: Int) { + fun collect(bindingViewModel: BindingViewModel) { + bindingViewModel.viewModelScope.launch { + stateFlow.collect { + bindingViewModel.notifyPropertyChanged(bindingId) + } + } + } + + operator fun getValue(thisRef: Any, property: KProperty<*>): T = stateFlow.value + } +} + +/** + * + * A [StateFlow] property for notifying a specific has changed that matches in [PropertyChangeRegistry]. + * This property only collect the flow data on the [androidx.lifecycle.viewModelScope] and notify them. + * So this property is read-only, we can't set a value directly. + * + * The getter for the property that changes should be marked with [androidx.databinding.Bindable]. + * + * @param coroutineScope A [CoroutineScope] where the collecting should be lunched. + * + * @return A flow delegation property [StateFlowBindingPropertyId]. + */ +@BindingPropertyDelegate +fun StateFlow.asBindingProperty(coroutineScope: CoroutineScope) = + StateFlowBindingPropertyIdOnScope(coroutineScope, this) + +/** + * + * A state flow delegate class for collecting value and notifying changed value on a property. + * + * @param coroutineScope A [CoroutineScope] where the collecting should be lunched. + * @param stateFlow A state flow for providing data. + */ +class StateFlowBindingPropertyIdOnScope constructor( + private val coroutineScope: CoroutineScope, + private val stateFlow: StateFlow, +) { + + operator fun provideDelegate(bindingObservable: BindingObservable, property: KProperty<*>): Delegate { + val delegate = Delegate(stateFlow, coroutineScope, property.bindingId()) + delegate.collect(bindingObservable) + return delegate + } + + class Delegate( + private val stateFlow: StateFlow, + private val coroutineScope: CoroutineScope, + private val bindingId: Int + ) { + fun collect(bindingObservable: BindingObservable) { + coroutineScope.launch { + stateFlow.collect { + bindingObservable.notifyPropertyChanged(bindingId) + } + } + } + + operator fun getValue(thisRef: Any, property: KProperty<*>): T = stateFlow.value + } +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/cache/AppDatabase.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/cache/AppDatabase.kt new file mode 100644 index 0000000..a44d103 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/cache/AppDatabase.kt @@ -0,0 +1,13 @@ +package com.lnmcode.galleryapp.business.datasource.cache + +import androidx.room.Database +import androidx.room.RoomDatabase +import com.lnmcode.galleryapp.business.datasource.cache.topics.TopicsDao +import com.lnmcode.galleryapp.business.datasource.cache.topics.TopicsEntities + +@Database(entities = [TopicsEntities::class], version = 1, exportSchema = true) +abstract class AppDatabase: RoomDatabase() { + + abstract fun topicsDao(): TopicsDao + +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/cache/helper/TopicsCacheRepository.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/cache/helper/TopicsCacheRepository.kt new file mode 100644 index 0000000..92e66b2 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/cache/helper/TopicsCacheRepository.kt @@ -0,0 +1,19 @@ +package com.lnmcode.galleryapp.business.datasource.cache.helper + +import com.lnmcode.galleryapp.business.datasource.cache.topics.TopicsEntities + +interface TopicsCacheRepository { + suspend fun getTopics(): List + + suspend fun getTopicsFromId( + id: String, + ): TopicsEntities + + suspend fun insertAndReplace( + topicsEntities: TopicsEntities + ): Long + + suspend fun deleteTopics( + topicsEntities: TopicsEntities + ): Int +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/cache/helper/TopicsCacheRepositoryImpl.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/cache/helper/TopicsCacheRepositoryImpl.kt new file mode 100644 index 0000000..44ba26e --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/cache/helper/TopicsCacheRepositoryImpl.kt @@ -0,0 +1,24 @@ +package com.lnmcode.galleryapp.business.datasource.cache.helper + +import com.lnmcode.galleryapp.business.datasource.cache.topics.TopicsDao +import com.lnmcode.galleryapp.business.datasource.cache.topics.TopicsEntities + +class TopicsCacheRepositoryImpl constructor( + private val topicsDao: TopicsDao, +) : TopicsCacheRepository { + override suspend fun getTopics(): List { + return topicsDao.getTopics() + } + + override suspend fun getTopicsFromId(id: String): TopicsEntities { + return topicsDao.getTopicsFromId(id) + } + + override suspend fun insertAndReplace(topicsEntities: TopicsEntities): Long { + return topicsDao.insertAndReplace(topicsEntities) + } + + override suspend fun deleteTopics(topicsEntities: TopicsEntities): Int { + return topicsDao.deleteTopics(topicsEntities) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/cache/topics/TopicsDao.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/cache/topics/TopicsDao.kt new file mode 100644 index 0000000..02d5d5c --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/cache/topics/TopicsDao.kt @@ -0,0 +1,19 @@ +package com.lnmcode.galleryapp.business.datasource.cache.topics + +import androidx.room.* + +@Dao +interface TopicsDao { + + @Query("SELECT * FROM topics") + suspend fun getTopics(): List + + @Query("SELECT * FROM topics WHERE id = :id") + suspend fun getTopicsFromId(id: String): TopicsEntities + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertAndReplace(topicsEntities: TopicsEntities): Long + + @Delete + suspend fun deleteTopics(topicsEntities: TopicsEntities): Int +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/cache/topics/TopicsEntities.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/cache/topics/TopicsEntities.kt new file mode 100644 index 0000000..71e4f8e --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/cache/topics/TopicsEntities.kt @@ -0,0 +1,33 @@ +package com.lnmcode.galleryapp.business.datasource.cache.topics + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.lnmcode.galleryapp.business.domain.cache.TopicsCacheDomain + +@Entity(tableName = "topics") +class TopicsEntities( + + @PrimaryKey(autoGenerate = false) + @ColumnInfo(name = "id") + val id: String, + + @ColumnInfo(name = "slug") + val slug: String, + + @ColumnInfo(name = "title") + val title: String, + + @ColumnInfo(name = "description") + val description: String, + +) + +fun TopicsEntities.toTopicsCacheDomain(): TopicsCacheDomain{ + return TopicsCacheDomain( + id = id, + slug = slug, + title = title, + description = description, + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/interceptor/RequestInterceptor.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/interceptor/RequestInterceptor.kt new file mode 100644 index 0000000..25e04ba --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/interceptor/RequestInterceptor.kt @@ -0,0 +1,14 @@ +package com.lnmcode.galleryapp.business.datasource.interceptor + +import okhttp3.Interceptor +import okhttp3.Response +import timber.log.Timber + +class RequestInterceptor: Interceptor { + override fun intercept(chain: Interceptor.Chain): Response { + val originalRequest = chain.request() + val request = originalRequest.newBuilder().url(originalRequest.url).build() + Timber.d(request.toString()) + return chain.proceed(request) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/search/SearchApiResponsitoryImpl.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/search/SearchApiResponsitoryImpl.kt new file mode 100644 index 0000000..c01b1d6 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/search/SearchApiResponsitoryImpl.kt @@ -0,0 +1,5 @@ +package com.lnmcode.galleryapp.business.datasource.network.helper.search + +class SearchApiRepositoryImpl(private val apiService: SearchApiService) : SearchApiRepository { + override suspend fun search(key: String, query: String) = apiService.search(key = key, query = query) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/search/SearchApiService.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/search/SearchApiService.kt new file mode 100644 index 0000000..7dfa806 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/search/SearchApiService.kt @@ -0,0 +1,15 @@ +package com.lnmcode.galleryapp.business.datasource.network.helper.search + + +import com.lnmcode.galleryapp.business.datasource.network.search.response.Search +import retrofit2.http.GET +import retrofit2.http.Query + +interface SearchApiService { + @GET("search/photos") + suspend fun search( + @Query("client_id") key :String, + @Query("") query :String + ) :Search + +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/search/SearchIApiResponsitory.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/search/SearchIApiResponsitory.kt new file mode 100644 index 0000000..bfe72e6 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/search/SearchIApiResponsitory.kt @@ -0,0 +1,10 @@ +package com.lnmcode.galleryapp.business.datasource.network.helper.search + +import com.lnmcode.galleryapp.business.datasource.network.search.response.Search + +interface SearchApiRepository { + suspend fun search( + key :String, + query :String + ) : Search +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topic/TopicApiRepository.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topic/TopicApiRepository.kt new file mode 100644 index 0000000..f419787 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topic/TopicApiRepository.kt @@ -0,0 +1,11 @@ +package com.lnmcode.galleryapp.business.datasource.network.helper.topic + +import com.lnmcode.galleryapp.business.datasource.network.topic.reponse.TopicDto + + +interface TopicApiRepository { + suspend fun topic( + id :String, + key :String + ) : TopicDto +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topic/TopicApiRepositoryImpl.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topic/TopicApiRepositoryImpl.kt new file mode 100644 index 0000000..f60ed22 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topic/TopicApiRepositoryImpl.kt @@ -0,0 +1,5 @@ +package com.lnmcode.galleryapp.business.datasource.network.helper.topic + +class TopicApiRepositoryImpl(private val topicApiService: TopicApiService) :TopicApiRepository { + override suspend fun topic(id: String, key: String) = topicApiService.topicPhoto(id =id, key =key) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topic/TopicApiService.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topic/TopicApiService.kt new file mode 100644 index 0000000..d907991 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topic/TopicApiService.kt @@ -0,0 +1,15 @@ +package com.lnmcode.galleryapp.business.datasource.network.helper.topic + +import com.lnmcode.galleryapp.business.datasource.network.topic.reponse.TopicDto + +import retrofit2.http.GET +import retrofit2.http.Path +import retrofit2.http.Query + +interface TopicApiService { + @GET("topics/{id_or_slug}") + suspend fun topicPhoto( + @Path("id_or_slug") id :String, + @Query("client_id") key :String + ): TopicDto +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topicphoto/TopicPhotoApiRepository.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topicphoto/TopicPhotoApiRepository.kt new file mode 100644 index 0000000..3a6874b --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topicphoto/TopicPhotoApiRepository.kt @@ -0,0 +1,11 @@ +package com.lnmcode.galleryapp.business.datasource.network.helper.topicphoto + +import com.lnmcode.galleryapp.business.datasource.network.topicphoto.reponse.TopicPhotoResponse + + +interface TopicPhotoIApiRepository { + suspend fun topicPhoto( + id :String, + key :String + ) : List +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topicphoto/TopicPhotoApiRepositoryImpl.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topicphoto/TopicPhotoApiRepositoryImpl.kt new file mode 100644 index 0000000..37a1d8c --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topicphoto/TopicPhotoApiRepositoryImpl.kt @@ -0,0 +1,7 @@ +package com.lnmcode.galleryapp.business.datasource.network.helper.topicphoto + + + +class TopicPhotoApiRepositoryImpl(private val topicApiService: TopicPhotoApiService) : TopicPhotoIApiRepository { + override suspend fun topicPhoto(id :String,key: String) = topicApiService.topicPhoto(id =id,key = key) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topicphoto/TopicPhotoApiService.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topicphoto/TopicPhotoApiService.kt new file mode 100644 index 0000000..f49ce47 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topicphoto/TopicPhotoApiService.kt @@ -0,0 +1,14 @@ +package com.lnmcode.galleryapp.business.datasource.network.helper.topicphoto + +import com.lnmcode.galleryapp.business.datasource.network.topicphoto.reponse.TopicPhotoResponse +import retrofit2.http.GET +import retrofit2.http.Path +import retrofit2.http.Query + +interface TopicPhotoApiService { + @GET("topics/{id_or_slug}/photos") + suspend fun topicPhoto( + @Path("id_or_slug") id :String, + @Query("client_id") key :String, + ): List +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topics/TopicsApiRepositoryImpl.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topics/TopicsApiRepositoryImpl.kt new file mode 100644 index 0000000..16c20d5 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topics/TopicsApiRepositoryImpl.kt @@ -0,0 +1,5 @@ +package com.lnmcode.galleryapp.business.datasource.network.helper.topics + +class TopicsApiRepositoryImpl(private val topicsApiService: TopicsApiService) :TopicsIApiRepository { + override suspend fun topics(key: String) = topicsApiService.topics(key = key) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topics/TopicsApiService.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topics/TopicsApiService.kt new file mode 100644 index 0000000..811ce1b --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topics/TopicsApiService.kt @@ -0,0 +1,12 @@ +package com.lnmcode.galleryapp.business.datasource.network.helper.topics + +import com.lnmcode.galleryapp.business.datasource.network.topics.respose.TopicsDto +import retrofit2.http.GET +import retrofit2.http.Query + +interface TopicsApiService { + @GET("topics") + suspend fun topics( + @Query("client_id") key: String + ): List +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topics/TopicsIApiRepository.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topics/TopicsIApiRepository.kt new file mode 100644 index 0000000..d8185d3 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/helper/topics/TopicsIApiRepository.kt @@ -0,0 +1,9 @@ +package com.lnmcode.galleryapp.business.datasource.network.helper.topics + +import com.lnmcode.galleryapp.business.datasource.network.topics.respose.TopicsDto + +interface TopicsIApiRepository { + suspend fun topics( + key :String + ) : List +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/SearchLinksDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/SearchLinksDto.kt new file mode 100644 index 0000000..93f761a --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/SearchLinksDto.kt @@ -0,0 +1,10 @@ +package com.lnmcode.galleryapp.business.datasource.network.search + +import com.google.gson.annotations.SerializedName + +data class SearchLinksDto( + @SerializedName("self" ) val self : String, + @SerializedName("html" ) val html : String, + @SerializedName("download" ) val download : String, + @SerializedName("download_location" ) val downloadLocation : String +) \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/SearchResultsDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/SearchResultsDto.kt new file mode 100644 index 0000000..a6ab91e --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/SearchResultsDto.kt @@ -0,0 +1,22 @@ +package com.lnmcode.galleryapp.business.datasource.network.search + +import com.google.gson.annotations.SerializedName + +data class SearchResultsDto( + @SerializedName("id" ) val id : String, + @SerializedName("created_at" ) val createdAt : String, + @SerializedName("updated_at" ) val updatedAt : String, + @SerializedName("promoted_at" ) val promotedAt : String, + @SerializedName("width" ) val width : Int, + @SerializedName("height" ) val height : Int, + @SerializedName("color" ) val color : String, + @SerializedName("blur_hash" ) val blurHash : String, + @SerializedName("description" ) val description : String, + @SerializedName("alt_description" ) val altDescription : String, + @SerializedName("urls" ) val searchUrls : SearchUrlsDto, + @SerializedName("links" ) val links : SearchLinksDto, + @SerializedName("likes" ) val likes : Int?, + @SerializedName("liked_by_user" ) val likedByUser : Boolean, + @SerializedName("sponsorship" ) val sponsorship : String, + @SerializedName("user" ) val searchUser : SearchUsersDto, +) diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/SearchUrlsDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/SearchUrlsDto.kt new file mode 100644 index 0000000..38069ae --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/SearchUrlsDto.kt @@ -0,0 +1,12 @@ +package com.lnmcode.galleryapp.business.datasource.network.search + +import com.google.gson.annotations.SerializedName + +data class SearchUrlsDto( + @SerializedName("raw" ) val raw : String, + @SerializedName("full" ) val full : String, + @SerializedName("regular" ) val regular : String, + @SerializedName("small" ) val small : String, + @SerializedName("thumb" ) val thumb : String, + @SerializedName("small_s3" ) val smallS3 : String +) diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/SearchUserLinksDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/SearchUserLinksDto.kt new file mode 100644 index 0000000..4222e9e --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/SearchUserLinksDto.kt @@ -0,0 +1,13 @@ +package com.lnmcode.galleryapp.business.datasource.network.search + +import com.google.gson.annotations.SerializedName + +data class SearchUserLinksDto( + @SerializedName("self" ) val self : String, + @SerializedName("html" ) val html : String, + @SerializedName("photos" ) val photos : String, + @SerializedName("likes" ) val likes : String, + @SerializedName("portfolio" ) val portfolio : String, + @SerializedName("following" ) val following : String, + @SerializedName("followers" ) val followers : String +) diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/SearchUserProfileImageDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/SearchUserProfileImageDto.kt new file mode 100644 index 0000000..4e6d7c0 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/SearchUserProfileImageDto.kt @@ -0,0 +1,9 @@ +package com.lnmcode.galleryapp.business.datasource.network.search + +import com.google.gson.annotations.SerializedName + +data class SearchUserProfileImageDto( + @SerializedName("small" ) val small : String, + @SerializedName("medium" ) val medium : String, + @SerializedName("large" ) val large : String +) diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/SearchUsersDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/SearchUsersDto.kt new file mode 100644 index 0000000..2d689de --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/SearchUsersDto.kt @@ -0,0 +1,24 @@ +package com.lnmcode.galleryapp.business.datasource.network.search + +import com.google.gson.annotations.SerializedName + +data class SearchUsersDto ( + @SerializedName("id" ) val id : String, + @SerializedName("updated_at" ) val updatedAt : String, + @SerializedName("username" ) val username : String, + @SerializedName("name" ) val name : String, + @SerializedName("first_name" ) val firstName : String, + @SerializedName("last_name" ) val lastName : String, + @SerializedName("twitter_username" ) val twitterUsername : String, + @SerializedName("portfolio_url" ) val portfolioUrl : String, + @SerializedName("bio" ) val bio : String, + @SerializedName("location" ) val location : String, + @SerializedName("links" ) val links : SearchUserLinksDto, + @SerializedName("profile_image" ) val profileImage : SearchUserProfileImageDto, + @SerializedName("instagram_username" ) val instagramUsername : String, + @SerializedName("total_collections" ) val totalCollections : Int, + @SerializedName("total_likes" ) val totalLikes : Int, + @SerializedName("total_photos" ) val totalPhotos : Int, + @SerializedName("accepted_tos" ) val acceptedTos : Boolean, + @SerializedName("for_hire" ) val forHire : Boolean, + ) \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/response/Search.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/response/Search.kt new file mode 100644 index 0000000..e798cd3 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/search/response/Search.kt @@ -0,0 +1,10 @@ +package com.lnmcode.galleryapp.business.datasource.network.search.response + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.datasource.network.search.SearchResultsDto + +data class Search( + @SerializedName("total" ) val total : Int, + @SerializedName("total_pages" ) val totalPages : Int?, + @SerializedName("results" ) val results : ArrayList +) diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicCoverLinksDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicCoverLinksDto.kt new file mode 100644 index 0000000..03e8793 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicCoverLinksDto.kt @@ -0,0 +1,20 @@ +package com.lnmcode.galleryapp.business.datasource.network.topic + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topic.TopicCoverLinks +import com.lnmcode.galleryapp.business.domain.models.topic.TopicCoverPhoto + +data class TopicCoverLinksDto( + @SerializedName("self" ) val self : String?, + @SerializedName("html" ) val html : String?, + @SerializedName("download" ) val download : String?, + @SerializedName("download_location" ) val downloadLocation : String? +) +fun TopicCoverLinksDto.toTopicCoverLinks() : TopicCoverLinks { + return TopicCoverLinks( + self=self, + html= html, + download=download, + downloadLocation=downloadLocation + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicCoverPhotoDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicCoverPhotoDto.kt new file mode 100644 index 0000000..88419cb --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicCoverPhotoDto.kt @@ -0,0 +1,43 @@ +package com.lnmcode.galleryapp.business.datasource.network.topic + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topic.TopicCoverPhoto + +data class TopicCoverPhotoDto( + @SerializedName("id" ) val id : String?, + @SerializedName("created_at" ) val createdAt : String?, + @SerializedName("updated_at" ) val updatedAt : String?, + @SerializedName("promoted_at" ) val promotedAt : String?, + @SerializedName("width" ) val width : Int?, + @SerializedName("height" ) val height : Int?, + @SerializedName("color" ) val color : String?, + @SerializedName("blur_hash" ) val blurHash : String?, + @SerializedName("description" ) val description : String?, + @SerializedName("alt_description" ) val altDescription : String?, + @SerializedName("urls" ) val topicCoverPhotoDto : TopicCoverPhotoDto?, + @SerializedName("links" ) val topicCoverUrlsDto : TopicCoverUrlsDto?, + @SerializedName("likes" ) val likes : Int?, + @SerializedName("liked_by_user" ) val likedByUser : Boolean?, + @SerializedName("sponsorship" ) val sponsorship : String?, + @SerializedName("user" ) val topicUserDto : TopicUserDto? +) +fun TopicCoverPhotoDto.toTopicCoverPhoto() : TopicCoverPhoto{ + return TopicCoverPhoto( + id=id, + createdAt=createdAt, + updatedAt= updatedAt, + promotedAt= promotedAt, + width=width, + height= height, + color= color, + blurHash= blurHash, + description= description, + altDescription= altDescription, + topicCoverPhoto =topicCoverPhotoDto?.toTopicCoverPhoto() , + topicCoverUrls =topicCoverUrlsDto?.toTopicCoverUrls(), + likes= likes, + likedByUser= likedByUser, + sponsorship= sponsorship, + topicUser = topicUserDto?.toTopicUser() + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicCoverUrlsDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicCoverUrlsDto.kt new file mode 100644 index 0000000..fcc5063 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicCoverUrlsDto.kt @@ -0,0 +1,25 @@ +package com.lnmcode.galleryapp.business.datasource.network.topic + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topic.TopicCoverPhoto +import com.lnmcode.galleryapp.business.domain.models.topic.TopicCoverUrls +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsUrls + +data class TopicCoverUrlsDto( + @SerializedName("raw" ) val raw : String?, + @SerializedName("full" ) val full : String?, + @SerializedName("regular" ) val regular : String?, + @SerializedName("small" ) val small : String?, + @SerializedName("thumb" ) val thumb : String?, + @SerializedName("small_s3" ) val smallS3 : String? +) +fun TopicCoverUrlsDto.toTopicCoverUrls() : TopicCoverUrls { + return TopicCoverUrls( + raw=raw, + full =full, + regular= regular, + small= small, + thumb =thumb, + smallS3= smallS3 + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicLinksDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicLinksDto.kt new file mode 100644 index 0000000..9fba1c0 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicLinksDto.kt @@ -0,0 +1,17 @@ +package com.lnmcode.galleryapp.business.datasource.network.topic + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topic.TopicLinks + +data class TopicLinksDto ( + @SerializedName("self" ) val self : String?, + @SerializedName("html" ) val html : String?, + @SerializedName("photos" ) val photos : String? + ) +fun TopicLinksDto.toTopicLinks() :TopicLinks{ + return TopicLinks( + self=self, + html =html, + photos =photos + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicOwnersDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicOwnersDto.kt new file mode 100644 index 0000000..1999cea --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicOwnersDto.kt @@ -0,0 +1,47 @@ +package com.lnmcode.galleryapp.business.datasource.network.topic + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topic.TopicOwners + +data class TopicOwnersDto( + @SerializedName("id" ) val id : String?, + @SerializedName("updated_at" ) val updatedAt : String?, + @SerializedName("username" ) val username : String?, + @SerializedName("name" ) val name : String?, + @SerializedName("first_name" ) val firstName : String?, + @SerializedName("last_name" ) val lastName : String?, + @SerializedName("twitter_username" ) val twitterUsername : String?, + @SerializedName("portfolio_url" ) val portfolioUrl : String?, + @SerializedName("bio" ) val bio : String?, + @SerializedName("location" ) val location : String?, + @SerializedName("links" ) val topicOwnersLinksDto : TopicOwnersLinksDto? , + @SerializedName("profile_image" ) val topicOwnersProfileImageDto: TopicOwnersProfileImageDto?, + @SerializedName("instagram_username" ) val instagramUsername : String?, + @SerializedName("total_collections" ) val totalCollections : Int?, + @SerializedName("total_likes" ) val totalLikes : Int?, + @SerializedName("total_photos" ) val totalPhotos : Int?, + @SerializedName("accepted_tos" ) val acceptedTos : Boolean?, + @SerializedName("for_hire" ) val forHire : Boolean?, + +) +fun TopicOwnersDto.toTopicOwners() :TopicOwners{ + return TopicOwners( + id = id, + updatedAt= updatedAt, + username= username, + name = name, + firstName= firstName, + lastName= lastName, + twitterUsername= twitterUsername, + portfolioUrl= portfolioUrl, + bio =bio, + location=location,topicOwnersLinks= topicOwnersLinksDto?.toTopicOwnersLinks(), + topicOwnersProfileImage =topicOwnersProfileImageDto?.toTopicOwnersProfileImage(), + instagramUsername=instagramUsername, + totalCollections= totalCollections, + totalLikes= totalLikes, + totalPhotos= totalPhotos, + acceptedTos= acceptedTos, + forHire =forHire + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicOwnersLinksDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicOwnersLinksDto.kt new file mode 100644 index 0000000..7c7464c --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicOwnersLinksDto.kt @@ -0,0 +1,26 @@ +package com.lnmcode.galleryapp.business.datasource.network.topic + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topic.TopicOwnersLinks + +data class TopicOwnersLinksDto( + @SerializedName("self" ) val self : String?, + @SerializedName("html" ) val html : String?, + @SerializedName("photos" ) val photos : String?, + @SerializedName("likes" ) val likes : String?, + @SerializedName("portfolio" ) val portfolio : String?, + @SerializedName("following" ) val following : String?, + @SerializedName("followers" ) val followers : String? + +) +fun TopicOwnersLinksDto.toTopicOwnersLinks() :TopicOwnersLinks{ + return TopicOwnersLinks( + self=self, + html=html, + photos=photos, + likes=likes, + portfolio=portfolio, + following=following, + followers =followers + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicOwnersProfileImageDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicOwnersProfileImageDto.kt new file mode 100644 index 0000000..e88c840 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicOwnersProfileImageDto.kt @@ -0,0 +1,15 @@ +package com.lnmcode.galleryapp.business.datasource.network.topic + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topic.TopicOwnersProfileImage + +data class TopicOwnersProfileImageDto( + @SerializedName("small" ) val small : String?, + @SerializedName("medium" ) val medium : String?, + @SerializedName("large" ) val large : String? +) +fun TopicOwnersProfileImageDto.toTopicOwnersProfileImage() : TopicOwnersProfileImage { + return TopicOwnersProfileImage( + small=small, medium=medium, large=large + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicTopContributorsDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicTopContributorsDto.kt new file mode 100644 index 0000000..d625f47 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicTopContributorsDto.kt @@ -0,0 +1,51 @@ +package com.lnmcode.galleryapp.business.datasource.network.topic + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topic.TopicTopContributors +import com.lnmcode.galleryapp.business.domain.models.topic.TopicTopContributorsImageProfile +import com.lnmcode.galleryapp.business.domain.models.topic.TopicTopContributorsLinks + +data class TopicTopContributorsDto( + @SerializedName("id" ) val id : String?, + @SerializedName("updated_at" ) val updatedAt : String?, + @SerializedName("username" ) val username : String?, + @SerializedName("name" ) val name : String?, + @SerializedName("first_name" ) val firstName : String?, + @SerializedName("last_name" ) val lastName : String?, + @SerializedName("twitter_username" ) val twitterUsername : String?, + @SerializedName("portfolio_url" ) val portfolioUrl : String?, + @SerializedName("bio" ) val bio : String?, + @SerializedName("location" ) val location : String?, + @SerializedName("links" ) val topicTopContributorsLinksDto: TopicTopContributorsLinksDto?, + @SerializedName("profile_image" ) val topicTopContributorsImageProfileDto: TopicTopContributorsImageProfileDto?, + @SerializedName("instagram_username" ) val instagramUsername : String?, + @SerializedName("total_collections" ) val totalCollections : Int?, + @SerializedName("total_likes" ) val totalLikes : Int?, + @SerializedName("total_photos" ) val totalPhotos : Int?, + @SerializedName("accepted_tos" ) val acceptedTos : Boolean?, + @SerializedName("for_hire" ) val forHire : Boolean?, + + ) +fun TopicTopContributorsDto.toTopicTopContributors() :TopicTopContributors{ + return TopicTopContributors( + id =id, + updatedAt =updatedAt, + username=username, + name =name, + firstName= firstName, + lastName = lastName, + twitterUsername =twitterUsername, + portfolioUrl=portfolioUrl, + bio=bio, + location=location, + topicTopContributorsImageProfile = topicTopContributorsImageProfileDto?.toTopicTopContributorsImageProfile(), + topicTopContributorsLinks = topicTopContributorsLinksDto?.toTopicTopContributorsLinks(), + instagramUsername = instagramUsername, + totalCollections =totalCollections, + totalLikes = totalLikes, + totalPhotos = totalPhotos,acceptedTos = acceptedTos, + forHire = forHire + + + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicTopContributorsImageProfileDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicTopContributorsImageProfileDto.kt new file mode 100644 index 0000000..da3111e --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicTopContributorsImageProfileDto.kt @@ -0,0 +1,16 @@ +package com.lnmcode.galleryapp.business.datasource.network.topic + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topic.TopicTopContributorsImageProfile + +data class TopicTopContributorsImageProfileDto( + + @SerializedName("small" ) val small : String?, + @SerializedName("medium" ) val medium : String?, + @SerializedName("large" ) val large : String? +) +fun TopicTopContributorsImageProfileDto.toTopicTopContributorsImageProfile() : TopicTopContributorsImageProfile{ + return TopicTopContributorsImageProfile( + small=small, medium=medium, large=large + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicTopContributorsLinksDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicTopContributorsLinksDto.kt new file mode 100644 index 0000000..d13c5f0 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicTopContributorsLinksDto.kt @@ -0,0 +1,19 @@ +package com.lnmcode.galleryapp.business.datasource.network.topic + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topic.TopicTopContributorsLinks + +data class TopicTopContributorsLinksDto( + @SerializedName("self" ) val self : String?, + @SerializedName("html" ) val html : String?, + @SerializedName("photos" ) val photos : String?, + @SerializedName("likes" ) val likes : String?, + @SerializedName("portfolio" ) val portfolio : String?, + @SerializedName("following" ) val following : String?, + @SerializedName("followers" ) val followers : String? +) +fun TopicTopContributorsLinksDto.toTopicTopContributorsLinks() :TopicTopContributorsLinks{ + return TopicTopContributorsLinks( + self=self, html=html, photos=photos, likes=likes, portfolio=portfolio, following=following, followers=followers + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicUserDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicUserDto.kt new file mode 100644 index 0000000..d1d7f98 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicUserDto.kt @@ -0,0 +1,52 @@ +package com.lnmcode.galleryapp.business.datasource.network.topic + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topic.TopicUser + +data class TopicUserDto( + @SerializedName("id" ) val id : String?, + @SerializedName("updated_at" ) val updatedAt : String?, + @SerializedName("username" ) val username : String?, + @SerializedName("name" ) val name : String?, + @SerializedName("first_name" ) val firstName : String?, + @SerializedName("last_name" ) val lastName : String?, + @SerializedName("twitter_username" ) val twitterUsername : String?, + @SerializedName("portfolio_url" ) val portfolioUrl : String?, + @SerializedName("bio" ) val bio : String?, + @SerializedName("location" ) val location : String?, + @SerializedName("links" ) val topicUserLinksDto : TopicUserLinksDto? , + @SerializedName("profile_image" ) val topicUserProfileImageDto: TopicUserProfileImageDto?, + @SerializedName("instagram_username" ) val instagramUsername : String?, + @SerializedName("total_collections" ) val totalCollections : Int?, + @SerializedName("total_likes" ) val totalLikes : Int?, + @SerializedName("total_photos" ) val totalPhotos : Int?, + @SerializedName("accepted_tos" ) val acceptedTos : Boolean?, + @SerializedName("for_hire" ) val forHire : Boolean?, +) +fun TopicUserDto.toTopicUser() :TopicUser{ + return TopicUser( + username=username, + id=id, + updatedAt=updatedAt, + name =name, + firstName = firstName, + lastName = lastName, + twitterUsername = twitterUsername, + topicUserProfileImage = topicUserProfileImageDto?.toTopicUserProfileImage(), + portfolioUrl = portfolioUrl, + bio = bio, + location = location, + topicUserLinks = topicUserLinksDto?.toTopicUserLinks(), + instagramUsername = instagramUsername, + totalPhotos = totalPhotos, + totalLikes = totalLikes, + totalCollections = totalCollections, + acceptedTos = acceptedTos, + forHire = forHire + + + + + + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicUserLinksDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicUserLinksDto.kt new file mode 100644 index 0000000..db391ed --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicUserLinksDto.kt @@ -0,0 +1,20 @@ +package com.lnmcode.galleryapp.business.datasource.network.topic + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topic.TopicUserLinks + +data class TopicUserLinksDto ( + @SerializedName("self" ) val self : String?, + @SerializedName("html" ) val html : String?, + @SerializedName("photos" ) val photos : String?, + @SerializedName("likes" ) val likes : String?, + @SerializedName("portfolio" ) val portfolio : String?, + @SerializedName("following" ) val following : String?, + @SerializedName("followers" ) val followers : String? + ) +fun TopicUserLinksDto.toTopicUserLinks() :TopicUserLinks{ + return TopicUserLinks( + self=self, html=html, photos=photos, likes=likes, portfolio=portfolio, following=following, followers=followers + ) +} + diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicUserProfileImageDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicUserProfileImageDto.kt new file mode 100644 index 0000000..958aa49 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/TopicUserProfileImageDto.kt @@ -0,0 +1,15 @@ +package com.lnmcode.galleryapp.business.datasource.network.topic + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topic.TopicUserProfileImage + +data class TopicUserProfileImageDto ( + @SerializedName("small" ) val small : String?, + @SerializedName("medium" ) val medium : String?, + @SerializedName("large" ) val large : String? +) +fun TopicUserProfileImageDto.toTopicUserProfileImage() :TopicUserProfileImage{ + return TopicUserProfileImage( + small=small, medium=medium, large=large + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/reponse/TopicDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/reponse/TopicDto.kt new file mode 100644 index 0000000..727fae6 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topic/reponse/TopicDto.kt @@ -0,0 +1,46 @@ +package com.lnmcode.galleryapp.business.datasource.network.topic.reponse + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.datasource.network.topic.* +import com.lnmcode.galleryapp.business.domain.models.topic.Topic + +data class TopicDto( + @SerializedName("id" ) val id : String?, + @SerializedName("slug" ) val slug : String?, + @SerializedName("title" ) val title : String?, + @SerializedName("description" ) val description : String?, + @SerializedName("published_at" ) val publishedAt : String?, + @SerializedName("updated_at" ) val updatedAt : String?, + @SerializedName("starts_at" ) val startsAt : String?, + @SerializedName("ends_at" ) val endsAt : String?, + @SerializedName("only_submissions_after" ) val onlySubmissionsAfter : String?, + @SerializedName("featured" ) val featured : Boolean?, + @SerializedName("total_photos" ) val totalPhotos : Int?, + @SerializedName("total_current_user_submissions" ) val totalCurrentUserSubmissions : String?, + @SerializedName("links" ) val topicLinksDto : TopicLinksDto?, + @SerializedName("status" ) val status : String?, + @SerializedName("owners" ) val topicOwnersDto : List?, + @SerializedName("top_contributors" ) val topContributorsDto : List?, + @SerializedName("cover_photo" ) val topicCoverPhotoDto : TopicCoverPhotoDto?, +) +fun TopicDto.toTopicDomain() : Topic { + return Topic( + id = id, + slug= slug, + title =title, + description =description , + publishedAt =publishedAt, + updatedAt =updatedAt, + startsAt =startsAt, + endsAt =endsAt, + onlySubmissionsAfter =onlySubmissionsAfter, + featured=featured, + totalPhotos=totalPhotos, + totalCurrentUserSubmissions=totalCurrentUserSubmissions, + topicLinks=topicLinksDto?.toTopicLinks(), + status =status, + topicOwners= topicOwnersDto?.map { it.toTopicOwners() }, + topContributors= topContributorsDto?.map { it.toTopicTopContributors() }, + topicCoverPhoto= topicCoverPhotoDto?.toTopicCoverPhoto() + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topicphoto/TopicPhotoLinksDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topicphoto/TopicPhotoLinksDto.kt new file mode 100644 index 0000000..a103097 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topicphoto/TopicPhotoLinksDto.kt @@ -0,0 +1,20 @@ +package com.lnmcode.galleryapp.business.datasource.network.topicphoto + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topicphoto.TopicPhotoLinks +import com.lnmcode.galleryapp.business.domain.models.topicphoto.TopicPhotoUserProfileImage + +data class TopicPhotoLinksDto ( + @SerializedName("self") val self : String, + @SerializedName("html") val html : String, + @SerializedName("download") val download : String, + @SerializedName("download_location") val downloadLocation : String +) +fun TopicPhotoLinksDto.toTopicPhotoLinks() : TopicPhotoLinks{ + return TopicPhotoLinks( + self =self, + html=html, + download=download, + downloadLocation=downloadLocation + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topicphoto/TopicPhotoUrlsDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topicphoto/TopicPhotoUrlsDto.kt new file mode 100644 index 0000000..c475d6a --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topicphoto/TopicPhotoUrlsDto.kt @@ -0,0 +1,23 @@ +package com.lnmcode.galleryapp.business.datasource.network.topicphoto + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topicphoto.TopicPhotoUrls + +data class TopicPhotoUrlsDto( + @SerializedName("raw") val raw : String, + @SerializedName("full") val full : String, + @SerializedName("regular") val regular : String, + @SerializedName("small") val small : String, + @SerializedName("thumb") val thumb : String, + @SerializedName("small_s3") val smallS3 : String +) +fun TopicPhotoUrlsDto.toTopicPhotoUrls() :TopicPhotoUrls{ + return TopicPhotoUrls( + raw=raw, + full=full, + regular=regular, + small=small, + thumb=thumb, + smallS3=smallS3 + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topicphoto/TopicPhotoUserDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topicphoto/TopicPhotoUserDto.kt new file mode 100644 index 0000000..b602815 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topicphoto/TopicPhotoUserDto.kt @@ -0,0 +1,49 @@ +package com.lnmcode.galleryapp.business.datasource.network.topicphoto + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topicphoto.TopicPhoto +import com.lnmcode.galleryapp.business.domain.models.topicphoto.TopicPhotoUser + + +data class TopicPhotoUserDto( + @SerializedName("id") val id : String, + @SerializedName("updated_at") val updatedAt : String, + @SerializedName("username") val username : String, + @SerializedName("name") val name : String, + @SerializedName("first_name") val firstName : String, + @SerializedName("last_name") val lastName : String?, +// @SerializedName("portfolio_url") val portfolioUrl: String, + @SerializedName("bio") val bio : String?, + @SerializedName("location") val location : String?, + @SerializedName("links") val topicPhotoUserLinksDto : TopicPhotoUserLinksDto, + @SerializedName("profile_image") val topicPhotoUserprofileImageDto : TopicPhotoUserProfileImageDto, + @SerializedName("instagram_username") val instagramUsername : String?, + @SerializedName("total_collections") val totalCollections : Int, + @SerializedName("total_likes") val totalLikes : Int, + @SerializedName("total_photos") val totalPhotos : Int, + @SerializedName("accepted_tos") val acceptedTos : Boolean, + @SerializedName("for_hire") val forHire : Boolean, + + ) +fun TopicPhotoUserDto.toTopicPhotoUser() :TopicPhotoUser{ + return TopicPhotoUser( + id=id, + updatedAt=updatedAt, + username=username, + name=name, + firstName=firstName, + lastName=lastName, +// portfolioUrl= portfolioUrl, + bio=bio, + location=location, + topicPhotoUserLinks = topicPhotoUserLinksDto.toTopicPhotoUserLinks(), + topicPhotoUserprofileImage = topicPhotoUserprofileImageDto.toTopicPhotoUserProfileImage(), + instagramUsername = instagramUsername, + totalCollections = totalCollections, + totalLikes =totalLikes, + totalPhotos =totalPhotos, + acceptedTos =acceptedTos, + forHire =forHire + + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topicphoto/TopicPhotoUserLinksDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topicphoto/TopicPhotoUserLinksDto.kt new file mode 100644 index 0000000..f8098bc --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topicphoto/TopicPhotoUserLinksDto.kt @@ -0,0 +1,25 @@ +package com.lnmcode.galleryapp.business.datasource.network.topicphoto + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topicphoto.TopicPhotoUserLinks + +data class TopicPhotoUserLinksDto ( + @SerializedName("self" ) val self : String, + @SerializedName("html" ) val html : String, + @SerializedName("photos" ) val photos : String, + @SerializedName("likes" ) val likes : String?, + @SerializedName("portfolio" ) val portfolio : String, + @SerializedName("following" ) val following : String, + @SerializedName("followers" ) val followers : String + ) +fun TopicPhotoUserLinksDto.toTopicPhotoUserLinks() :TopicPhotoUserLinks{ + return TopicPhotoUserLinks( + self=self, + html=html, + photos=photos, + likes=likes, + portfolio=portfolio, + following=following, + followers=followers + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topicphoto/TopicPhotoUserProfileImageDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topicphoto/TopicPhotoUserProfileImageDto.kt new file mode 100644 index 0000000..a524775 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topicphoto/TopicPhotoUserProfileImageDto.kt @@ -0,0 +1,17 @@ +package com.lnmcode.galleryapp.business.datasource.network.topicphoto + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topicphoto.TopicPhotoUserProfileImage + +data class TopicPhotoUserProfileImageDto( + @SerializedName("small" ) val small : String, + @SerializedName("medium" ) val medium : String, + @SerializedName("large" ) val large : String +) +fun TopicPhotoUserProfileImageDto.toTopicPhotoUserProfileImage() :TopicPhotoUserProfileImage{ + return TopicPhotoUserProfileImage( + small=small, + medium=medium, + large=large + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topicphoto/reponse/TopicPhotoResponse.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topicphoto/reponse/TopicPhotoResponse.kt new file mode 100644 index 0000000..cf8eb85 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topicphoto/reponse/TopicPhotoResponse.kt @@ -0,0 +1,44 @@ +package com.lnmcode.galleryapp.business.datasource.network.topicphoto.reponse + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.datasource.network.topicphoto.* +import com.lnmcode.galleryapp.business.domain.models.topicphoto.TopicPhoto + +data class TopicPhotoResponse( + @SerializedName("id") val id: String, + @SerializedName("created_at") val createdAt : String?, + @SerializedName("updated_at") val updatedAt : String?, + @SerializedName("promoted_at")val promotedAt : String?, + @SerializedName("width") val width: Int, + @SerializedName("height") val height: Int, + @SerializedName("color") val color : String, + @SerializedName("blur_hash") val blurHash: String, + @SerializedName("description") val description: String?, + @SerializedName("alt_description") val altDescription: String?, + @SerializedName("urls") val topicPhotoUrlsDto : TopicPhotoUrlsDto, + @SerializedName("links") val topicPhotoLinksDto : TopicPhotoLinksDto, + @SerializedName("likes") val likes: Int, + @SerializedName("liked_by_user") val likedByUser: Boolean, + //@SerializedName("sponsorship") val sponsorship: String?, + @SerializedName("user") val topicPhotoUserDto: TopicPhotoUserDto +) +fun TopicPhotoResponse.toTopicPhoto() : TopicPhoto{ + return TopicPhoto( + id=id, + createdAt=createdAt, + updatedAt=updatedAt, + promotedAt=promotedAt, + width=width, + height=height, + color=color, + blurHash=blurHash, + description=description, + altDescription=altDescription, + topicPhotoUrls =topicPhotoUrlsDto.toTopicPhotoUrls(), + topicPhotoLinks =topicPhotoLinksDto.toTopicPhotoLinks(), + likes= likes, + likedByUser=likedByUser, + //sponsorship=sponsorship, + topicPhotoUser=topicPhotoUserDto.toTopicPhotoUser() + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsCoverPhotoDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsCoverPhotoDto.kt new file mode 100644 index 0000000..add7161 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsCoverPhotoDto.kt @@ -0,0 +1,45 @@ +package com.lnmcode.galleryapp.business.datasource.network.topics + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsCoverPhoto +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsUsers + +data class TopicsCoverPhotoDto( + @SerializedName("id" ) val id : String, + @SerializedName("created_at" ) val createdAt : String, + @SerializedName("updated_at" ) val updatedAt : String, + @SerializedName("promoted_at" ) val promotedAt : String?, + @SerializedName("width" ) val width : Int, + @SerializedName("height" ) val height : Int, + @SerializedName("color" ) val color : String, + @SerializedName("blur_hash" ) val blurHash : String, + @SerializedName("description" ) val description : String?, + @SerializedName("alt_description" ) val altDescription : String?, + @SerializedName("urls" ) val topicsCoverPhotoUrlsDto : TopicsCoverPhotoUrlsDto, + @SerializedName("links" ) val topicsCoverPhotoLinksDto : TopicsCoverPhotoLinksDto, + @SerializedName("likes" ) val likes : Int?, + @SerializedName("liked_by_user" ) val likedByUser : Boolean, + @SerializedName("sponsorship" ) val sponsorship : String?, + @SerializedName("user" ) val topicsUser : TopicsUsers +) + +fun TopicsCoverPhotoDto.toTopicsCoverPhoto() : TopicsCoverPhoto { + return TopicsCoverPhoto( + id = id, + createdAt = createdAt, + updatedAt = updatedAt, + promotedAt = promotedAt, + width = width, + height = height, + color = color, + blurHash = blurHash, + description = description, + altDescription = altDescription, + topicsCoverPhotoLinks = topicsCoverPhotoLinksDto.toTopicsCoverPhotoLinks(), + topicsCoverPhotoUrls = topicsCoverPhotoUrlsDto.toTopicsCoverPhotoUrlsDto(), + likes = likes, + likedByUser = likedByUser, + sponsorship = sponsorship, + topicsUser = topicsUser, + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsCoverPhotoLinksDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsCoverPhotoLinksDto.kt new file mode 100644 index 0000000..c67157d --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsCoverPhotoLinksDto.kt @@ -0,0 +1,16 @@ +package com.lnmcode.galleryapp.business.datasource.network.topics +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsCoverPhotoLinks + +data class TopicsCoverPhotoLinksDto ( + @SerializedName("self" ) val self : String, + @SerializedName("html" ) val html : String, + @SerializedName("download" ) val download : String, + @SerializedName("download_location" ) val downloadLocation : String + ) + +fun TopicsCoverPhotoLinksDto.toTopicsCoverPhotoLinks(): TopicsCoverPhotoLinks { + return TopicsCoverPhotoLinks( + self, html, download, downloadLocation + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsCoverPhotoUrlsDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsCoverPhotoUrlsDto.kt new file mode 100644 index 0000000..5d6256a --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsCoverPhotoUrlsDto.kt @@ -0,0 +1,19 @@ +package com.lnmcode.galleryapp.business.datasource.network.topics + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsCoverPhotoUrls + +data class TopicsCoverPhotoUrlsDto ( + @SerializedName("raw" ) val raw : String, + @SerializedName("full" ) val full : String, + @SerializedName("regular" ) val regular : String, + @SerializedName("small" ) val small : String, + @SerializedName("thumb" ) val thumb : String, + @SerializedName("small_s3" ) val smallS3 : String + ) + +fun TopicsCoverPhotoUrlsDto.toTopicsCoverPhotoUrlsDto(): TopicsCoverPhotoUrls { + return TopicsCoverPhotoUrls( + raw, full, regular, small, thumb, smallS3 + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsLinksDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsLinksDto.kt new file mode 100644 index 0000000..2cccdf1 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsLinksDto.kt @@ -0,0 +1,16 @@ +package com.lnmcode.galleryapp.business.datasource.network.topics + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsLinks + +data class TopicsLinksDto( + @SerializedName("self" ) val self : String, + @SerializedName("html" ) val html : String, + @SerializedName("photos" ) val photos : String +) + +fun TopicsLinksDto.toTopicsLink(): TopicsLinks { + return TopicsLinks( + self, html, photos + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsOwnersDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsOwnersDto.kt new file mode 100644 index 0000000..2682053 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsOwnersDto.kt @@ -0,0 +1,51 @@ +package com.lnmcode.galleryapp.business.datasource.network.topics + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsOwners +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsOwnersLinks +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsOwnersProfileImage + +data class TopicsOwnersDto( + @SerializedName("id" ) val id : String, + @SerializedName("updated_at" ) val updatedAt : String, + @SerializedName("username" ) val username : String, + @SerializedName("name" ) val name : String, + @SerializedName("first_name" ) val firstName : String, + @SerializedName("last_name" ) val lastName : String?, + @SerializedName("twitter_username" ) val twitterUsername : String?, + @SerializedName("portfolio_url" ) val portfolioUrl : String?, + @SerializedName("bio" ) val bio : String, + @SerializedName("location" ) val location : String, + @SerializedName("links" ) val topicsOwnerLinksDto : TopicsOwnersLinksDto, + @SerializedName("profile_image" ) val topicsOwnerProfileImageDto :TopicsOwnersProfileImageDto, + @SerializedName("instagram_username" ) val instagramUsername : String, + @SerializedName("total_collections" ) val totalCollections : Int, + @SerializedName("total_likes" ) val totalLikes : Int, + @SerializedName("total_photos" ) val totalPhotos : Int, + @SerializedName("accepted_tos" ) val acceptedTos : Boolean, + @SerializedName("for_hire" ) val forHire : Boolean, + +) + +fun TopicsOwnersDto.toTopicsOwners(): TopicsOwners { + return TopicsOwners( + id = id, + updatedAt = updatedAt, + username = username, + name = name, + firstName = firstName, + lastName = lastName, + twitterUsername = twitterUsername, + portfolioUrl = portfolioUrl, + bio = bio, + location = location, + topicsOwnerLinks = topicsOwnerLinksDto.toTopicsOwnersLinks(), + topicsOwnerProfileImage = topicsOwnerProfileImageDto.toTopicsOwnersProfileImage(), + instagramUsername = instagramUsername, + totalCollections = totalCollections, + totalLikes = totalLikes, + totalPhotos = totalPhotos, + acceptedTos = acceptedTos, + forHire = forHire + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsOwnersLinksDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsOwnersLinksDto.kt new file mode 100644 index 0000000..8be28a6 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsOwnersLinksDto.kt @@ -0,0 +1,21 @@ +package com.lnmcode.galleryapp.business.datasource.network.topics + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsOwnersLinks + +data class TopicsOwnersLinksDto( + @SerializedName("self" ) val self : String, + @SerializedName("html" ) val html : String, + @SerializedName("photos" ) val photos : String, + @SerializedName("likes" ) val likes : String, + @SerializedName("portfolio" ) val portfolio : String, + @SerializedName("following" ) val following : String, + @SerializedName("followers" ) val followers : String +) + +fun TopicsOwnersLinksDto.toTopicsOwnersLinks(): TopicsOwnersLinks { + return TopicsOwnersLinks( + self = self, + html, photos, likes, portfolio, following, followers + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsOwnersProfileImageDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsOwnersProfileImageDto.kt new file mode 100644 index 0000000..d52e303 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsOwnersProfileImageDto.kt @@ -0,0 +1,16 @@ +package com.lnmcode.galleryapp.business.datasource.network.topics + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsOwnersProfileImage + +data class TopicsOwnersProfileImageDto ( + @SerializedName("small" ) val small : String, + @SerializedName("medium" ) val medium : String, + @SerializedName("large" ) val large : String + ) + +fun TopicsOwnersProfileImageDto.toTopicsOwnersProfileImage(): TopicsOwnersProfileImage { + return TopicsOwnersProfileImage( + small, medium, large + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsPreviewPhotoUrlsDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsPreviewPhotoUrlsDto.kt new file mode 100644 index 0000000..285c88b --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsPreviewPhotoUrlsDto.kt @@ -0,0 +1,19 @@ +package com.lnmcode.galleryapp.business.datasource.network.topics + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsPreviewPhotoUrls + +data class TopicsPreviewPhotoUrlsDto ( + @SerializedName("raw" ) val raw : String, + @SerializedName("full" ) val full : String, + @SerializedName("regular" ) val regular : String, + @SerializedName("small" ) val small : String, + @SerializedName("thumb" ) val thumb : String, + @SerializedName("small_s3" ) val smallS3 : String + ) + +fun TopicsPreviewPhotoUrlsDto.toTopicsPreviewPhotoUrls(): TopicsPreviewPhotoUrls { + return TopicsPreviewPhotoUrls( + raw, full, regular, small, thumb, smallS3 + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsPreviewPhotosDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsPreviewPhotosDto.kt new file mode 100644 index 0000000..3a7f92f --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsPreviewPhotosDto.kt @@ -0,0 +1,20 @@ +package com.lnmcode.galleryapp.business.datasource.network.topics + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsPreviewPhotoUrls +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsPreviewPhotos + +data class TopicsPreviewPhotosDto( + @SerializedName("id" ) val id : String, + @SerializedName("created_at" ) val createdAt : String, + @SerializedName("updated_at" ) val updatedAt : String, + @SerializedName("blur_hash" ) val blurHash : String, + @SerializedName("urls" ) val TopicsPreviewPhotoUrls : TopicsPreviewPhotoUrls + +) + +fun TopicsPreviewPhotosDto.toTopicsPreviewPhotos(): TopicsPreviewPhotos { + return TopicsPreviewPhotos( + id, createdAt, updatedAt, blurHash, TopicsPreviewPhotoUrls + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsUrlsDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsUrlsDto.kt new file mode 100644 index 0000000..9937f1d --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsUrlsDto.kt @@ -0,0 +1,20 @@ +package com.lnmcode.galleryapp.business.datasource.network.topics + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsUrls + +data class TopicsUrlsDto ( + @SerializedName("raw" ) val raw : String, + @SerializedName("full" ) val full : String, + @SerializedName("regular" ) val regular : String, + @SerializedName("small" ) val small : String, + @SerializedName("thumb" ) val thumb : String, + @SerializedName("small_s3" ) val smallS3 : String + +) + +fun TopicsUrlsDto.toTopicsUrls(): TopicsUrls { + return TopicsUrls( + raw, full, regular, small, thumb, smallS3 + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsUserLinksDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsUserLinksDto.kt new file mode 100644 index 0000000..dc12efb --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsUserLinksDto.kt @@ -0,0 +1,21 @@ +package com.lnmcode.galleryapp.business.datasource.network.topics + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsUserLinks + +data class TopicsUserLinksDto( + @SerializedName("self" ) val self : String, + @SerializedName("html" ) val html : String, + @SerializedName("photos" ) val photos : String, + @SerializedName("likes" ) val likes : String, + @SerializedName("portfolio" ) val portfolio : String, + @SerializedName("following" ) val following : String, + @SerializedName("followers" ) val followers : String, + +) + +fun TopicsUserLinksDto.toTopicsUserLinks(): TopicsUserLinks { + return TopicsUserLinks( + self, html, photos, likes, portfolio, following, followers + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsUserProfileImageDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsUserProfileImageDto.kt new file mode 100644 index 0000000..9a640bf --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsUserProfileImageDto.kt @@ -0,0 +1,17 @@ +package com.lnmcode.galleryapp.business.datasource.network.topics + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsUserProfileImage + +data class TopicsUserProfileImageDto( + @SerializedName("small" ) val small : String, + @SerializedName("medium" ) val medium : String, + @SerializedName("large" ) val large : String + +) + +fun TopicsUserProfileImageDto.toTopicsUserProfileImage(): TopicsUserProfileImage { + return TopicsUserProfileImage( + small, medium, large + ) +} diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsUsersDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsUsersDto.kt new file mode 100644 index 0000000..799c61e --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/TopicsUsersDto.kt @@ -0,0 +1,46 @@ +package com.lnmcode.galleryapp.business.datasource.network.topics + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsUserLinks +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsUserProfileImage +import com.lnmcode.galleryapp.business.domain.models.topics.TopicsUsers + +data class TopicsUsersDto( + @SerializedName("id" ) val id : String, + @SerializedName("updated_at" ) val updatedAt : String, + @SerializedName("username" ) val username : String, + @SerializedName("name" ) val name : String, + @SerializedName("first_name" ) val firstName : String, + @SerializedName("last_name" ) val lastName : String, + @SerializedName("twitter_username" ) val twitterUsername : String, + @SerializedName("portfolio_url" ) val portfolioUrl : String, + @SerializedName("bio" ) val bio : String, + @SerializedName("location" ) val location : String, + @SerializedName("links" ) val topicsUserlinksDto : TopicsUserLinksDto, + @SerializedName("profile_image" ) val topicsUserProfileImageDto : TopicsUserProfileImageDto, + @SerializedName("instagram_username" ) val instagramUsername : String, + @SerializedName("total_collections" ) val totalCollections : Int, + @SerializedName("total_likes" ) val totalLikes : Int, + @SerializedName("total_photos" ) val totalPhotos : Int, + @SerializedName("accepted_tos" ) val acceptedTos : Boolean, + @SerializedName("for_hire" ) val forHire : Boolean, + + ) + +fun TopicsUsersDto.toTopicsUsers(): TopicsUsers { + return TopicsUsers( + id = id, + updatedAt = updatedAt, + username = username, + name = name, + firstName = firstName, + lastName = lastName, + twitterUsername = twitterUsername, + portfolioUrl = portfolioUrl, + bio = bio, + location = location, + topicsUserLinks = topicsUserlinksDto.toTopicsUserLinks(), + topicsUserProfileImage = topicsUserProfileImageDto.toTopicsUserProfileImage(), + instagramUsername, totalCollections, totalLikes, totalPhotos, acceptedTos, forHire + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/respose/TopicsDto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/respose/TopicsDto.kt new file mode 100644 index 0000000..b5a1b23 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/network/topics/respose/TopicsDto.kt @@ -0,0 +1,47 @@ +package com.lnmcode.galleryapp.business.datasource.network.topics.respose + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.datasource.network.topics.* +import com.lnmcode.galleryapp.business.domain.models.topics.Topics + +data class TopicsDto( + @SerializedName("id" ) val id : String, + @SerializedName("slug" ) val slug : String, + @SerializedName("title" ) val title : String, + @SerializedName("description" ) val description : String, + @SerializedName("published_at" ) val publishedAt : String, + @SerializedName("updated_at" ) val updatedAt : String, + @SerializedName("starts_at" ) val startsAt : String, + @SerializedName("ends_at" ) val endsAt : String?, + @SerializedName("only_submissions_after" ) val onlySubmissionsAfter : String?, + @SerializedName("featured" ) val featured : Boolean, + @SerializedName("total_photos" ) val totalPhotos : Int, + @SerializedName("total_current_user_submissions" ) val totalCurrentUserSubmissions : String?, + @SerializedName("links" ) val topicsLinkDto : TopicsLinksDto, + @SerializedName("status" ) val status : String, + @SerializedName("owners" ) val topicsOwnersDto : List, + @SerializedName("cover_photo" ) val topicsCoverPhotoDto : TopicsCoverPhotoDto?, + @SerializedName("preview_photos" ) val topicsPreviewPhotosDto : List +) + +fun TopicsDto.toTopicsDomain(): Topics { + return Topics( + id = id, + slug = slug, + title = title, + description = description, + publishedAt = publishedAt, + updatedAt = updatedAt, + startsAt = startsAt, + endsAt = endsAt, + onlySubmissionsAfter = onlySubmissionsAfter, + featured = featured, + totalPhotos = totalPhotos, + totalCurrentUserSubmissions = totalCurrentUserSubmissions, + topicsLinkDto = topicsLinkDto.toTopicsLink(), + status = status, + topicsOwners = topicsOwnersDto.map { it.toTopicsOwners() }, + topicsCoverPhoto = topicsCoverPhotoDto?.toTopicsCoverPhoto(), + topicsPreviewPhotos = topicsPreviewPhotosDto.map { it.toTopicsPreviewPhotos() }, + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/usecase/SearchUseCase.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/usecase/SearchUseCase.kt new file mode 100644 index 0000000..9667530 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/usecase/SearchUseCase.kt @@ -0,0 +1,11 @@ +package com.lnmcode.galleryapp.business.datasource.usecase + +import com.lnmcode.galleryapp.business.datasource.network.helper.search.SearchApiRepository +import com.lnmcode.galleryapp.business.datasource.network.search.SearchResultsDto + +class SearchUseCase(private val searchApiRepository: SearchApiRepository) { + suspend fun getSearch(query :String, key: String) : List{ + val repository = searchApiRepository.search(query = query, key = key) + return repository.results + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/usecase/TopicPhotoUseCase.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/usecase/TopicPhotoUseCase.kt new file mode 100644 index 0000000..d04246b --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/usecase/TopicPhotoUseCase.kt @@ -0,0 +1,38 @@ +package com.lnmcode.galleryapp.business.datasource.usecase +import android.util.Log +import androidx.annotation.WorkerThread +import com.lnmcode.galleryapp.business.datasource.network.helper.topic.TopicApiRepository +import com.lnmcode.galleryapp.business.datasource.network.helper.topicphoto.TopicPhotoIApiRepository +import com.lnmcode.galleryapp.business.datasource.network.topic.reponse.toTopicDomain +import com.lnmcode.galleryapp.business.datasource.network.topicphoto.reponse.TopicPhotoResponse +import com.lnmcode.galleryapp.business.datasource.network.topicphoto.reponse.toTopicPhoto +import com.lnmcode.galleryapp.business.domain.models.topic.Topic +import com.lnmcode.galleryapp.business.domain.models.topicphoto.TopicPhoto +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.* +import timber.log.Timber + +class TopicPhotoUseCase( + private val keyApi :String, + private val topicPhotoApiRepository: TopicPhotoIApiRepository +) { + init { + Timber.d("Injection TopicsPhotoUserCase") + + } + @WorkerThread + fun getTopicPhoto( + topicsId: String, + onSuccess: () -> Unit, + ) : Flow> = flow{ + val topicPhoto = topicPhotoApiRepository.topicPhoto(id= topicsId, key =keyApi).map { it.toTopicPhoto() + } + emit(topicPhoto) + }.onCompletion { + onSuccess() + + }.flowOn(Dispatchers.IO).catch {e-> + Timber.e(e.message) + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/usecase/TopicUseCase.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/usecase/TopicUseCase.kt new file mode 100644 index 0000000..1c2770e --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/usecase/TopicUseCase.kt @@ -0,0 +1,28 @@ +package com.lnmcode.galleryapp.business.datasource.usecase +import androidx.annotation.WorkerThread +import com.lnmcode.galleryapp.business.datasource.network.helper.topic.TopicApiRepository +import com.lnmcode.galleryapp.business.datasource.network.topic.reponse.toTopicDomain +import com.lnmcode.galleryapp.business.domain.models.topic.Topic +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.* +import timber.log.Timber + + +class TopicUseCase( + private val keyApi :String, + private val topicApiRepository: TopicApiRepository) { + init { + Timber.d("Injection TopicsUserCase") + + } + @WorkerThread + fun getTopic( + id: String, + onSuccess: () -> Unit, + ) : Flow = flow{ + val topic = topicApiRepository.topic(id=id, key =keyApi).toTopicDomain() + emit(topic) + }.onCompletion { }.flowOn(Dispatchers.IO).catch { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/usecase/TopicsCacheUseCase.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/usecase/TopicsCacheUseCase.kt new file mode 100644 index 0000000..8117909 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/usecase/TopicsCacheUseCase.kt @@ -0,0 +1,64 @@ +package com.lnmcode.galleryapp.business.datasource.usecase + +import androidx.annotation.WorkerThread +import com.lnmcode.galleryapp.business.datasource.cache.helper.TopicsCacheRepository +import com.lnmcode.galleryapp.business.datasource.cache.topics.toTopicsCacheDomain +import com.lnmcode.galleryapp.business.domain.cache.TopicsCacheDomain +import com.lnmcode.galleryapp.business.domain.cache.toEntity +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.* +import timber.log.Timber + +class TopicsCacheUseCase( + private val topicsCacheRepository: TopicsCacheRepository, +) { + + init { + Timber.d("Injection TopicsCacheUseCase") + } + + @WorkerThread + fun getTopics( + onSuccess: () -> Unit, + ): Flow> = flow { + val topicsCache = topicsCacheRepository.getTopics().map { it.toTopicsCacheDomain() } + emit(topicsCache) + }.onCompletion { onSuccess() }.flowOn(Dispatchers.IO).catch { e -> + Timber.e(e.message) + } + + @WorkerThread + fun getTopicsFromId( + id: String, + onSuccess: () -> Unit, + ): Flow = flow { + val topics = topicsCacheRepository.getTopicsFromId(id).toTopicsCacheDomain() + emit(topics) + }.onCompletion { onSuccess() }.flowOn(Dispatchers.IO).catch { e -> + Timber.e(e.message) + } + + @WorkerThread + fun insertAndReplace( + topicsCacheDomain: TopicsCacheDomain?, + onSuccess: () -> Unit, + ) = flow { + val topicsEntities = topicsCacheDomain?.toEntity() + val longInsert = topicsEntities?.let { topicsCacheRepository.insertAndReplace(it) } + emit(longInsert) + }.onCompletion { onSuccess() }.flowOn(Dispatchers.IO).catch { e -> + Timber.e(e.message) + } + + @WorkerThread + fun deleteTopics( + topicsCacheDomain: TopicsCacheDomain?, + onSuccess: () -> Unit, + ) = flow { + val topicsEntities = topicsCacheDomain?.toEntity() + val longInsert = topicsEntities?.let { topicsCacheRepository.deleteTopics(it) } + emit(longInsert) + }.onCompletion { onSuccess() }.flowOn(Dispatchers.IO).catch { e -> + Timber.e(e.message) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/datasource/usecase/TopicsUseCase.kt b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/usecase/TopicsUseCase.kt new file mode 100644 index 0000000..92f672c --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/datasource/usecase/TopicsUseCase.kt @@ -0,0 +1,29 @@ +package com.lnmcode.galleryapp.business.datasource.usecase + +import androidx.annotation.WorkerThread +import com.lnmcode.galleryapp.business.datasource.network.helper.topics.TopicsIApiRepository +import com.lnmcode.galleryapp.business.datasource.network.topics.respose.toTopicsDomain +import com.lnmcode.galleryapp.business.domain.models.topics.Topics +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.* +import timber.log.Timber + +class TopicsUseCase constructor( + private val keyAPI: String, + private val topicsIApiRepository: TopicsIApiRepository +) { + + init { + Timber.d("Injection TopicsUserCase") + } + @WorkerThread + fun getTopics( + onSuccess: () -> Unit, + ): Flow> = flow { + val topics = topicsIApiRepository.topics(key = keyAPI).map { it.toTopicsDomain() } + emit(topics) + }.onCompletion { onSuccess() }.flowOn(Dispatchers.IO).catch { e -> + Timber.e(e.message) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/cache/TopicsCacheDomain.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/cache/TopicsCacheDomain.kt new file mode 100644 index 0000000..7789779 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/cache/TopicsCacheDomain.kt @@ -0,0 +1,16 @@ +package com.lnmcode.galleryapp.business.domain.cache + +import com.lnmcode.galleryapp.business.datasource.cache.topics.TopicsEntities + +data class TopicsCacheDomain( + val id: String, + val slug: String, + val title: String, + val description: String, +) + +fun TopicsCacheDomain.toEntity(): TopicsEntities { + return TopicsEntities( + id, slug, title, description + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/Topic.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/Topic.kt new file mode 100644 index 0000000..58ea163 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/Topic.kt @@ -0,0 +1,20 @@ +package com.lnmcode.galleryapp.business.domain.models.topic +data class Topic( + val id : String?, + val slug : String?, + val title : String?, + val description : String?, + val publishedAt : String?, + val updatedAt : String?, + val startsAt : String?, + val endsAt : String?, + val onlySubmissionsAfter : String?, + val featured : Boolean?, + val totalPhotos : Int?, + val totalCurrentUserSubmissions : String?, + val topicLinks : TopicLinks?, + val status : String?, + val topicOwners : List?, + val topContributors : List?, + val topicCoverPhoto : TopicCoverPhoto?, + ) diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicCoverLinks.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicCoverLinks.kt new file mode 100644 index 0000000..c17e5ec --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicCoverLinks.kt @@ -0,0 +1,10 @@ +package com.lnmcode.galleryapp.business.domain.models.topic + +import com.google.gson.annotations.SerializedName + +data class TopicCoverLinks( + val self : String?, + val html : String?, + val download : String?, + val downloadLocation : String? +) diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicCoverPhoto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicCoverPhoto.kt new file mode 100644 index 0000000..9f9d6c5 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicCoverPhoto.kt @@ -0,0 +1,25 @@ +package com.lnmcode.galleryapp.business.domain.models.topic + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.datasource.network.topic.TopicCoverPhotoDto +import com.lnmcode.galleryapp.business.datasource.network.topic.TopicCoverUrlsDto +import com.lnmcode.galleryapp.business.datasource.network.topic.TopicUserDto + +data class TopicCoverPhoto ( + val id : String?, + val createdAt : String?, + val updatedAt : String?, + val promotedAt : String?, + val width : Int?, + val height : Int?, + val color : String?, + val blurHash : String?, + val description : String?, + val altDescription : String?, + val topicCoverPhoto : TopicCoverPhoto?, + val topicCoverUrls : TopicCoverUrls?, + val likes : Int?, + val likedByUser : Boolean?, + val sponsorship : String?, + val topicUser : TopicUser? +) \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicCoverUrls.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicCoverUrls.kt new file mode 100644 index 0000000..48d7218 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicCoverUrls.kt @@ -0,0 +1,12 @@ +package com.lnmcode.galleryapp.business.domain.models.topic + +import com.google.gson.annotations.SerializedName + +data class TopicCoverUrls( + val raw : String?, + val full : String?, + val regular : String?, + val small : String?, + val thumb : String?, + val smallS3 : String? +) diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicLinks.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicLinks.kt new file mode 100644 index 0000000..b86f302 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicLinks.kt @@ -0,0 +1,9 @@ +package com.lnmcode.galleryapp.business.domain.models.topic + +import com.google.gson.annotations.SerializedName + +data class TopicLinks( + val self : String?, + val html : String?, + val photos : String? +) diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicOwners.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicOwners.kt new file mode 100644 index 0000000..df8c7ba --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicOwners.kt @@ -0,0 +1,26 @@ +package com.lnmcode.galleryapp.business.domain.models.topic + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.datasource.network.topic.TopicOwnersLinksDto +import com.lnmcode.galleryapp.business.datasource.network.topic.TopicOwnersProfileImageDto + +data class TopicOwners( + val id : String?, + val updatedAt : String?, + val username : String?, + val name : String?, + val firstName : String?, + val lastName : String?, + val twitterUsername : String?, + val portfolioUrl : String?, + val bio : String?, + val location : String?, + val topicOwnersLinks : TopicOwnersLinks?, + val topicOwnersProfileImage: TopicOwnersProfileImage?, + val instagramUsername : String?, + val totalCollections : Int?, + val totalLikes : Int?, + val totalPhotos : Int?, + val acceptedTos : Boolean?, + val forHire : Boolean?, +) diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicOwnersLinks.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicOwnersLinks.kt new file mode 100644 index 0000000..c9b5be0 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicOwnersLinks.kt @@ -0,0 +1,13 @@ +package com.lnmcode.galleryapp.business.domain.models.topic + +import com.google.gson.annotations.SerializedName + +data class TopicOwnersLinks( + val self : String?, + val html : String?, + val photos : String?, + val likes : String?, + val portfolio : String?, + val following : String?, + val followers : String? +) diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicOwnersProfileImage.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicOwnersProfileImage.kt new file mode 100644 index 0000000..bfc2976 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicOwnersProfileImage.kt @@ -0,0 +1,9 @@ +package com.lnmcode.galleryapp.business.domain.models.topic + +import com.google.gson.annotations.SerializedName + +data class TopicOwnersProfileImage( + val small : String?, + val medium : String?, + val large : String? +) diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicTopContributors.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicTopContributors.kt new file mode 100644 index 0000000..906531d --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicTopContributors.kt @@ -0,0 +1,26 @@ +package com.lnmcode.galleryapp.business.domain.models.topic + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.datasource.network.topic.TopicTopContributorsImageProfileDto +import com.lnmcode.galleryapp.business.datasource.network.topic.TopicTopContributorsLinksDto + +data class TopicTopContributors( + val id : String?, + val updatedAt : String?, + val username : String?, + val name : String?, + val firstName : String?, + val lastName : String?, + val twitterUsername : String?, + val portfolioUrl : String?, + val bio : String?, + val location : String?, + val topicTopContributorsLinks: TopicTopContributorsLinks?, + val topicTopContributorsImageProfile: TopicTopContributorsImageProfile?, + val instagramUsername : String?, + val totalCollections : Int?, + val totalLikes : Int?, + val totalPhotos : Int?, + val acceptedTos : Boolean?, + val forHire : Boolean?, +) diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicTopContributorsImageProfile.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicTopContributorsImageProfile.kt new file mode 100644 index 0000000..12e64a2 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicTopContributorsImageProfile.kt @@ -0,0 +1,9 @@ +package com.lnmcode.galleryapp.business.domain.models.topic + +import com.google.gson.annotations.SerializedName + +data class TopicTopContributorsImageProfile( + val small : String?, + val medium : String?, + val large : String? +) diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicTopContributorsLinks.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicTopContributorsLinks.kt new file mode 100644 index 0000000..541d8f8 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicTopContributorsLinks.kt @@ -0,0 +1,13 @@ +package com.lnmcode.galleryapp.business.domain.models.topic + +import com.google.gson.annotations.SerializedName + +data class TopicTopContributorsLinks( + val self : String?, + val html : String?, + val photos : String?, + val likes : String?, + val portfolio : String?, + val following : String?, + val followers : String? +) diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicUser.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicUser.kt new file mode 100644 index 0000000..02c1b4a --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicUser.kt @@ -0,0 +1,26 @@ +package com.lnmcode.galleryapp.business.domain.models.topic + +import com.google.gson.annotations.SerializedName +import com.lnmcode.galleryapp.business.datasource.network.topic.TopicUserLinksDto +import com.lnmcode.galleryapp.business.datasource.network.topic.TopicUserProfileImageDto + +data class TopicUser( + val id : String?, + val updatedAt : String?, + val username : String?, + val name : String?, + val firstName : String?, + val lastName : String?, + val twitterUsername : String?, + val portfolioUrl : String?, + val bio : String?, + val location : String?, + val topicUserLinks: TopicUserLinks?, + val topicUserProfileImage: TopicUserProfileImage?, + val instagramUsername : String?, + val totalCollections : Int?, + val totalLikes : Int?, + val totalPhotos : Int?, + val acceptedTos : Boolean?, + val forHire : Boolean?, +) diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicUserLinks.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicUserLinks.kt new file mode 100644 index 0000000..e0cd221 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicUserLinks.kt @@ -0,0 +1,13 @@ +package com.lnmcode.galleryapp.business.domain.models.topic + +import com.google.gson.annotations.SerializedName + +data class TopicUserLinks( + val self : String?, + val html : String?, + val photos : String?, + val likes : String?, + val portfolio : String?, + val following : String?, + val followers : String? +) diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicUserProfileImage.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicUserProfileImage.kt new file mode 100644 index 0000000..68c9f15 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topic/TopicUserProfileImage.kt @@ -0,0 +1,9 @@ +package com.lnmcode.galleryapp.business.domain.models.topic + +import com.google.gson.annotations.SerializedName + +data class TopicUserProfileImage( + val small : String?, + val medium : String?, + val large : String? +) diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topicphoto/TopicPhoto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topicphoto/TopicPhoto.kt new file mode 100644 index 0000000..629694a --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topicphoto/TopicPhoto.kt @@ -0,0 +1,27 @@ +package com.lnmcode.galleryapp.business.domain.models.topicphoto +import android.os.Parcelable +import com.lnmcode.galleryapp.business.datasource.network.topicphoto.TopicPhotoLinksDto +import com.lnmcode.galleryapp.business.datasource.network.topicphoto.TopicPhotoUrlsDto +import com.lnmcode.galleryapp.business.datasource.network.topicphoto.TopicPhotoUserDto +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicPhoto( + val id: String, + val createdAt : String?, + val updatedAt : String?, + val promotedAt : String?, + val width: Int, + val height: Int, + val color : String, + val blurHash: String, + val description: String?, + val altDescription: String?, + val topicPhotoUrls : TopicPhotoUrls, + val topicPhotoLinks : TopicPhotoLinks, + val likes: Int, + val likedByUser: Boolean, + //val sponsorship: String?, + val topicPhotoUser: TopicPhotoUser +): Parcelable + diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topicphoto/TopicPhotoLinks.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topicphoto/TopicPhotoLinks.kt new file mode 100644 index 0000000..2e72637 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topicphoto/TopicPhotoLinks.kt @@ -0,0 +1,12 @@ +package com.lnmcode.galleryapp.business.domain.models.topicphoto + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicPhotoLinks( + val self : String, + val html : String, + val download : String, + val downloadLocation : String +): Parcelable diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topicphoto/TopicPhotoUrls.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topicphoto/TopicPhotoUrls.kt new file mode 100644 index 0000000..8fda3d7 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topicphoto/TopicPhotoUrls.kt @@ -0,0 +1,14 @@ +package com.lnmcode.galleryapp.business.domain.models.topicphoto + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicPhotoUrls( + val raw : String, + val full : String, + val regular : String, + val small : String, + val thumb : String, + val smallS3 : String +): Parcelable diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topicphoto/TopicPhotoUser.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topicphoto/TopicPhotoUser.kt new file mode 100644 index 0000000..1ccdb36 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topicphoto/TopicPhotoUser.kt @@ -0,0 +1,25 @@ +package com.lnmcode.galleryapp.business.domain.models.topicphoto + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicPhotoUser( + val id : String, + val updatedAt : String, + val username : String, + val name : String, + val firstName : String, + val lastName : String?, +// val portfolioUrl: String, + val bio : String?, + val location : String?, + val topicPhotoUserLinks : TopicPhotoUserLinks, + val topicPhotoUserprofileImage : TopicPhotoUserProfileImage, + val instagramUsername : String?, + val totalCollections : Int, + val totalLikes : Int, + val totalPhotos : Int, + val acceptedTos : Boolean, + val forHire : Boolean, +): Parcelable diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topicphoto/TopicPhotoUserLinks.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topicphoto/TopicPhotoUserLinks.kt new file mode 100644 index 0000000..acebe74 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topicphoto/TopicPhotoUserLinks.kt @@ -0,0 +1,15 @@ +package com.lnmcode.galleryapp.business.domain.models.topicphoto + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicPhotoUserLinks( + val self : String, + val html : String, + val photos : String, + val likes : String?, + val portfolio : String?, + val following : String, + val followers : String +): Parcelable diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topicphoto/TopicPhotoUserProfileImage.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topicphoto/TopicPhotoUserProfileImage.kt new file mode 100644 index 0000000..66e499f --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topicphoto/TopicPhotoUserProfileImage.kt @@ -0,0 +1,11 @@ +package com.lnmcode.galleryapp.business.domain.models.topicphoto + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicPhotoUserProfileImage( + val small : String, + val medium : String, + val large : String +): Parcelable diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/Topics.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/Topics.kt new file mode 100644 index 0000000..dc35e40 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/Topics.kt @@ -0,0 +1,25 @@ +package com.lnmcode.galleryapp.business.domain.models.topics + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class Topics( + val id: String, + val slug: String, + val title: String, + val description: String, + val publishedAt: String, + val updatedAt: String, + val startsAt: String, + val endsAt: String?, + val onlySubmissionsAfter: String?, + val featured: Boolean, + val totalPhotos: Int, + val totalCurrentUserSubmissions: String?, + val topicsLinkDto: TopicsLinks, + val status: String, + val topicsOwners: List, + val topicsCoverPhoto: TopicsCoverPhoto?, + val topicsPreviewPhotos: List +) :Parcelable diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsCoverPhoto.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsCoverPhoto.kt new file mode 100644 index 0000000..be01f49 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsCoverPhoto.kt @@ -0,0 +1,24 @@ +package com.lnmcode.galleryapp.business.domain.models.topics + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicsCoverPhoto( + val id: String, + val createdAt: String, + val updatedAt: String, + val promotedAt: String?, + val width: Int, + val height: Int, + val color: String, + val blurHash: String, + val description: String?, + val altDescription: String?, + val topicsCoverPhotoUrls: TopicsCoverPhotoUrls, + val topicsCoverPhotoLinks: TopicsCoverPhotoLinks, + val likes: Int?, + val likedByUser: Boolean, + val sponsorship: String?, + val topicsUser: TopicsUsers +) :Parcelable diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsCoverPhotoLinks.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsCoverPhotoLinks.kt new file mode 100644 index 0000000..b37869e --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsCoverPhotoLinks.kt @@ -0,0 +1,12 @@ +package com.lnmcode.galleryapp.business.domain.models.topics + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicsCoverPhotoLinks( + val self: String, + val html: String, + val download: String, + val downloadLocation: String +): Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsCoverPhotoUrls.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsCoverPhotoUrls.kt new file mode 100644 index 0000000..ff03d29 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsCoverPhotoUrls.kt @@ -0,0 +1,14 @@ +package com.lnmcode.galleryapp.business.domain.models.topics + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicsCoverPhotoUrls( + val raw: String, + val full: String, + val regular: String, + val small: String, + val thumb: String, + val smallS3: String +): Parcelable diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsLinks.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsLinks.kt new file mode 100644 index 0000000..6b18467 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsLinks.kt @@ -0,0 +1,11 @@ +package com.lnmcode.galleryapp.business.domain.models.topics + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicsLinks( + val self: String, + val html: String, + val photos: String +): Parcelable diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsOwners.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsOwners.kt new file mode 100644 index 0000000..7e70ef2 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsOwners.kt @@ -0,0 +1,26 @@ +package com.lnmcode.galleryapp.business.domain.models.topics + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicsOwners( + val id: String, + val updatedAt: String, + val username: String, + val name: String, + val firstName: String, + val lastName: String?, + val twitterUsername: String?, + val portfolioUrl: String?, + val bio: String, + val location: String?, + val topicsOwnerLinks: TopicsOwnersLinks, + val topicsOwnerProfileImage: TopicsOwnersProfileImage, + val instagramUsername: String, + val totalCollections: Int, + val totalLikes: Int, + val totalPhotos: Int, + val acceptedTos: Boolean, + val forHire: Boolean, +) :Parcelable diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsOwnersLinks.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsOwnersLinks.kt new file mode 100644 index 0000000..1f8db18 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsOwnersLinks.kt @@ -0,0 +1,15 @@ +package com.lnmcode.galleryapp.business.domain.models.topics + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicsOwnersLinks( + val self: String, + val html: String, + val photos: String, + val likes: String, + val portfolio: String, + val following: String, + val followers: String +):Parcelable diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsOwnersProfileImage.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsOwnersProfileImage.kt new file mode 100644 index 0000000..c7ce941 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsOwnersProfileImage.kt @@ -0,0 +1,11 @@ +package com.lnmcode.galleryapp.business.domain.models.topics + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicsOwnersProfileImage( + val small: String, + val medium: String, + val large: String +) :Parcelable diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsPreviewPhotoUrls.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsPreviewPhotoUrls.kt new file mode 100644 index 0000000..e0c2409 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsPreviewPhotoUrls.kt @@ -0,0 +1,14 @@ +package com.lnmcode.galleryapp.business.domain.models.topics + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicsPreviewPhotoUrls( + val raw: String, + val full: String, + val regular: String, + val small: String, + val thumb: String, + val smallS3: String +): Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsPreviewPhotos.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsPreviewPhotos.kt new file mode 100644 index 0000000..2aded14 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsPreviewPhotos.kt @@ -0,0 +1,13 @@ +package com.lnmcode.galleryapp.business.domain.models.topics + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicsPreviewPhotos( + val id: String, + val createdAt: String, + val updatedAt: String, + val blurHash: String, + val TopicsPreviewPhotoUrls: TopicsPreviewPhotoUrls +): Parcelable diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsUrls.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsUrls.kt new file mode 100644 index 0000000..e7361ea --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsUrls.kt @@ -0,0 +1,14 @@ +package com.lnmcode.galleryapp.business.domain.models.topics + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicsUrls( + val raw: String, + val full: String, + val regular: String, + val small: String, + val thumb: String, + val smallS3: String +): Parcelable diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsUserLinks.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsUserLinks.kt new file mode 100644 index 0000000..f45a431 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsUserLinks.kt @@ -0,0 +1,15 @@ +package com.lnmcode.galleryapp.business.domain.models.topics + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicsUserLinks( + val self: String, + val html: String, + val photos: String, + val likes: String, + val portfolio: String, + val following: String, + val followers: String, +): Parcelable diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsUserProfileImage.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsUserProfileImage.kt new file mode 100644 index 0000000..fc6735c --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsUserProfileImage.kt @@ -0,0 +1,11 @@ +package com.lnmcode.galleryapp.business.domain.models.topics + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicsUserProfileImage( + val small: String, + val medium: String, + val large: String +): Parcelable diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsUsers.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsUsers.kt new file mode 100644 index 0000000..9149c4b --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/models/topics/TopicsUsers.kt @@ -0,0 +1,26 @@ +package com.lnmcode.galleryapp.business.domain.models.topics + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class TopicsUsers( + val id: String, + val updatedAt: String, + val username: String, + val name: String, + val firstName: String, + val lastName: String, + val twitterUsername: String, + val portfolioUrl: String, + val bio: String, + val location: String?, + val topicsUserLinks: TopicsUserLinks, + val topicsUserProfileImage: TopicsUserProfileImage, + val instagramUsername: String, + val totalCollections: Int, + val totalLikes: Int, + val totalPhotos: Int, + val acceptedTos: Boolean, + val forHire: Boolean, +): Parcelable diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/utils/Constants.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/utils/Constants.kt new file mode 100644 index 0000000..3c8acb5 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/utils/Constants.kt @@ -0,0 +1,12 @@ +package com.lnmcode.galleryapp.business.domain.utils + +class Constants { + + companion object{ + + const val BASE_URL_API_NAME = "baseUrlAPI" + const val KEY_API_URL_NAME = "" + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/utils/DataState.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/utils/DataState.kt new file mode 100644 index 0000000..3c0c37e --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/utils/DataState.kt @@ -0,0 +1,39 @@ +package com.lnmcode.galleryapp.business.domain.utils + + +class DataState( + val stateMessage: StateMessage? = null, + val data: T? = null, + val isLoading: Boolean = false +) { + + companion object { + fun error( + response: Response, + ): DataState { + return DataState( + stateMessage = StateMessage( + response + ), + data = null, + ) + } + + fun data( + response: Response?, + data: T? = null, + ): DataState { + return DataState( + stateMessage = response?.let { + StateMessage( + it + ) + }, + data = data, + ) + } + + fun loading(): DataState = DataState(isLoading = true) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/business/domain/utils/StateMessage.kt b/app/src/main/java/com/lnmcode/galleryapp/business/domain/utils/StateMessage.kt new file mode 100644 index 0000000..b1c864c --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/business/domain/utils/StateMessage.kt @@ -0,0 +1,7 @@ +package com.lnmcode.galleryapp.business.domain.utils + +data class StateMessage(val response: Response) + +data class Response( + val message: String?, +) \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/di/AppModule.kt b/app/src/main/java/com/lnmcode/galleryapp/di/AppModule.kt new file mode 100644 index 0000000..1213d98 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/di/AppModule.kt @@ -0,0 +1,4 @@ +package com.lnmcode.galleryapp.di + +val appModule = + networkModule + repositoryModel + useCaseModule + persistenceModule + viewModelModule \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/di/NetworkModule.kt b/app/src/main/java/com/lnmcode/galleryapp/di/NetworkModule.kt new file mode 100644 index 0000000..483aadf --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/di/NetworkModule.kt @@ -0,0 +1,63 @@ +package com.lnmcode.galleryapp.di + +import com.lnmcode.galleryapp.business.datasource.interceptor.RequestInterceptor +import com.lnmcode.galleryapp.business.datasource.network.helper.search.SearchApiService +import com.lnmcode.galleryapp.business.datasource.network.helper.topic.TopicApiService +import com.lnmcode.galleryapp.business.datasource.network.helper.topicphoto.TopicPhotoApiService +import com.lnmcode.galleryapp.business.datasource.network.helper.topics.TopicsApiService +import com.lnmcode.galleryapp.business.domain.utils.Constants +import okhttp3.OkHttpClient +import org.koin.core.qualifier.named +import org.koin.dsl.module +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +val networkModule = module { + + single(named(Constants.BASE_URL_API_NAME)) { baseUrlString() } + single(named(Constants.KEY_API_URL_NAME)) { keyAPIUrl() } + + single { RequestInterceptor() } + + single { okHttpClientBuilder(get()) } + + single { retrofitBuilder(get(), get(qualifier = named(Constants.BASE_URL_API_NAME))) } + + // Search service + single { get().create(SearchApiService::class.java) } + + // Topic service + single { get().create(TopicApiService::class.java) } + + single { get().create(TopicPhotoApiService::class.java) } + + single { get().create(TopicsApiService::class.java) } + +} + +internal fun okHttpClientBuilder( + interceptor: RequestInterceptor +): OkHttpClient { + return OkHttpClient.Builder() + .addInterceptor(interceptor) + .build() +} + +internal fun retrofitBuilder( + okHttpClient: OkHttpClient, + baseUrlAPI: String, +): Retrofit { + return Retrofit.Builder() + .client(okHttpClient) + .baseUrl(baseUrlAPI) + .addConverterFactory(GsonConverterFactory.create()) + .build() +} + +internal fun baseUrlString(): String { + return "https://api.unsplash.com/" +} + +internal fun keyAPIUrl(): String { + return "5IFGi9p0CqcZxupJ1ZV9ZUAoXddSBuRGYMW2cjKEvv8" +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/di/PersistenceModule.kt b/app/src/main/java/com/lnmcode/galleryapp/di/PersistenceModule.kt new file mode 100644 index 0000000..6b01f2b --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/di/PersistenceModule.kt @@ -0,0 +1,24 @@ +package com.lnmcode.galleryapp.di + +import android.content.Context +import androidx.room.Room +import com.lnmcode.galleryapp.R +import com.lnmcode.galleryapp.business.datasource.cache.AppDatabase +import org.koin.android.ext.koin.androidApplication +import org.koin.dsl.module + +val persistenceModule = module { + + single { roomDatabaseBuilder(androidApplication()) } + + single { get().topicsDao() } + +} + +internal fun roomDatabaseBuilder( + context: Context +): AppDatabase { + return Room.databaseBuilder(context, AppDatabase::class.java, + context.getString(R.string.database_name) + ).fallbackToDestructiveMigration().build() +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/di/RepositoryModule.kt b/app/src/main/java/com/lnmcode/galleryapp/di/RepositoryModule.kt new file mode 100644 index 0000000..9a9588a --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/di/RepositoryModule.kt @@ -0,0 +1,32 @@ +package com.lnmcode.galleryapp.di + +import com.lnmcode.galleryapp.business.datasource.cache.helper.TopicsCacheRepository +import com.lnmcode.galleryapp.business.datasource.cache.helper.TopicsCacheRepositoryImpl +import com.lnmcode.galleryapp.business.datasource.network.helper.search.SearchApiRepositoryImpl +import com.lnmcode.galleryapp.business.datasource.network.helper.search.SearchApiRepository +import com.lnmcode.galleryapp.business.datasource.network.helper.topic.TopicApiRepository +import com.lnmcode.galleryapp.business.datasource.network.helper.topic.TopicApiRepositoryImpl +import com.lnmcode.galleryapp.business.datasource.network.helper.topicphoto.TopicPhotoApiRepositoryImpl +import com.lnmcode.galleryapp.business.datasource.network.helper.topicphoto.TopicPhotoIApiRepository +import com.lnmcode.galleryapp.business.datasource.network.helper.topics.TopicsApiRepositoryImpl +import com.lnmcode.galleryapp.business.datasource.network.helper.topics.TopicsIApiRepository +import org.koin.dsl.bind +import org.koin.dsl.module + +val repositoryModel = module { + + // Repository network + // Search repository + single { SearchApiRepositoryImpl(get()) } + + // Topic repository + single { TopicApiRepositoryImpl(get()) } + + + single { TopicPhotoApiRepositoryImpl(get()) } + + single { TopicsApiRepositoryImpl(get()) } + + // Repository cache + single { TopicsCacheRepositoryImpl(get()) } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/di/UseCaseModule.kt b/app/src/main/java/com/lnmcode/galleryapp/di/UseCaseModule.kt new file mode 100644 index 0000000..279d9f1 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/di/UseCaseModule.kt @@ -0,0 +1,21 @@ +package com.lnmcode.galleryapp.di + +import com.lnmcode.galleryapp.business.datasource.usecase.* +import com.lnmcode.galleryapp.business.domain.utils.Constants +import org.koin.core.qualifier.named +import org.koin.dsl.module + +val useCaseModule = module { + + // UseCase network + single { SearchUseCase(get()) } + + single { TopicPhotoUseCase(get(qualifier = named(Constants.KEY_API_URL_NAME)),get()) } + + factory { TopicsUseCase(get(qualifier = named(Constants.KEY_API_URL_NAME)), get()) } + + single { TopicUseCase(get(qualifier = named(Constants.KEY_API_URL_NAME)),get()) } + + // UseCase cache + single { TopicsCacheUseCase(get()) } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/di/ViewModelModule.kt b/app/src/main/java/com/lnmcode/galleryapp/di/ViewModelModule.kt new file mode 100644 index 0000000..a031ef1 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/di/ViewModelModule.kt @@ -0,0 +1,19 @@ +package com.lnmcode.galleryapp.di + +import com.lnmcode.galleryapp.presentation.ui.MainViewModel +import com.lnmcode.galleryapp.presentation.ui.boards.BoardsViewModel +import com.lnmcode.galleryapp.presentation.ui.detail.DetailViewModel +import com.lnmcode.galleryapp.presentation.ui.gallery.GalleryViewModel +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.dsl.module + +val viewModelModule = module { + + viewModel { MainViewModel() } + + viewModel { BoardsViewModel(get(), get()) } + + viewModel { (topicsId: String) -> GalleryViewModel(topicsId, get()) } + + viewModel { DetailViewModel() } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/BaseApplication.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/BaseApplication.kt deleted file mode 100644 index 328c184..0000000 --- a/app/src/main/java/com/lnmcode/galleryapp/presentation/BaseApplication.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.lnmcode.galleryapp.presentation - -import android.app.Application -import android.content.Context - -class BaseApplication: Application() { - -} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/MainActivity.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/MainActivity.kt deleted file mode 100644 index 1a24fda..0000000 --- a/app/src/main/java/com/lnmcode/galleryapp/presentation/MainActivity.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.lnmcode.galleryapp.presentation - -import androidx.appcompat.app.AppCompatActivity -import android.os.Bundle -import com.lnmcode.galleryapp.R - -class MainActivity : AppCompatActivity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/adapter/BaseAdapter.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/adapter/BaseAdapter.kt new file mode 100644 index 0000000..55419b3 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/adapter/BaseAdapter.kt @@ -0,0 +1,81 @@ +package com.lnmcode.galleryapp.presentation.adapter + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.lifecycle.* +import androidx.recyclerview.widget.* + +abstract class BaseAdapter : RecyclerView.Adapter(), DefaultLifecycleObserver { + + private val differ = AsyncListDiffer( + getAdapterCallBack(), + getAsyncDifferConfigBuilder() + ) + + fun addSubmit(list: List) { + differ.submitList(list.toMutableList()) + } + + private fun getDiffCallBack(): DiffUtil.ItemCallback { + return object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: T, newItem: T): Boolean { + return areItemsTheSameItem(oldItem, newItem) + } + + override fun areContentsTheSame(oldItem: T, newItem: T): Boolean { + return areContentsTheSameItem(oldItem, newItem) + } + } + } + + private fun getAsyncDifferConfigBuilder() = AsyncDifferConfig.Builder(getDiffCallBack()).build() + + private fun getAdapterCallBack() = RecyclerAdapterCallBack(this) + + /** + * return layout by resource id + */ + abstract fun layout(): Int + + /** + * return viewholder by resource id + */ + abstract fun viewHolder(view: View): BaseViewHolder + + /** + * Called to check whether two objects represent the same item. + */ + abstract fun areItemsTheSameItem(oldItem: T, newItem: T): Boolean + + /** + * Called to check whether two items have the same data. + */ + abstract fun areContentsTheSameItem(oldItem: T, newItem: T): Boolean + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder { + return viewHolder( + LayoutInflater.from(parent.context).inflate( + layout(), parent, false, + ) + ) + } + + override fun onBindViewHolder(holder: BaseViewHolder, position: Int) { + try { + holder.bindData(data = differ.currentList[position] as Any) + } catch (e: Exception) { + e.printStackTrace() + } + } + + override fun getItemCount(): Int { + return differ.currentList.size + } + + override fun onDestroy(owner: LifecycleOwner) { + super.onDestroy(owner) + differ.currentList.clear() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/adapter/BaseViewHolder.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/adapter/BaseViewHolder.kt new file mode 100644 index 0000000..a711505 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/adapter/BaseViewHolder.kt @@ -0,0 +1,21 @@ +package com.lnmcode.galleryapp.presentation.adapter + +import android.content.Context +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import kotlin.jvm.Throws + +abstract class BaseViewHolder(view: View) : RecyclerView.ViewHolder(view), View.OnClickListener { + + val context: Context = view.context + + init { + view.setOnClickListener(this) + } + + /** + * binds data to view holder class + * */ + @Throws(Exception::class) + abstract fun bindData(data: Any) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/adapter/RecyclerAdapterCallBack.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/adapter/RecyclerAdapterCallBack.kt new file mode 100644 index 0000000..e0adb37 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/adapter/RecyclerAdapterCallBack.kt @@ -0,0 +1,23 @@ +package com.lnmcode.galleryapp.presentation.adapter + +import androidx.recyclerview.widget.ListUpdateCallback + +class RecyclerAdapterCallBack( + private val adapter: BaseAdapter +) : ListUpdateCallback { + override fun onInserted(position: Int, count: Int) { + adapter.notifyItemChanged(position, count) + } + + override fun onRemoved(position: Int, count: Int) { + adapter.notifyDataSetChanged() + } + + override fun onMoved(fromPosition: Int, toPosition: Int) { + adapter.notifyDataSetChanged() + } + + override fun onChanged(position: Int, count: Int, payload: Any?) { + adapter.notifyItemRangeChanged(position, count, payload) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/adapter/SectionRow.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/adapter/SectionRow.kt new file mode 100644 index 0000000..329a754 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/adapter/SectionRow.kt @@ -0,0 +1,15 @@ +package com.lnmcode.galleryapp.presentation.adapter + +data class SectionRow( + var section: Int = 0, + var row: Int = 0, +) { + + fun nextSection() { + this.section++ + this.row = 0 + } + + fun nextRow() = row++ + +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/binding/RecyclerViewBinding.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/binding/RecyclerViewBinding.kt new file mode 100644 index 0000000..bce86ca --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/binding/RecyclerViewBinding.kt @@ -0,0 +1,81 @@ +package com.lnmcode.galleryapp.presentation.binding + +import androidx.databinding.BindingAdapter +import androidx.recyclerview.widget.RecyclerView +import com.lnmcode.galleryapp.business.domain.cache.TopicsCacheDomain +import com.lnmcode.galleryapp.business.domain.models.topicphoto.TopicPhoto +import com.lnmcode.galleryapp.business.domain.models.topics.Topics +import com.lnmcode.galleryapp.presentation.adapter.BaseAdapter +import com.lnmcode.galleryapp.presentation.ui.boards.BoardTopicsAdapter +import com.lnmcode.galleryapp.presentation.ui.boards.BoardsAdapter +import com.lnmcode.galleryapp.presentation.ui.gallery.GalleryAdapter +import com.lnmcode.galleryapp.presentation.ui.gallery.GalleryHeadAdapter + +object RecyclerViewBinding { + + @JvmStatic + @BindingAdapter("adapter", "adapterTopicsList") + fun bindAdapterPosterList( + view: RecyclerView, + adapter: BoardsAdapter, + topics: List?, + ) { + if (view.adapter != null) { + val adapterRecycler = view.adapter as BoardsAdapter + adapterRecycler.addTopics(topics ?: emptyList()) + } else { + adapter.addTopics(topics ?: emptyList()) + view.adapter = adapter + } + + } + + @JvmStatic + @BindingAdapter("adapter", "adapterTopicsCache") + fun bindAdapterTopicsCache( + view: RecyclerView, + adapter: BoardTopicsAdapter, + topics: List, + ) { + if (view.adapter != null) { + val adapterRecycler = view.adapter as BoardTopicsAdapter + adapterRecycler.addTopics(topics) + } else { + adapter.addTopics(topics) + view.adapter = adapter + } + } + + @JvmStatic + @BindingAdapter("adapter", "adapterTopicPhoto") + fun bindAdapterTopicPhoto( + view: RecyclerView, + adapter: GalleryHeadAdapter, + topicPhoto: List, + ) { + if (view.adapter != null) { + val adapterRecycler = view.adapter as GalleryHeadAdapter + adapterRecycler.addTopics(topicPhoto) + } else { + adapter.addTopics(topicPhoto) + view.adapter = adapter + } + } + + @JvmStatic + @BindingAdapter("adapter", "adapterGridTopicPhoto") + fun bindAdapterGridTopicPhoto( + view: RecyclerView, + adapter: GalleryAdapter, + topicPhoto: List, + ) { + if (view.adapter != null) { + val adapterRecycler = view.adapter as GalleryAdapter + adapterRecycler.addTopics(topicPhoto) + } else { + adapter.addTopics(topicPhoto) + view.adapter = adapter + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/binding/ViewBinding.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/binding/ViewBinding.kt new file mode 100644 index 0000000..b4e8d24 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/binding/ViewBinding.kt @@ -0,0 +1,29 @@ +package com.lnmcode.galleryapp.presentation.binding + +import android.view.View +import android.widget.ImageView +import androidx.databinding.BindingAdapter +import com.lnmcode.galleryapp.presentation.extensions.gone +import com.lnmcode.galleryapp.presentation.glide.GlideApp + +object ViewBinding { + + @JvmStatic + @BindingAdapter("loadImage") + fun bindLoadImage(view: ImageView, url: String?) { + GlideApp.with(view.context) + .load(url) + .into(view) + } + + @JvmStatic + @BindingAdapter("gone") + fun bindGone(view: View, shouldBeGone: Boolean?) { + if (shouldBeGone == true) { + view.gone(true) + } else { + view.gone(false) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/extensions/ViewExtensions.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/extensions/ViewExtensions.kt new file mode 100644 index 0000000..f576186 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/extensions/ViewExtensions.kt @@ -0,0 +1,12 @@ +package com.lnmcode.galleryapp.presentation.extensions + +import android.view.View + +fun View.visible() { + visibility = View.VISIBLE +} + +fun View.gone(shouldBeGone: Boolean) { + if (shouldBeGone) visibility = View.GONE + else visible() +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/glide/GlideApp.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/glide/GlideApp.kt new file mode 100644 index 0000000..b66a49a --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/glide/GlideApp.kt @@ -0,0 +1,7 @@ +package com.lnmcode.galleryapp.presentation.glide + +import com.bumptech.glide.annotation.GlideModule +import com.bumptech.glide.module.AppGlideModule + +@GlideModule +class GlideAppModule: AppGlideModule() \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/BaseApplication.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/BaseApplication.kt new file mode 100644 index 0000000..fdc08c2 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/BaseApplication.kt @@ -0,0 +1,22 @@ +package com.lnmcode.galleryapp.presentation.ui + +import android.app.Application +import android.content.Context +import com.lnmcode.galleryapp.di.appModule +import org.koin.android.ext.koin.androidContext +import org.koin.core.context.startKoin +import timber.log.Timber + +class BaseApplication: Application() { + + override fun onCreate() { + super.onCreate() + startKoin { + androidContext(this@BaseApplication) + modules(appModule) + } + + Timber.plant(Timber.DebugTree()) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/MainActivity.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/MainActivity.kt new file mode 100644 index 0000000..e80d2f8 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/MainActivity.kt @@ -0,0 +1,19 @@ +package com.lnmcode.galleryapp.presentation.ui + +import android.os.Bundle +import androidx.navigation.fragment.NavHostFragment +import com.lnmcode.galleryapp.R +import com.lnmcode.galleryapp.bindables.BindingActivity +import com.lnmcode.galleryapp.databinding.ActivityMainBinding +import org.koin.androidx.viewmodel.ext.android.getViewModel + +class MainActivity : BindingActivity(R.layout.activity_main) { + + override fun onCreate(savedInstanceState: Bundle?) { + //applyExitMaterialTransform() + super.onCreate(savedInstanceState) + binding { + vm = getViewModel() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/MainViewModel.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/MainViewModel.kt new file mode 100644 index 0000000..b764652 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/MainViewModel.kt @@ -0,0 +1,16 @@ +package com.lnmcode.galleryapp.presentation.ui + +import androidx.databinding.Bindable +import com.lnmcode.galleryapp.bindables.BindingViewModel +import com.lnmcode.galleryapp.bindables.bindingProperty + +class MainViewModel(): BindingViewModel() { + + @get:Bindable + var isLoading: Boolean by bindingProperty(false) + private set + + fun setShowLoading(boolean: Boolean) { + isLoading = boolean + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/OnChangeLayout.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/OnChangeLayout.kt new file mode 100644 index 0000000..06c9c1d --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/OnChangeLayout.kt @@ -0,0 +1,11 @@ +package com.lnmcode.galleryapp.presentation.ui + +import android.view.View +import android.widget.ImageView + +interface OnChangeLayout { + + fun onChangeSharedWithParameters(data: Any, viewItemShare: ImageView) + + fun onChangeWithParameters(data: Any) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/boards/BoardTopicsAdapter.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/boards/BoardTopicsAdapter.kt new file mode 100644 index 0000000..28fe289 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/boards/BoardTopicsAdapter.kt @@ -0,0 +1,40 @@ +package com.lnmcode.galleryapp.presentation.ui.boards + +import android.view.View +import com.lnmcode.galleryapp.R +import com.lnmcode.galleryapp.business.domain.cache.TopicsCacheDomain +import com.lnmcode.galleryapp.presentation.adapter.BaseAdapter +import com.lnmcode.galleryapp.presentation.adapter.BaseViewHolder +import com.lnmcode.galleryapp.presentation.adapter.SectionRow +import com.lnmcode.galleryapp.presentation.viewholder.BoardTopicsViewHolder + +class BoardTopicsAdapter( + private val boardsActionCacheEvent: BoardsActionCacheEvent, +) : BaseAdapter() { + + init { + addSubmit(listOf()) + } + + fun addTopics(topics: List) { + addSubmit(topics) + } + + override fun layout() = R.layout.layout_item_topics_boards + + override fun viewHolder(view: View) = BoardTopicsViewHolder(view, boardsActionCacheEvent) + + override fun areItemsTheSameItem( + oldItem: TopicsCacheDomain, + newItem: TopicsCacheDomain + ): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSameItem( + oldItem: TopicsCacheDomain, + newItem: TopicsCacheDomain + ): Boolean { + return oldItem.id == newItem.id + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/boards/BoardsActionCacheEvent.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/boards/BoardsActionCacheEvent.kt new file mode 100644 index 0000000..06a92f7 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/boards/BoardsActionCacheEvent.kt @@ -0,0 +1,9 @@ +package com.lnmcode.galleryapp.presentation.ui.boards + +import com.lnmcode.galleryapp.business.domain.cache.TopicsCacheDomain + +interface BoardsActionCacheEvent { + fun insertTopicsCache(topicsCacheDomain: TopicsCacheDomain) + + fun deleteTopicsCache(topicsCacheDomain: TopicsCacheDomain) +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/boards/BoardsAdapter.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/boards/BoardsAdapter.kt new file mode 100644 index 0000000..bccb71a --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/boards/BoardsAdapter.kt @@ -0,0 +1,42 @@ +package com.lnmcode.galleryapp.presentation.ui.boards + +import android.view.View +import com.lnmcode.galleryapp.R +import com.lnmcode.galleryapp.business.domain.cache.TopicsCacheDomain +import com.lnmcode.galleryapp.business.domain.models.topicphoto.TopicPhoto +import com.lnmcode.galleryapp.business.domain.models.topics.Topics +import com.lnmcode.galleryapp.presentation.adapter.BaseAdapter +import com.lnmcode.galleryapp.presentation.ui.OnChangeLayout +import com.lnmcode.galleryapp.presentation.viewholder.BoardViewHolder + +class BoardsAdapter( + private val onChangeLayout: OnChangeLayout, + private val boardsActionCacheEvent: BoardsActionCacheEvent, +) : BaseAdapter() { + + init { + addSubmit(listOf()) + } + + fun addTopics(topics: List) { + addSubmit(topics) + } + + override fun layout() = R.layout.layout_item_boards + + override fun viewHolder(view: View) = BoardViewHolder(view, onChangeLayout, boardsActionCacheEvent) + + override fun areItemsTheSameItem( + oldItem: Topics, + newItem: Topics + ): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSameItem( + oldItem: Topics, + newItem: Topics + ): Boolean { + return oldItem.id == newItem.id + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/boards/BoardsFragment.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/boards/BoardsFragment.kt new file mode 100644 index 0000000..376e2db --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/boards/BoardsFragment.kt @@ -0,0 +1,55 @@ +package com.lnmcode.galleryapp.presentation.ui.boards + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.navigation.fragment.findNavController +import com.lnmcode.galleryapp.R +import com.lnmcode.galleryapp.bindables.BindingFragment +import com.lnmcode.galleryapp.business.domain.cache.TopicsCacheDomain +import com.lnmcode.galleryapp.business.domain.models.topic.Topic +import com.lnmcode.galleryapp.business.domain.models.topics.Topics +import com.lnmcode.galleryapp.databinding.FragmentBoardsBinding +import com.lnmcode.galleryapp.presentation.ui.OnChangeLayout +import org.koin.androidx.viewmodel.ext.android.viewModel + +class BoardsFragment( +) : BindingFragment(R.layout.fragment_boards), OnChangeLayout, + BoardsActionCacheEvent { + + private val viewModel: BoardsViewModel by viewModel() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + super.onCreateView(inflater, container, savedInstanceState) + return binding { + adapter = BoardsAdapter(this@BoardsFragment, this@BoardsFragment) + adapterTopics = BoardTopicsAdapter(this@BoardsFragment) + vm = viewModel + }.root + } + + override fun onChangeSharedWithParameters(data: Any, viewItemShare: ImageView) { + + } + + override fun onChangeWithParameters(data: Any) { + findNavController().navigate( + BoardsFragmentDirections.actionBoardsFragmentToGalleryFragment(data as String) + ) + } + + override fun insertTopicsCache(topicsCacheDomain: TopicsCacheDomain) { + viewModel.insertTopicsCache(topicsCacheDomain) + } + + override fun deleteTopicsCache(topicsCacheDomain: TopicsCacheDomain) { + viewModel.deleteTopicsCache(topicsCacheDomain) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/boards/BoardsViewModel.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/boards/BoardsViewModel.kt new file mode 100644 index 0000000..2fbc9d1 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/boards/BoardsViewModel.kt @@ -0,0 +1,106 @@ +package com.lnmcode.galleryapp.presentation.ui.boards + +import androidx.databinding.Bindable +import androidx.lifecycle.viewModelScope +import com.lnmcode.galleryapp.bindables.BindingViewModel +import com.lnmcode.galleryapp.bindables.asBindingProperty +import com.lnmcode.galleryapp.bindables.bindingProperty +import com.lnmcode.galleryapp.business.datasource.usecase.TopicsCacheUseCase +import com.lnmcode.galleryapp.business.domain.models.topics.Topics +import com.lnmcode.galleryapp.business.datasource.usecase.TopicsUseCase +import com.lnmcode.galleryapp.business.domain.cache.TopicsCacheDomain +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flatMapLatest +import timber.log.Timber + +class BoardsViewModel( + private val topicsUseCase: TopicsUseCase, + private val topicsCacheUseCase: TopicsCacheUseCase, +) : BindingViewModel() { + @get:Bindable + var isLoading: Boolean by bindingProperty(true) + private set + private val topicsFlow = topicsUseCase.getTopics( + onSuccess = { isLoading = true } + ) + + @get:Bindable + val topics: List by topicsFlow.asBindingProperty(viewModelScope, emptyList()) + private val topicsCacheStateFlow = MutableStateFlow(0) + private val topicsCacheFlow = topicsCacheStateFlow.flatMapLatest { + topicsCacheUseCase.getTopics( + onSuccess = { + isLoading = true + } + ) + } + + @get:Bindable + val topicsCache: List by topicsCacheFlow.asBindingProperty( + viewModelScope, + emptyList() + ) + + private val insertTopicsDomainStateFlow = MutableStateFlow(null) + private val insertTopicsDomainFlow = insertTopicsDomainStateFlow.flatMapLatest { + topicsCacheUseCase.insertAndReplace( + it, + onSuccess = { + onDoneInsertTopicsCacheItem() + onRefreshTopicsFromCache() + isLoading = true + } + ) + } + + @get:Bindable + private val insertTopicsDomain by insertTopicsDomainFlow.asBindingProperty(viewModelScope) + + private val deleteTopicsDomainStateFlow = MutableStateFlow(null) + private val deleteTopicsDomainFlow = deleteTopicsDomainStateFlow.flatMapLatest { + topicsCacheUseCase.deleteTopics( + it, + onSuccess = { + onDoneDeleteTopicsCacheItem() + onRefreshTopicsFromCache() + isLoading = true + } + ) + } + + @get:Bindable + private val deleteTopicsDomain by deleteTopicsDomainFlow.asBindingProperty(viewModelScope) + + private var numberCountEvent: Int = -1 + + fun insertTopicsCache(topicsCacheDomain: TopicsCacheDomain) { + if (!topicsCache.contains(topicsCacheDomain)) { + Timber.d(topicsCacheDomain.toString()) + insertTopicsDomainStateFlow.value = topicsCacheDomain + } + } + + fun deleteTopicsCache(topicsCacheDomain: TopicsCacheDomain) { + Timber.d(topicsCacheDomain.toString()) + deleteTopicsDomainStateFlow.value = topicsCacheDomain + } + + private fun onRefreshTopicsFromCache() { + topicsCacheStateFlow.value = numberCountEvent++ + Timber.d("onRefreshTopicsFromCache ${topicsCacheStateFlow.value}") + } + + private fun onDoneDeleteTopicsCacheItem() { + deleteTopicsDomainStateFlow.value = null + } + + private fun onDoneInsertTopicsCacheItem() { + insertTopicsDomainStateFlow.value = null + } + + init { + Timber.d("Init Boards View model") + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/detail/DetailBottomSheet.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/detail/DetailBottomSheet.kt new file mode 100644 index 0000000..a4b9ebb --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/detail/DetailBottomSheet.kt @@ -0,0 +1,11 @@ +package com.lnmcode.galleryapp.presentation.ui.detail + +import android.view.View +import com.google.android.material.bottomsheet.BottomSheetBehavior + +interface DetailBottomSheet { + + fun getBottomSheetBehavior(bottomSheet: View): BottomSheetBehavior + + fun showAndHideBottomSheet() +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/detail/DetailFragment.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/detail/DetailFragment.kt new file mode 100644 index 0000000..4c82e89 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/detail/DetailFragment.kt @@ -0,0 +1,81 @@ +package com.lnmcode.galleryapp.presentation.ui.detail + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.view.ViewCompat +import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController +import androidx.navigation.fragment.navArgs +import androidx.transition.Transition +import androidx.transition.TransitionInflater +import com.google.android.material.bottomsheet.BottomSheetBehavior +import com.lnmcode.galleryapp.R +import com.lnmcode.galleryapp.bindables.BindingFragment +import com.lnmcode.galleryapp.databinding.FragmentDetailBinding +import kotlinx.coroutines.delay +import timber.log.Timber + +class DetailFragment : BindingFragment(R.layout.fragment_detail), + DetailBottomSheet { + + private val viewModel: DetailViewModel by viewModels() + private lateinit var bottomSheetBehavior: BottomSheetBehavior + private val args by navArgs() + private val topicPhoto by lazy { args.topicPhoto } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setAnimationSharedElement() + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + super.onCreateView(inflater, container, savedInstanceState) + return binding { + vm = viewModel + }.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + viewModel.setTopicPhotoArgs(topicPhoto) + binding { + bottomSheetBehavior = getBottomSheetBehavior(bottomSheet) + btnClose.setOnClickListener { backPopNav() } + textView2.setOnClickListener { + showAndHideBottomSheet() + } + } + } + + private fun backPopNav() { + findNavController().popBackStack() + } + + override fun getBottomSheetBehavior(bottomSheet: View): BottomSheetBehavior { + return BottomSheetBehavior.from(bottomSheet).apply { + state = BottomSheetBehavior.STATE_COLLAPSED + } + } + + override fun showAndHideBottomSheet() { + Timber.d("${bottomSheetBehavior.state}") + if (bottomSheetBehavior.state == BottomSheetBehavior.STATE_COLLAPSED) + bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED + else bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED + } + + private fun setAnimationSharedElement() { + val animation = TransitionInflater.from(requireContext()).inflateTransition( + android.R.transition.move + ) + sharedElementEnterTransition = animation + sharedElementReturnTransition = animation + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/detail/DetailViewModel.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/detail/DetailViewModel.kt new file mode 100644 index 0000000..b0b99ad --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/detail/DetailViewModel.kt @@ -0,0 +1,19 @@ +package com.lnmcode.galleryapp.presentation.ui.detail + +import androidx.databinding.Bindable +import com.lnmcode.galleryapp.bindables.BindingViewModel +import com.lnmcode.galleryapp.bindables.bindingProperty +import com.lnmcode.galleryapp.business.domain.models.topicphoto.TopicPhoto + +class DetailViewModel : BindingViewModel() { + + @get:Bindable + var topicPhoto: TopicPhoto? by bindingProperty(null) + private set + + + fun setTopicPhotoArgs(topicPhoto: TopicPhoto) { + this.topicPhoto = topicPhoto + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/gallery/GalleryAdapter.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/gallery/GalleryAdapter.kt new file mode 100644 index 0000000..a600c13 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/gallery/GalleryAdapter.kt @@ -0,0 +1,38 @@ +package com.lnmcode.galleryapp.presentation.ui.gallery + +import android.view.View +import com.lnmcode.galleryapp.R +import com.lnmcode.galleryapp.business.domain.cache.TopicsCacheDomain +import com.lnmcode.galleryapp.business.domain.models.topic.Topic +import com.lnmcode.galleryapp.business.domain.models.topicphoto.TopicPhoto +import com.lnmcode.galleryapp.presentation.adapter.BaseAdapter +import com.lnmcode.galleryapp.presentation.adapter.BaseViewHolder +import com.lnmcode.galleryapp.presentation.ui.OnChangeLayout +import com.lnmcode.galleryapp.presentation.viewholder.GalleryGridViewHolder +import com.lnmcode.galleryapp.presentation.viewholder.GalleryViewHolder +import timber.log.Timber + + +class GalleryAdapter( + private val onChangeLayout: OnChangeLayout, +) : BaseAdapter() { + fun addTopics(topicPhoto: List) { + addSubmit(topicPhoto) + } + + override fun layout() = R.layout.layout_item_gridview_gallery + + override fun viewHolder(view: View) = GalleryGridViewHolder(view, onChangeLayout) + + override fun areItemsTheSameItem(oldItem: TopicPhoto, newItem: TopicPhoto): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSameItem(oldItem: TopicPhoto, newItem: TopicPhoto): Boolean { + return oldItem == newItem + } + + init { + Timber.d("Init GalleryAdapter") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/gallery/GalleryFragment.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/gallery/GalleryFragment.kt new file mode 100644 index 0000000..faba397 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/gallery/GalleryFragment.kt @@ -0,0 +1,69 @@ +package com.lnmcode.galleryapp.presentation.ui.gallery + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.core.view.ViewCompat +import androidx.core.view.doOnPreDraw +import androidx.navigation.fragment.FragmentNavigator +import androidx.navigation.fragment.FragmentNavigatorExtras +import androidx.navigation.fragment.findNavController +import androidx.navigation.fragment.navArgs +import androidx.transition.TransitionInflater +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.StaggeredGridLayoutManager +import com.lnmcode.galleryapp.R +import com.lnmcode.galleryapp.bindables.BindingFragment +import com.lnmcode.galleryapp.business.domain.models.topicphoto.TopicPhoto +import com.lnmcode.galleryapp.databinding.FragmentGalleryBinding +import com.lnmcode.galleryapp.presentation.ui.OnChangeLayout +import com.lnmcode.galleryapp.presentation.ui.detail.DetailFragmentArgs +import org.koin.androidx.viewmodel.ext.android.viewModel +import org.koin.core.parameter.parametersOf +import timber.log.Timber + +class GalleryFragment : BindingFragment(R.layout.fragment_gallery), + OnChangeLayout { + + private val args by navArgs() + private val topicId by lazy { args.topicsId } + + private val viewModel: GalleryViewModel by viewModel { parametersOf(topicId) } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + super.onCreateView(inflater, container, savedInstanceState) + return binding { + adapterHead = GalleryHeadAdapter(this@GalleryFragment) + adapterGrid = GalleryAdapter(this@GalleryFragment) + vm = viewModel + }.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + postponeEnterTransition() + binding.root.viewTreeObserver.addOnPreDrawListener { + startPostponedEnterTransition() + true + } + } + + override fun onChangeSharedWithParameters(data: Any, viewItemShare: ImageView) { + val dataTopicPhoto = data as TopicPhoto + val actions = GalleryFragmentDirections.actionGalleryFragmentToDetailFragment(dataTopicPhoto) + val extras = FragmentNavigatorExtras(viewItemShare to "image_transition_detail") + findNavController().navigate(actions, extras) + } + + override fun onChangeWithParameters(data: Any) { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/gallery/GalleryHeadAdapter.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/gallery/GalleryHeadAdapter.kt new file mode 100644 index 0000000..6e41894 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/gallery/GalleryHeadAdapter.kt @@ -0,0 +1,34 @@ +package com.lnmcode.galleryapp.presentation.ui.gallery + +import android.view.View +import com.lnmcode.galleryapp.R +import com.lnmcode.galleryapp.business.domain.models.topicphoto.TopicPhoto +import com.lnmcode.galleryapp.presentation.adapter.BaseAdapter +import com.lnmcode.galleryapp.presentation.ui.OnChangeLayout +import com.lnmcode.galleryapp.presentation.viewholder.GalleryViewHolder +import timber.log.Timber + +class GalleryHeadAdapter( + private val onChangeLayout: OnChangeLayout, +) : BaseAdapter() { + + fun addTopics(topicPhoto: List) { + addSubmit(topicPhoto) + } + + override fun layout() = R.layout.layout_item_gallery + + override fun viewHolder(view: View) = GalleryViewHolder(view, onChangeLayout) + + override fun areItemsTheSameItem(oldItem: TopicPhoto, newItem: TopicPhoto): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSameItem(oldItem: TopicPhoto, newItem: TopicPhoto): Boolean { + return oldItem == newItem + } + + init { + Timber.d("Init GalleryHeadAdapter") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/gallery/GalleryViewModel.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/gallery/GalleryViewModel.kt new file mode 100644 index 0000000..534b939 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/ui/gallery/GalleryViewModel.kt @@ -0,0 +1,31 @@ +package com.lnmcode.galleryapp.presentation.ui.gallery + +import androidx.databinding.Bindable +import androidx.lifecycle.viewModelScope +import com.lnmcode.galleryapp.bindables.BindingViewModel +import com.lnmcode.galleryapp.bindables.asBindingProperty +import com.lnmcode.galleryapp.bindables.bindingProperty +import com.lnmcode.galleryapp.business.datasource.usecase.TopicPhotoUseCase +import com.lnmcode.galleryapp.business.domain.models.topicphoto.TopicPhoto + + +class GalleryViewModel( + private val topicsId: String, + private val topicPhotoUserCase: TopicPhotoUseCase +) : BindingViewModel() { + @get:Bindable + var isLoading: Boolean by bindingProperty(true) + private set + private val topicPhotoFlow = topicPhotoUserCase.getTopicPhoto( + topicsId = topicsId, + onSuccess = { isLoading = true } + ) + + @get:Bindable + val topicPhoto: List by topicPhotoFlow.asBindingProperty( + viewModelScope, + emptyList() + ) + + +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/utils/ResUtils.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/utils/ResUtils.kt new file mode 100644 index 0000000..a370353 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/utils/ResUtils.kt @@ -0,0 +1,40 @@ +package com.lnmcode.galleryapp.presentation.utils + +import android.content.Context +import android.view.View +import android.widget.Toast +import androidx.annotation.ColorRes +import androidx.annotation.IntDef +import androidx.annotation.StringRes +import androidx.core.content.res.ResourcesCompat +import com.google.android.material.snackbar.Snackbar +import com.lnmcode.galleryapp.R + + +object ResUtils { + + fun getResColor(context: Context, @ColorRes colorRes: Int) = + ResourcesCompat.getColor(context.resources, colorRes, null) + + fun showToast(context: Context, message: String, @ToastDuration duration: Int = Toast.LENGTH_SHORT) = + Toast.makeText(context, message, duration).show() + + fun showToast(context: Context, @StringRes messageRes: Int, @ToastDuration duration: Int = Toast.LENGTH_SHORT) = + showToast(context, context.getString(messageRes), duration) + + fun showSnackBar(view: View, @StringRes messageRes: Int, @SnackBarDuration duration: Int = Snackbar.LENGTH_SHORT) = + showSnackBar(view, view.resources.getString(messageRes), duration) + + fun showSnackBar(view: View, message: String, @SnackBarDuration duration: Int = Snackbar.LENGTH_SHORT) = + Snackbar.make(view, message, duration) + .setAnimationMode(Snackbar.ANIMATION_MODE_SLIDE) + .setTextColor(getResColor(view.context, android.R.color.white)) + .setBackgroundTint(getResColor(view.context, R.color.black)) + .show() +} + +@IntDef(Snackbar.LENGTH_SHORT, Snackbar.LENGTH_LONG, Snackbar.LENGTH_INDEFINITE) +annotation class SnackBarDuration + +@IntDef(Toast.LENGTH_SHORT, Toast.LENGTH_LONG) +annotation class ToastDuration \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/viewholder/BindingLazy.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/viewholder/BindingLazy.kt new file mode 100644 index 0000000..49d20f4 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/viewholder/BindingLazy.kt @@ -0,0 +1,10 @@ +package com.lnmcode.galleryapp.presentation.viewholder + +import androidx.databinding.DataBindingUtil +import androidx.databinding.ViewDataBinding +import com.lnmcode.galleryapp.presentation.adapter.BaseViewHolder + +inline fun BaseViewHolder.bindings(): Lazy = + lazy(LazyThreadSafetyMode.NONE) { + requireNotNull(DataBindingUtil.bind(itemView)) { "cannot find the matched view to layout." } + } diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/viewholder/BoardTopicsViewHolder.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/viewholder/BoardTopicsViewHolder.kt new file mode 100644 index 0000000..85a6abd --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/viewholder/BoardTopicsViewHolder.kt @@ -0,0 +1,43 @@ +package com.lnmcode.galleryapp.presentation.viewholder + +import android.view.View +import com.lnmcode.galleryapp.business.domain.cache.TopicsCacheDomain +import com.lnmcode.galleryapp.databinding.LayoutItemTopicsBoardsBinding +import com.lnmcode.galleryapp.presentation.adapter.BaseViewHolder +import com.lnmcode.galleryapp.presentation.ui.OnChangeLayout +import com.lnmcode.galleryapp.presentation.ui.boards.BoardsActionCacheEvent +import timber.log.Timber + +class BoardTopicsViewHolder( + view: View, + private val boardsActionCacheEvent: BoardsActionCacheEvent, +) : BaseViewHolder(view) { + private lateinit var data: TopicsCacheDomain + private val binding: LayoutItemTopicsBoardsBinding by bindings() + + override fun bindData(data: Any) { + if (data is TopicsCacheDomain) { + this.data = data + setUpLayout() + } + } + + private fun setUpLayout() { + binding.apply { + topics = data + imgIconRemove.setOnClickListener { + val topicsData = TopicsCacheDomain( + id = data.id, + slug = data.slug, + title = data.title, + description = data.description + ) + boardsActionCacheEvent.deleteTopicsCache(topicsData) + } + } + } + + override fun onClick(v: View?) { + Timber.d("BoardTopicsViewHolder clicked: ${data.title}") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/viewholder/BoardViewHolder.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/viewholder/BoardViewHolder.kt new file mode 100644 index 0000000..b1792d7 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/viewholder/BoardViewHolder.kt @@ -0,0 +1,46 @@ +package com.lnmcode.galleryapp.presentation.viewholder + +import android.view.View +import com.lnmcode.galleryapp.business.domain.cache.TopicsCacheDomain +import com.lnmcode.galleryapp.business.domain.models.topics.Topics +import com.lnmcode.galleryapp.databinding.LayoutItemBoardsBinding +import com.lnmcode.galleryapp.presentation.adapter.BaseViewHolder +import com.lnmcode.galleryapp.presentation.ui.OnChangeLayout +import com.lnmcode.galleryapp.presentation.ui.boards.BoardsActionCacheEvent +import timber.log.Timber + +class BoardViewHolder( + view: View, + private val onChangeLayout: OnChangeLayout, + private val boardsActionCacheEvent: BoardsActionCacheEvent, +) : BaseViewHolder(view) { + + private lateinit var data: Topics + private val binding: LayoutItemBoardsBinding by bindings() + + override fun bindData(data: Any) { + if (data is Topics) { + this.data = data + setUpLayout() + } + } + private fun setUpLayout() { + binding.apply { + topic = data + imgIconCard.setOnClickListener { + val topicsData = TopicsCacheDomain( + id = data.id, + slug = data.slug, + title = data.title, + description = data.description + ) + boardsActionCacheEvent.insertTopicsCache(topicsData) + } + } + } + + override fun onClick(v: View?) { + Timber.d("BoardViewItem clicked ${data.title}") + onChangeLayout.onChangeWithParameters(data.id) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/viewholder/GalleryGridViewHolder.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/viewholder/GalleryGridViewHolder.kt new file mode 100644 index 0000000..cee3fd0 --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/viewholder/GalleryGridViewHolder.kt @@ -0,0 +1,36 @@ +package com.lnmcode.galleryapp.presentation.viewholder + +import android.view.View +import androidx.core.view.ViewCompat +import com.lnmcode.galleryapp.business.domain.models.topicphoto.TopicPhoto +import com.lnmcode.galleryapp.databinding.LayoutItemGridviewGalleryBinding +import com.lnmcode.galleryapp.presentation.adapter.BaseViewHolder +import com.lnmcode.galleryapp.presentation.ui.OnChangeLayout +import timber.log.Timber + +class GalleryGridViewHolder( + view: View, + private val onChangeLayout: OnChangeLayout, +) : BaseViewHolder(view) { + + private lateinit var data: TopicPhoto + private val binding: LayoutItemGridviewGalleryBinding by bindings() + + override fun bindData(data: Any) { + if (data is TopicPhoto) { + this.data = data + setUpLayout() + } + } + + private fun setUpLayout() { + binding.apply { + topicPhoto = data + } + } + + override fun onClick(v: View?) { + Timber.d("GalleryGridViewHolder clicked item ${data.id}") + onChangeLayout.onChangeSharedWithParameters(data, binding.image) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lnmcode/galleryapp/presentation/viewholder/GalleryViewHolder.kt b/app/src/main/java/com/lnmcode/galleryapp/presentation/viewholder/GalleryViewHolder.kt new file mode 100644 index 0000000..aeccc4c --- /dev/null +++ b/app/src/main/java/com/lnmcode/galleryapp/presentation/viewholder/GalleryViewHolder.kt @@ -0,0 +1,35 @@ +package com.lnmcode.galleryapp.presentation.viewholder + +import android.view.View +import com.lnmcode.galleryapp.business.domain.models.topicphoto.TopicPhoto +import com.lnmcode.galleryapp.databinding.LayoutItemGalleryBinding +import com.lnmcode.galleryapp.presentation.adapter.BaseViewHolder +import com.lnmcode.galleryapp.presentation.ui.OnChangeLayout +import timber.log.Timber + +class GalleryViewHolder( + view: View, + private val onChangeLayout: OnChangeLayout, +) : BaseViewHolder(view) { + + private lateinit var data: TopicPhoto + private val binding: LayoutItemGalleryBinding by bindings() + override fun bindData(data: Any) { + if (data is TopicPhoto) { + this.data = data + setUpLayout() + } + } + + private fun setUpLayout() { + binding.apply { + topicPhoto = data + } + } + + override fun onClick(v: View?) { + Timber.d("GalleryViewHolder clicked item ${data.id}") + onChangeLayout.onChangeSharedWithParameters(data, binding.imgItemTopGallery) + } + +} \ No newline at end of file diff --git a/app/src/main/res/anim/slide_from_left.xml b/app/src/main/res/anim/slide_from_left.xml new file mode 100644 index 0000000..ada4f1a --- /dev/null +++ b/app/src/main/res/anim/slide_from_left.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/slide_from_right.xml b/app/src/main/res/anim/slide_from_right.xml new file mode 100644 index 0000000..2470170 --- /dev/null +++ b/app/src/main/res/anim/slide_from_right.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/slide_to_left.xml b/app/src/main/res/anim/slide_to_left.xml new file mode 100644 index 0000000..64d6829 --- /dev/null +++ b/app/src/main/res/anim/slide_to_left.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/slide_to_right.xml b/app/src/main/res/anim/slide_to_right.xml new file mode 100644 index 0000000..a73c633 --- /dev/null +++ b/app/src/main/res/anim/slide_to_right.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_linear_gradient.xml b/app/src/main/res/drawable/bg_linear_gradient.xml new file mode 100644 index 0000000..e367581 --- /dev/null +++ b/app/src/main/res/drawable/bg_linear_gradient.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_radius_corner_white.xml b/app/src/main/res/drawable/bg_radius_corner_white.xml new file mode 100644 index 0000000..01378a6 --- /dev/null +++ b/app/src/main/res/drawable/bg_radius_corner_white.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/boder_image_itemgallery.xml b/app/src/main/res/drawable/boder_image_itemgallery.xml new file mode 100644 index 0000000..344bd84 --- /dev/null +++ b/app/src/main/res/drawable/boder_image_itemgallery.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add.xml b/app/src/main/res/drawable/ic_add.xml new file mode 100644 index 0000000..b88b155 --- /dev/null +++ b/app/src/main/res/drawable/ic_add.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_arrow_back.png b/app/src/main/res/drawable/ic_arrow_back.png new file mode 100644 index 0000000..de3bc34 Binary files /dev/null and b/app/src/main/res/drawable/ic_arrow_back.png differ diff --git a/app/src/main/res/drawable/ic_baseline_arrow_back_ios_24.xml b/app/src/main/res/drawable/ic_baseline_arrow_back_ios_24.xml new file mode 100644 index 0000000..1909c56 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_arrow_back_ios_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_close.xml b/app/src/main/res/drawable/ic_close.xml new file mode 100644 index 0000000..70db409 --- /dev/null +++ b/app/src/main/res/drawable/ic_close.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_pen_detail.xml b/app/src/main/res/drawable/ic_pen_detail.xml new file mode 100644 index 0000000..6d52da0 --- /dev/null +++ b/app/src/main/res/drawable/ic_pen_detail.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/font-v26/font_tt_norms.xml b/app/src/main/res/font-v26/font_tt_norms.xml new file mode 100644 index 0000000..70f4549 --- /dev/null +++ b/app/src/main/res/font-v26/font_tt_norms.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/font/europa_regular.ttf b/app/src/main/res/font/europa_regular.ttf new file mode 100644 index 0000000..1d479fd Binary files /dev/null and b/app/src/main/res/font/europa_regular.ttf differ diff --git a/app/src/main/res/font/font_europa_regular.xml b/app/src/main/res/font/font_europa_regular.xml new file mode 100644 index 0000000..f58c949 --- /dev/null +++ b/app/src/main/res/font/font_europa_regular.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/font/font_tt_norms.xml b/app/src/main/res/font/font_tt_norms.xml new file mode 100644 index 0000000..70f4549 --- /dev/null +++ b/app/src/main/res/font/font_tt_norms.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/font/tt_norms_medium.otf b/app/src/main/res/font/tt_norms_medium.otf new file mode 100644 index 0000000..54f5c4c Binary files /dev/null and b/app/src/main/res/font/tt_norms_medium.otf differ diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 7a9080d..9c36099 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,18 +1,44 @@ - + xmlns:tools="http://schemas.android.com/tools"> - + - \ No newline at end of file + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_boards.xml b/app/src/main/res/layout/fragment_boards.xml new file mode 100644 index 0000000..bed3117 --- /dev/null +++ b/app/src/main/res/layout/fragment_boards.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_detail.xml b/app/src/main/res/layout/fragment_detail.xml new file mode 100644 index 0000000..893531e --- /dev/null +++ b/app/src/main/res/layout/fragment_detail.xml @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_gallery.xml b/app/src/main/res/layout/fragment_gallery.xml new file mode 100644 index 0000000..cfd3100 --- /dev/null +++ b/app/src/main/res/layout/fragment_gallery.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_bottom_sheet_detail.xml b/app/src/main/res/layout/layout_bottom_sheet_detail.xml new file mode 100644 index 0000000..cae19f1 --- /dev/null +++ b/app/src/main/res/layout/layout_bottom_sheet_detail.xml @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_item_boards.xml b/app/src/main/res/layout/layout_item_boards.xml new file mode 100644 index 0000000..6be06ac --- /dev/null +++ b/app/src/main/res/layout/layout_item_boards.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_item_gallery.xml b/app/src/main/res/layout/layout_item_gallery.xml new file mode 100644 index 0000000..d6030f7 --- /dev/null +++ b/app/src/main/res/layout/layout_item_gallery.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_item_gridview_gallery.xml b/app/src/main/res/layout/layout_item_gridview_gallery.xml new file mode 100644 index 0000000..96f98d2 --- /dev/null +++ b/app/src/main/res/layout/layout_item_gridview_gallery.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_item_topics_boards.xml b/app/src/main/res/layout/layout_item_topics_boards.xml new file mode 100644 index 0000000..e47ad5f --- /dev/null +++ b/app/src/main/res/layout/layout_item_topics_boards.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_main.xml b/app/src/main/res/navigation/nav_main.xml new file mode 100644 index 0000000..fdab28c --- /dev/null +++ b/app/src/main/res/navigation/nav_main.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index f8c6127..3d891cc 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,5 +1,6 @@ + #F0F4F4 #FFBB86FC #FF6200EE #FF3700B3 @@ -7,4 +8,8 @@ #FF018786 #FF000000 #FFFFFFFF + #F0F4F4 + #FC5C4C + #FD814A + #E2E2E2 \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..bc4d2b9 --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,25 @@ + + + 12dp + 8dp + 2dp + 260dp + 25dp + 10dp + 15dp + 34sp + 20dp + 34sp + 1dp + 10dp + 4dp + 15dp + 10dp + 8dp + 12dp + 15dp + 15sp + 17sp + 6dp + 20sp + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0750463..0a86077 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,18 @@ GalleryApp + GalleryApp.db + Boards + Following galleries to power up your art care + Artist + Size + Location + Location + Overview + It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using Content here, content here, making it look like readable English. + %1$s x %2$s + No have any description + Gallery + Curated Galleries + %1$s_grid + %1$s_top \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index d71f818..2e8196a 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/preview/preview01.gif b/preview/preview01.gif new file mode 100644 index 0000000..6c8b1ab Binary files /dev/null and b/preview/preview01.gif differ diff --git a/preview/preview02.gif b/preview/preview02.gif new file mode 100644 index 0000000..16302de Binary files /dev/null and b/preview/preview02.gif differ diff --git a/preview/preview03.gif b/preview/preview03.gif new file mode 100644 index 0000000..5b586ad Binary files /dev/null and b/preview/preview03.gif differ