Skip to content

Commit

Permalink
Release 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
wrozwad committed Sep 30, 2018
2 parents 66afe3e + b44963d commit afec082
Show file tree
Hide file tree
Showing 185 changed files with 5,714 additions and 9 deletions.
8 changes: 1 addition & 7 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,7 @@ captures/

# IntelliJ
*.iml
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
.idea/assetWizardSettings.xml
.idea/dictionaries
.idea/libraries
.idea/caches
.idea/

# Keystore files
# Uncomment the following line if you do not want to check your keystore files in.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Gitez
# <img width="150" alt="Gitez" src="https://user-images.githubusercontent.com/2025949/45154336-88711f00-b1d7-11e8-97c1-b5a6d17e0fb8.png">
Test app written for recruitment process. Copy, paste, share and smile! :)

## Project assumptions

* Create simple Android application that uses [GitHub API](https://developer.github.com/v3/)

I decided to use [GitHub GraphQL API V4](https://developer.github.com/v4/) for fun part :)
Unfortunately [anonymous apps can't use GitHub GraphQL API V4](https://platform.github.community/t/permit-access-without-oauth-token/2572) so far. So we're stick with REST API V3.

* Application should allow to search for users and repositories
* Main screen of the app should contain search field and list of search results
Expand Down
1 change: 1 addition & 0 deletions androidcore/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
42 changes: 42 additions & 0 deletions androidcore/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

dependencies {
def rootExt = rootProject.ext
def componentDependencies = rootExt.coreComponent
def unitTestDependencies = rootExt.unitTesting
def acceptanceTestDependencies = rootExt.acceptanceTesting

// Base
implementation project(':tim')
implementation project(':util')

// Android
implementation componentDependencies.appCompat
implementation componentDependencies.coreKtx
implementation componentDependencies.collectionKtx
implementation componentDependencies.lifecycle
kapt componentDependencies.lifecycleProcessor
implementation componentDependencies.material

// Reactive
implementation componentDependencies.rxJava
implementation componentDependencies.rxAndroid
implementation componentDependencies.rxKotlin
implementation componentDependencies.rxBindingKtx

// Other
implementation componentDependencies.dagger
implementation componentDependencies.daggerAndroid
kapt componentDependencies.daggerProcessor

// Unit/Integration tests
testImplementation unitTestDependencies.kotlin
testImplementation unitTestDependencies.kotlinTest
testImplementation unitTestDependencies.junit

// Acceptance tests
androidTestImplementation acceptanceTestDependencies.testRunner
}
1 change: 1 addition & 0 deletions androidcore/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<manifest package="com.socros.android.app.base" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.socros.android.lib.androidcore

import com.socros.android.lib.androidcore.di.AppComponent
import com.socros.android.lib.androidcore.di.DaggerAppComponent
import dagger.android.support.DaggerApplication

abstract class ACApp : DaggerApplication() {

private lateinit var appComponent: AppComponent

override fun applicationInjector() = appComponent
internal fun provideAppModuleSubComponent() = appComponent.appModuleSubComponentBuilder.build()

override fun onCreate() {
appComponent = DaggerAppComponent.builder().create(this) as AppComponent
super.onCreate()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.socros.android.lib.androidcore.di

import javax.inject.Qualifier

@Qualifier
annotation class ActivityContext
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.socros.android.lib.androidcore.di

import javax.inject.Scope

/**
* In Dagger, an unscoped component cannot depend on a scoped component. As
* {@link AppComponent} is a scoped component ({@code @Singleton}, we create a custom
* scope to be used by all fragment components. Additionally, a component with a specific scope
* cannot have a sub component with the same scope.
*
* @see <a href="https://github.com/googlesamples/android-architecture-components">Android Architecture Components samples</a>
*/
@Scope
@Retention
annotation class ActivityScope
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.socros.android.lib.androidcore.di

import com.socros.android.lib.androidcore.ACApp
import dagger.Component
import dagger.android.AndroidInjector
import dagger.android.support.AndroidSupportInjectionModule
import javax.inject.Singleton

@Singleton
@Component(modules = [AppModule::class, AndroidSupportInjectionModule::class])
interface AppComponent : AndroidInjector<ACApp> {

val appModuleSubComponentBuilder: AppModuleSubComponent.Builder

@Component.Builder
abstract class Builder : AndroidInjector.Builder<ACApp>() {
abstract override fun build(): AppComponent
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.socros.android.lib.androidcore.di

import javax.inject.Qualifier

@Qualifier
annotation class AppContext
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.socros.android.lib.androidcore.di

import android.app.Application
import android.content.Context
import dagger.Binds
import dagger.Module

/**
* This is a Dagger module. We use this to bind our Application class as a Context in the AppComponent
* By using Dagger Android we do not need to pass our Application instance to any module,
* we simply need to expose our Application as Context.
* One of the advantages of Dagger.Android is that your
* Application & Activities are provided into your graph for you.
* [AppComponent].
*
* @see <a href="https://github.com/googlesamples/android-architecture-components">Android Architecture Components samples</a>
*/
@Module
abstract class AppModule {
@AppContext
@Binds
abstract fun bindContext(application: Application): Context
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.socros.android.lib.androidcore.di

import android.app.Application
import dagger.BindsInstance
import dagger.android.AndroidInjector

/**
* @see <a href="https://medium.com/@luigi.papino/dagger2-for-modular-architecture-332e1250a85f">Dagger2 for Modular Architecture</a>
*/
interface AppModuleInjector<T : AppProvider> : AndroidInjector<T> {

abstract class Builder<T : AppProvider> : AndroidInjector.Builder<T>() {

@BindsInstance
abstract operator fun plus(application: Application): Builder<T>

abstract operator fun plus(component: AppModuleSubComponent): Builder<T>

fun inject(objectToInject: T) {
objectToInject.provideApp().also {
plus(it)
plus(it.provideAppModuleSubComponent())
}

create(objectToInject).inject(objectToInject)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.socros.android.lib.androidcore.di

import dagger.Subcomponent

/**
* Created by luigipapino on 18/02/2018, previously named BaseSubComponent
*/
@Subcomponent
interface AppModuleSubComponent {
@Subcomponent.Builder
interface Builder {
fun build(): AppModuleSubComponent
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.socros.android.lib.androidcore.di

import com.socros.android.lib.androidcore.ACApp

interface AppProvider {
fun provideApp(): ACApp
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.socros.android.lib.androidcore.di

import javax.inject.Scope

/**
* @see <a href="https://github.com/googlesamples/android-architecture-components">Android Architecture Components samples</a>
*/
@Scope
@Retention
annotation class FragmentScope
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Copyright (C) 2018 Fernando Cejas Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.socros.android.lib.androidcore.di.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import javax.inject.Inject
import javax.inject.Provider

@Suppress("UNCHECKED_CAST")
class ViewModelFactory
@Inject constructor(private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>)
: ViewModelProvider.Factory {

override fun <T : ViewModel> create(modelClass: Class<T>): T {
val creator = creators[modelClass]
?: creators.asIterable().firstOrNull { modelClass.isAssignableFrom(it.key) }?.value
?: throw IllegalArgumentException("Unknown ViewModel class $modelClass")

return try {
creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.socros.android.lib.androidcore.di.viewmodel

import androidx.lifecycle.ViewModel
import dagger.MapKey
import kotlin.annotation.AnnotationTarget.FUNCTION
import kotlin.reflect.KClass

@MapKey
@Target(FUNCTION)
annotation class ViewModelKey(val value: KClass<out ViewModel>)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.socros.android.lib.androidcore.di.viewmodel

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProviders

inline fun <reified VM : ViewModel> ViewModelFactory.create(target: FragmentActivity) =
ViewModelProviders.of(target, this)[VM::class.java]

inline fun <reified VM : ViewModel> ViewModelFactory.create(target: Fragment) =
ViewModelProviders.of(target, this)[VM::class.java]
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.socros.android.lib.androidcore.view

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.socros.android.lib.androidcore.ACApp
import com.socros.android.lib.androidcore.di.AppProvider

abstract class ACActivity : AppCompatActivity(), AppProvider {

/**
* You can pass a `null` value if your activity doesn't need to draw itself,
* eg. when you set activity theme to `"@android:style/Theme.NoDisplay"` in manifest
*/
protected abstract val layoutResId: Int?

final override fun provideApp() = application as ACApp

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
layoutResId?.let {
setContentView(it)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.socros.android.lib.androidcore.view

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.socros.android.lib.androidcore.ACApp
import com.socros.android.lib.androidcore.di.AppProvider

abstract class ACFragment : Fragment(), AppProvider {

/**
* You can pass a `null` value if your fragment doesn't need to draw itself
*/
protected abstract val layoutResId: Int?

final override fun provideApp() = activity?.application as ACApp

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return layoutResId?.let {
inflater.inflate(it, container, false)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.socros.android.lib.androidcore.view

import android.view.View
import kotlinx.android.extensions.LayoutContainer

open class LayoutContainer(override val containerView: View) : LayoutContainer
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.socros.android.lib.androidcore.view.launcher

import android.app.Activity
import android.os.Bundle

/**
* Fist app activity that decide which activity should be run as first depends on user logged in status.
*
* Use with `android:theme="@android:style/Theme.NoDisplay"`
*/
abstract class ACLauncherActivity : Activity(), Launcher {

override fun onCreate(savedInstanceState: Bundle?) {
startActivity(provideNextActivity())
finish()
super.onCreate(savedInstanceState)
}

}
Loading

0 comments on commit afec082

Please sign in to comment.