diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ec48877
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,56 @@
+# Built application files
+*.apk
+*.ap_
+
+# Files for the ART/Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+
+# Gradle files
+/.idea
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# Intellij
+*.iml
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/gradle.xml
+.idea/dictionaries
+.idea/libraries
+
+# Keystore files
+*.jks
+
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
+
+# Google Services (e.g. APIs or Firebase)
+google-services.json
+
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
diff --git a/androidveil/.gitignore b/androidveil/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/androidveil/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/androidveil/build.gradle b/androidveil/build.gradle
new file mode 100644
index 0000000..2434fb7
--- /dev/null
+++ b/androidveil/build.gradle
@@ -0,0 +1,38 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+apply plugin: 'com.novoda.bintray-release'
+
+android {
+ compileSdkVersion 28
+
+ defaultConfig {
+ minSdkVersion 15
+ targetSdkVersion 28
+ versionCode 1
+ versionName "1.0"
+ }
+}
+
+publish {
+ userOrg = 'devmagician'
+ groupId = 'com.github.skydoves'
+ artifactId = 'androidveil'
+ publishVersion = '1.0.1'
+ desc = 'This is AndroidVeil by skydoves'
+ website = 'https://github.com/skydoves/AndroidVeil'
+ issueTracker = "${website}/issues"
+ repository = "${website}.git"
+}
+
+dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation "com.android.support:appcompat-v7:$support_version"
+ implementation "com.android.support:recyclerview-v7:$support_version"
+ implementation "com.github.skydoves:baserecyclerviewadapter:$adapter_version"
+ api "com.facebook.shimmer:shimmer:$shimmer_version"
+}
+
+tasks.withType(Javadoc) {
+ excludes = ['**/*.kt']
+ options.addBooleanOption('Xdoclint:none', true)
+}
diff --git a/androidveil/proguard-rules.pro b/androidveil/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/androidveil/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/androidveil/src/main/AndroidManifest.xml b/androidveil/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..f3a44d9
--- /dev/null
+++ b/androidveil/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
diff --git a/androidveil/src/main/java/com/skydoves/androidveil/VeilLayout.kt b/androidveil/src/main/java/com/skydoves/androidveil/VeilLayout.kt
new file mode 100644
index 0000000..5a8c8bd
--- /dev/null
+++ b/androidveil/src/main/java/com/skydoves/androidveil/VeilLayout.kt
@@ -0,0 +1,234 @@
+
+/*
+ * Copyright (C) 2018 skydoves
+ *
+ * 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.skydoves.androidveil
+
+import android.annotation.TargetApi
+import android.content.Context
+import android.graphics.Color
+import android.os.Build
+import android.support.annotation.ColorInt
+import android.support.annotation.LayoutRes
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewTreeObserver
+import android.widget.FrameLayout
+import com.facebook.shimmer.Shimmer
+import com.facebook.shimmer.ShimmerFrameLayout
+import java.util.*
+class VeilLayout : FrameLayout {
+
+ @ColorInt var baseColor = Color.LTGRAY
+ @ColorInt var highlightColor = Color.DKGRAY
+ var baseAlpha = 1.0f
+ var highlightAlpha = 1.0f
+ var dropOff = 0.5f
+
+ @LayoutRes var layout = -1
+ set(value) {
+ field = value
+ reDrawLayout(value)
+ }
+
+ var isVeiled = false
+ private set
+
+ private val maskElements = ArrayList()
+ val shimmerContainer = ShimmerFrameLayout(context)
+ val nonShimmer = Shimmer.AlphaHighlightBuilder().setBaseAlpha(1.0f).setDropoff(1.0f).build()
+ var shimmer = Shimmer.AlphaHighlightBuilder().build()
+ set(value) {
+ field = value
+ shimmerContainer.setShimmer(value)
+ }
+ var shimmerEnable: Boolean = true
+ set(value) {
+ field = value
+ when(value) {
+ true -> shimmerContainer.setShimmer(shimmer)
+ false -> shimmerContainer.setShimmer(nonShimmer)
+ }
+ }
+
+ constructor(context: Context) : super(context) {
+ onCreate()
+ }
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+ getAttrs(attrs)
+ onCreate()
+ }
+
+ constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
+ getAttrs(attrs)
+ onCreate()
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
+ getAttrs(attrs)
+ onCreate()
+ }
+
+ private fun getAttrs(attrs: AttributeSet?) {
+ val a = context.obtainStyledAttributes(attrs, R.styleable.VeilLayout)
+ try {
+ if (a.hasValue(R.styleable.VeilLayout_veilLayout_veiled))
+ isVeiled = a.getBoolean(R.styleable.VeilLayout_veilLayout_veiled, isVeiled)
+ if (a.hasValue(R.styleable.VeilLayout_veilLayout_layout))
+ layout = a.getResourceId(R.styleable.VeilLayout_veilLayout_layout, -1)
+ if (a.hasValue(R.styleable.VeilLayout_veilLayout_shimmerEnable))
+ shimmerEnable = a.getBoolean(R.styleable.VeilLayout_veilLayout_shimmerEnable, shimmerEnable)
+ if (a.hasValue(R.styleable.VeilLayout_veilLayout_baseColor))
+ baseColor = a.getColor(R.styleable.VeilLayout_veilLayout_baseColor, baseColor)
+ if (a.hasValue(R.styleable.VeilLayout_veilLayout_highlightColor))
+ highlightColor = a.getColor(R.styleable.VeilLayout_veilLayout_highlightColor, highlightColor)
+ if (a.hasValue(R.styleable.VeilLayout_veilLayout_baseAlpha))
+ baseAlpha = a.getFloat(R.styleable.VeilLayout_veilLayout_baseAlpha, baseAlpha)
+ if (a.hasValue(R.styleable.VeilLayout_veilLayout_highlightAlpha))
+ highlightAlpha = a.getFloat(R.styleable.VeilLayout_veilLayout_highlightAlpha, highlightAlpha)
+ if (a.hasValue(R.styleable.VeilLayout_veilLayout_dropOff))
+ dropOff = a.getFloat(R.styleable.VeilLayout_veilLayout_dropOff, dropOff)
+ } finally {
+ a.recycle()
+ }
+ }
+
+ private fun onCreate() {
+ shimmerContainer.invisible()
+ val shimmerBuilder = Shimmer.ColorHighlightBuilder()
+ shimmerBuilder.setBaseColor(baseColor).setHighlightColor(highlightColor)
+ shimmerBuilder.setBaseAlpha(baseAlpha).setDropoff(highlightAlpha).setDropoff(dropOff)
+ shimmerBuilder.setAutoStart(false)
+ shimmer = shimmerBuilder.build()
+ shimmerEnable = shimmerEnable
+ }
+
+ /** Remove previous views and inflate a new layout. */
+ private fun reDrawLayout(layout: Int) {
+ removeAllViews()
+ LayoutInflater.from(context).inflate(layout, this, true)
+ onFinishInflate()
+ }
+
+ /** Call addMaskElements method after inflating. */
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ removeView(shimmerContainer)
+ addView(shimmerContainer)
+ addMaskElements(this)
+ }
+
+ /**
+ * Called when addMaskElements is called.
+ * Adds masked views by viewTree structure except for ViewGroup.
+ */
+ private fun addMaskElements(parent: ViewGroup) {
+ for (i in 0 until parent.childCount) {
+ val child = parent.getChildAt(i)
+ child.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
+ @Suppress("DEPRECATION")
+ override fun onGlobalLayout() {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
+ viewTreeObserver.removeGlobalOnLayoutListener(this)
+ } else {
+ viewTreeObserver.removeOnGlobalLayoutListener(this)
+ }
+
+ if (child is ViewGroup) {
+ addMaskElements(child)
+ } else {
+ var marginX = 0f
+ var marginY = 0f
+ var parentUpper = parent.parent
+ while((parentUpper !is VeilLayout)) {
+ if(parentUpper is ViewGroup) {
+ val params = parentUpper.layoutParams
+ if(params is MarginLayoutParams) {
+ marginX += parentUpper.x
+ marginY += parentUpper.y
+ }
+ parentUpper = parentUpper.parent
+ } else {
+ break
+ }
+ }
+
+ // create a masked view
+ val view = View(context)
+ view.layoutParams = FrameLayout.LayoutParams(child.measuredWidth, child.measuredHeight)
+ view.x = marginX + parent.x + child.x
+ view.y = marginY + parent.y + child.y
+ view.setBackgroundColor(baseColor)
+ maskElements.add(view)
+ shimmerContainer.addView(view)
+ }
+ }
+ })
+ }
+
+ // Invalidate the whole masked view.
+ invalidate()
+
+ // Auto veiled
+ isVeiled = !isVeiled
+ when(isVeiled) {
+ true -> unVeil()
+ false -> veil()
+ }
+ }
+
+ /** Make appear the mask. */
+ fun veil() {
+ if (!isVeiled) {
+ isVeiled = true
+ startShimmer()
+ invalidate()
+ }
+ }
+
+ /** Make disappear the mask. */
+ fun unVeil() {
+ if (isVeiled) {
+ isVeiled = false
+ stopShimmer()
+ invalidate()
+ }
+ }
+
+ /** Starts the shimmer animation. */
+ fun startShimmer() {
+ shimmerContainer.visible()
+ if(shimmerEnable) {
+ shimmerContainer.startShimmer()
+ }
+ }
+
+ /** Stops the shimmer animation. */
+ fun stopShimmer() {
+ shimmerContainer.invisible()
+ shimmerContainer.stopShimmer()
+ }
+
+ /** Invalidate VeilLayout & Shimmer */
+ override fun invalidate() {
+ super.invalidate()
+ shimmerContainer.invalidate()
+ }
+}
diff --git a/androidveil/src/main/java/com/skydoves/androidveil/VeilParams.kt b/androidveil/src/main/java/com/skydoves/androidveil/VeilParams.kt
new file mode 100644
index 0000000..42bfdf8
--- /dev/null
+++ b/androidveil/src/main/java/com/skydoves/androidveil/VeilParams.kt
@@ -0,0 +1,29 @@
+
+/*
+ * Copyright (C) 2018 skydoves
+ *
+ * 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.skydoves.androidveil
+
+import android.support.annotation.ColorInt
+import com.facebook.shimmer.Shimmer
+
+data class VeilParams(@ColorInt var baseColor: Int,
+ @ColorInt var highlightColor: Int,
+ var baseAlpha: Float,
+ var highlightAlpha: Float,
+ var dropOff: Float,
+ var shimmerEnable: Boolean,
+ var shimmer: Shimmer?)
diff --git a/androidveil/src/main/java/com/skydoves/androidveil/VeilRecyclerFrameView.kt b/androidveil/src/main/java/com/skydoves/androidveil/VeilRecyclerFrameView.kt
new file mode 100644
index 0000000..c0f992d
--- /dev/null
+++ b/androidveil/src/main/java/com/skydoves/androidveil/VeilRecyclerFrameView.kt
@@ -0,0 +1,201 @@
+
+/*
+ * Copyright (C) 2018 skydoves
+ *
+ * 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.skydoves.androidveil
+
+import android.content.Context
+import android.graphics.Color
+import android.support.annotation.ColorInt
+import android.support.annotation.LayoutRes
+import android.support.v7.widget.GridLayoutManager
+import android.support.v7.widget.LinearLayoutManager
+import android.support.v7.widget.RecyclerView
+import android.support.v7.widget.StaggeredGridLayoutManager
+import android.util.AttributeSet
+import android.widget.RelativeLayout
+import com.facebook.shimmer.Shimmer
+import com.skydoves.baserecyclerviewadapter.RecyclerViewPaginator
+
+@Suppress( "unused", "MemberVisibilityCanBePrivate")
+class VeilRecyclerFrameView : RelativeLayout {
+
+ private val userRecyclerView: RecyclerView = RecyclerView(context)
+
+ private val veiledRecyclerView: RecyclerView = RecyclerView(context)
+ private var veiledAdapter: VeiledAdapter? = null
+
+ private var isVeiled = false
+
+ @ColorInt private var baseColor = Color.LTGRAY
+ @ColorInt private var highlightColor = Color.DKGRAY
+ private var baseAlpha = 1.0f
+ private var highlightAlpha = 1.0f
+ private var dropOff = 0.5f
+ @LayoutRes private var layout = -1
+
+ var shimmer: Shimmer? = null
+ var shimmerEnable: Boolean = true
+ private val threshold = 10
+
+ constructor(context: Context) : super(context) {
+ onCreate()
+ }
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
+ getAttrs(attrs)
+ onCreate()
+ }
+
+ constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(context, attrs, defStyle) {
+ getAttrs(attrs)
+ onCreate()
+ }
+
+ private fun getAttrs(attrs: AttributeSet?) {
+ val a = context.obtainStyledAttributes(attrs, R.styleable.VeilRecyclerFrameView)
+ try {
+ if (a.hasValue(R.styleable.VeilRecyclerFrameView_veilFrame_veiled))
+ isVeiled = a.getBoolean(R.styleable.VeilRecyclerFrameView_veilFrame_veiled, isVeiled)
+ if (a.hasValue(R.styleable.VeilRecyclerFrameView_veilFrame_layout))
+ layout = a.getResourceId(R.styleable.VeilRecyclerFrameView_veilFrame_layout, -1)
+ if (a.hasValue(R.styleable.VeilRecyclerFrameView_veilFrame_shimmerEnable))
+ shimmerEnable = a.getBoolean(R.styleable.VeilRecyclerFrameView_veilFrame_shimmerEnable, shimmerEnable)
+ if (a.hasValue(R.styleable.VeilRecyclerFrameView_veilFrame_baseColor))
+ baseColor = a.getColor(R.styleable.VeilRecyclerFrameView_veilFrame_baseColor, baseColor)
+ if (a.hasValue(R.styleable.VeilRecyclerFrameView_veilFrame_highlightColor))
+ highlightColor = a.getColor(R.styleable.VeilRecyclerFrameView_veilFrame_highlightColor, highlightColor)
+ if (a.hasValue(R.styleable.VeilRecyclerFrameView_veilFrame_baseAlpha))
+ baseAlpha = a.getFloat(R.styleable.VeilRecyclerFrameView_veilFrame_baseAlpha, baseAlpha)
+ if (a.hasValue(R.styleable.VeilRecyclerFrameView_veilFrame_highlightAlpha))
+ highlightAlpha = a.getFloat(R.styleable.VeilRecyclerFrameView_veilFrame_highlightAlpha, highlightAlpha)
+ if (a.hasValue(R.styleable.VeilRecyclerFrameView_veilFrame_dropOff))
+ dropOff = a.getFloat(R.styleable.VeilRecyclerFrameView_veilFrame_dropOff, dropOff)
+ } finally {
+ a.recycle()
+ }
+ }
+
+ private fun onCreate() {
+ val paginator = RecyclerViewPaginator(
+ recyclerView = veiledRecyclerView,
+ onLast = { false },
+ loadMore = { veiledRecyclerView.post { veiledAdapter?.update(it, threshold) } },
+ isLoading = { false }
+ )
+ paginator.threshold = threshold
+ addView(userRecyclerView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
+ addView(veiledRecyclerView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
+ when(isVeiled) {
+ true -> visibleVeilRecyclerView()
+ false -> visibleUserRecyclerView()
+ }
+
+ if(layout != -1)
+ setVeilLayout(layout)
+ }
+
+ /** Sets mask layout. */
+ fun setVeilLayout(layout: Int) {
+ veiledAdapter = VeiledAdapter(layout)
+ veiledRecyclerView.adapter = veiledAdapter
+ }
+
+ /** Sets mask layout and VeiledItemOnClickListener. */
+ fun setVeilLayout(layout: Int, onItemClickListener: VeiledItemOnClickListener) {
+ veiledAdapter = VeiledAdapter(layout, onItemClickListener)
+ veiledRecyclerView.adapter = veiledAdapter
+ }
+
+ /** Sets mask layout and adds masked items. */
+ fun setVeilLayout(layout: Int, size: Int) {
+ this.setVeilLayout(layout)
+ this.addVeiledItems(size)
+ }
+
+ /** Sets mask layout and VeiledItemOnClickListener and adds masked items. */
+ fun setVeilLayout(layout: Int, onItemClickListener: VeiledItemOnClickListener, size: Int) {
+ this.setVeilLayout(layout, onItemClickListener)
+ this.addVeiledItems(size)
+ }
+
+ /** Adds masked items. */
+ fun addVeiledItems(size: Int) {
+ val paramList = ArrayList()
+ for (i in 0 until size) {
+ paramList.add(VeilParams(baseColor, highlightColor, baseAlpha, highlightAlpha, dropOff, shimmerEnable, shimmer))
+ }
+ veiledAdapter?.addParams(paramList)
+ }
+
+ /** Sets userRecyclerView's adapter. */
+ fun setAdapter(adapter: RecyclerView.Adapter<*>?) {
+ this.userRecyclerView.adapter = adapter
+ this.invalidate()
+ }
+
+ /** Sets userRecyclerView's adapter and RecyclerViews LayoutManager. */
+ fun setAdapter(adapter: RecyclerView.Adapter<*>?, layoutManager: RecyclerView.LayoutManager) {
+ this.setAdapter(adapter)
+ this.setLayoutManager(layoutManager)
+ }
+
+ /** Sets RecyclerViews LayoutManager. */
+ fun setLayoutManager(layoutManager: RecyclerView.LayoutManager) {
+ if(layoutManager is GridLayoutManager) {
+ this.userRecyclerView.layoutManager = layoutManager
+ this.veiledRecyclerView.layoutManager = GridLayoutManager(context, layoutManager.spanCount)
+ } else if(layoutManager is StaggeredGridLayoutManager) {
+ this.userRecyclerView.layoutManager = layoutManager
+ this.veiledRecyclerView.layoutManager = StaggeredGridLayoutManager(layoutManager.spanCount, layoutManager.orientation)
+ } else if(layoutManager is LinearLayoutManager) { // This condition should be at the last.
+ this.userRecyclerView.layoutManager = layoutManager
+ this.veiledRecyclerView.layoutManager = LinearLayoutManager(context)
+ }
+ }
+
+ /** Make appear the mask. */
+ fun veil() {
+ veiledAdapter?.let {
+ if (!isVeiled) {
+ isVeiled = true
+ visibleVeilRecyclerView()
+ }
+ }
+ }
+
+ /** Make disappear the mask. */
+ fun unVeil() {
+ if (isVeiled) {
+ isVeiled = false
+ visibleUserRecyclerView()
+ }
+ }
+
+ /** Visible veiledRecyclerView and Invisible userRecyclerView. */
+ private fun visibleVeilRecyclerView() {
+ veiledRecyclerView.visible()
+ veiledRecyclerView.bringToFront()
+ userRecyclerView.invisible()
+ }
+
+ /** Invisible veiledRecyclerView and Visible userRecyclerView. */
+ private fun visibleUserRecyclerView() {
+ userRecyclerView.visible()
+ userRecyclerView.bringToFront()
+ veiledRecyclerView.invisible()
+ }
+}
diff --git a/androidveil/src/main/java/com/skydoves/androidveil/VeiledAdapter.kt b/androidveil/src/main/java/com/skydoves/androidveil/VeiledAdapter.kt
new file mode 100644
index 0000000..1e64ad9
--- /dev/null
+++ b/androidveil/src/main/java/com/skydoves/androidveil/VeiledAdapter.kt
@@ -0,0 +1,55 @@
+
+/*
+ * Copyright (C) 2018 skydoves
+ *
+ * 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.skydoves.androidveil
+
+import android.support.annotation.LayoutRes
+import android.view.View
+import com.skydoves.baserecyclerviewadapter.BaseAdapter
+import com.skydoves.baserecyclerviewadapter.BaseViewHolder
+import com.skydoves.baserecyclerviewadapter.SectionRow
+
+class VeiledAdapter(@LayoutRes private val userLayout: Int,
+ private val onItemClickListener: VeiledItemOnClickListener? = null)
+ : BaseAdapter() {
+
+ fun addParams(params : List) {
+ clearSections()
+ addSection(ArrayList())
+ addItemsOnSection(0, params)
+ notifyDataSetChanged()
+ }
+
+ fun update(position: Int, threshold: Int) {
+ when(sections[0].size > position) {
+ true -> notifyItemChanged(position)
+ false -> {
+ for (i in position..position + threshold) {
+ notifyItemChanged(i)
+ }
+ }
+ }
+ }
+
+ override fun layout(sectionRow: SectionRow): Int {
+ return R.layout.item_veiled_layout
+ }
+
+ override fun viewHolder(layout: Int, view: View): BaseViewHolder {
+ return VeiledViewHolder(view, userLayout, onItemClickListener)
+ }
+}
diff --git a/androidveil/src/main/java/com/skydoves/androidveil/VeiledItemOnClickListener.kt b/androidveil/src/main/java/com/skydoves/androidveil/VeiledItemOnClickListener.kt
new file mode 100644
index 0000000..15510e7
--- /dev/null
+++ b/androidveil/src/main/java/com/skydoves/androidveil/VeiledItemOnClickListener.kt
@@ -0,0 +1,22 @@
+
+/*
+ * Copyright (C) 2018 skydoves
+ *
+ * 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.skydoves.androidveil
+
+interface VeiledItemOnClickListener {
+ fun onItemClicked(pos: Int)
+}
diff --git a/androidveil/src/main/java/com/skydoves/androidveil/VeiledViewHolder.kt b/androidveil/src/main/java/com/skydoves/androidveil/VeiledViewHolder.kt
new file mode 100644
index 0000000..d77c6de
--- /dev/null
+++ b/androidveil/src/main/java/com/skydoves/androidveil/VeiledViewHolder.kt
@@ -0,0 +1,66 @@
+
+/*
+ * Copyright (C) 2018 skydoves
+ *
+ * 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.skydoves.androidveil
+
+import android.support.annotation.LayoutRes
+import android.view.View
+import com.facebook.shimmer.Shimmer
+import com.skydoves.baserecyclerviewadapter.BaseViewHolder
+
+class VeiledViewHolder(view: View, @LayoutRes val layout: Int,
+ private val onItemClickListener: VeiledItemOnClickListener? = null)
+ : BaseViewHolder(view) {
+
+ private lateinit var veilParams: VeilParams
+
+ @Throws(Exception::class)
+ override fun bindData(data: Any) {
+ if (data is VeilParams) {
+ veilParams = data
+ drawItem()
+ }
+ }
+
+ /** Draw ViewHolderItem by data */
+ private fun drawItem() {
+ if(itemView is VeilLayout && itemView.layout == -1) {
+ itemView.layout = layout
+ veilParams.shimmer?.let {
+ itemView.shimmer = it
+ } ?: let {
+ val shimmer = Shimmer.ColorHighlightBuilder().setBaseColor(veilParams.baseColor).setHighlightColor(veilParams.highlightColor)
+ .setBaseAlpha(veilParams.baseAlpha).setHighlightAlpha(veilParams.highlightAlpha).setDropoff(veilParams.dropOff).build()
+ itemView.shimmer = shimmer
+ }
+ itemView.shimmerEnable = veilParams.shimmerEnable
+ itemView.veil()
+ } else if(itemView is VeilLayout) {
+ itemView.veil()
+ itemView.startShimmer()
+ }
+ }
+
+ /** Event OnClickListener */
+ override fun onClick(p0: View?) {
+ onItemClickListener?.onItemClicked(adapterPosition)
+ }
+
+ override fun onLongClick(p0: View?): Boolean {
+ return false
+ }
+}
diff --git a/androidveil/src/main/java/com/skydoves/androidveil/ViewExtension.kt b/androidveil/src/main/java/com/skydoves/androidveil/ViewExtension.kt
new file mode 100644
index 0000000..fecf94b
--- /dev/null
+++ b/androidveil/src/main/java/com/skydoves/androidveil/ViewExtension.kt
@@ -0,0 +1,28 @@
+
+/*
+ * Copyright (C) 2018 skydoves
+ *
+ * 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.skydoves.androidveil
+
+import android.view.View
+
+fun View.visible() {
+ this.visibility = View.VISIBLE
+}
+
+fun View.invisible() {
+ this.visibility = View.INVISIBLE
+}
\ No newline at end of file
diff --git a/androidveil/src/main/res/layout/item_veiled_layout.xml b/androidveil/src/main/res/layout/item_veiled_layout.xml
new file mode 100644
index 0000000..0097275
--- /dev/null
+++ b/androidveil/src/main/res/layout/item_veiled_layout.xml
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/androidveil/src/main/res/values/attrs_veil.xml b/androidveil/src/main/res/values/attrs_veil.xml
new file mode 100644
index 0000000..840da64
--- /dev/null
+++ b/androidveil/src/main/res/values/attrs_veil.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/androidveil/src/main/res/values/strings.xml b/androidveil/src/main/res/values/strings.xml
new file mode 100644
index 0000000..3027beb
--- /dev/null
+++ b/androidveil/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+ AndroidVeil
+ Loading
+
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..6fd8f4f
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,33 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+
+android {
+ compileSdkVersion 28
+ defaultConfig {
+ applicationId "com.skydoves.androidveildemo"
+ minSdkVersion 15
+ targetSdkVersion 28
+ versionCode 1
+ versionName "1.0"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation "com.android.support:appcompat-v7:$support_version"
+ implementation "com.android.support:design:$support_version"
+ implementation "com.android.support:recyclerview-v7:$support_version"
+ implementation "com.github.skydoves:baserecyclerviewadapter:$adapter_version"
+ implementation "io.reactivex.rxjava2:rxjava:$rxjava_version"
+ implementation "io.reactivex.rxjava2:rxandroid:$rxandroid_version"
+
+ implementation project(":androidveil")
+}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..89acbd3
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/skydoves/androidveildemo/DetailActivity.kt b/app/src/main/java/com/skydoves/androidveildemo/DetailActivity.kt
new file mode 100644
index 0000000..dd5e43f
--- /dev/null
+++ b/app/src/main/java/com/skydoves/androidveildemo/DetailActivity.kt
@@ -0,0 +1,32 @@
+package com.skydoves.androidveildemo
+
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import io.reactivex.Observable
+import io.reactivex.android.schedulers.AndroidSchedulers
+import kotlinx.android.synthetic.main.activity_detail.*
+import java.util.concurrent.TimeUnit
+
+/**
+ * Developed by skydoves on 2018-10-30.
+ * Copyright (c) 2018 skydoves rights reserved.
+ */
+
+class DetailActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_detail)
+ applyToolbarMargin(detail_toolbar)
+
+ detail_veilLayout_header.shimmer = ShimmerUtils.getGrayShimmer(this)
+
+ // delay-auto-unveil
+ val delay = Observable.just(0).delay(3000, TimeUnit.MILLISECONDS)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe {
+ detail_veilLayout_header.unVeil()
+ detail_veilLayout_body.unVeil()
+ }
+ }
+}
diff --git a/app/src/main/java/com/skydoves/androidveildemo/Extension.kt b/app/src/main/java/com/skydoves/androidveildemo/Extension.kt
new file mode 100644
index 0000000..c15fb0f
--- /dev/null
+++ b/app/src/main/java/com/skydoves/androidveildemo/Extension.kt
@@ -0,0 +1,31 @@
+package com.skydoves.androidveildemo
+
+import android.app.Activity
+import android.os.Build
+import android.support.design.widget.CollapsingToolbarLayout
+import android.support.v7.app.AppCompatActivity
+import android.support.v7.widget.Toolbar
+
+/**
+ * Developed by skydoves on 2018-10-31.
+ * Copyright (c) 2018 skydoves rights reserved.
+ */
+
+fun Activity.checkIsMaterialVersion() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
+
+fun AppCompatActivity.applyToolbarMargin(toolbar: Toolbar) {
+ if(checkIsMaterialVersion()) {
+ toolbar.layoutParams = (toolbar.layoutParams as CollapsingToolbarLayout.LayoutParams).apply {
+ topMargin = getStatusBarSize()
+ }
+ }
+}
+
+private fun AppCompatActivity.getStatusBarSize(): Int {
+ val idStatusBarHeight = resources.getIdentifier("status_bar_height", "dimen", "android")
+ return if (idStatusBarHeight > 0) {
+ resources.getDimensionPixelSize(idStatusBarHeight)
+ } else {
+ 0
+ }
+}
diff --git a/app/src/main/java/com/skydoves/androidveildemo/MainActivity.kt b/app/src/main/java/com/skydoves/androidveildemo/MainActivity.kt
new file mode 100644
index 0000000..ee89790
--- /dev/null
+++ b/app/src/main/java/com/skydoves/androidveildemo/MainActivity.kt
@@ -0,0 +1,55 @@
+package com.skydoves.androidveildemo
+
+import android.content.Intent
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.support.v7.widget.LinearLayoutManager
+import android.widget.Toast
+import com.skydoves.androidveil.VeiledItemOnClickListener
+import com.skydoves.androidveildemo.profile.ListItemUtils
+import com.skydoves.androidveildemo.profile.Profile
+import com.skydoves.androidveildemo.profile.ProfileAdapter
+import com.skydoves.androidveildemo.profile.ProfileViewHolder
+import io.reactivex.Observable
+import io.reactivex.android.schedulers.AndroidSchedulers
+import kotlinx.android.synthetic.main.activity_main.*
+import java.util.concurrent.TimeUnit
+
+/**
+ * Developed by skydoves on 2018-10-30.
+ * Copyright (c) 2018 skydoves rights reserved.
+ */
+
+class MainActivity : AppCompatActivity(), VeiledItemOnClickListener, ProfileViewHolder.Delegate {
+
+ private val adapter by lazy { ProfileAdapter(this) }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+
+ // sets VeilRecyclerView's properties
+ veilRecyclerView.setVeilLayout(R.layout.item_profile, this)
+ veilRecyclerView.setAdapter(adapter)
+ veilRecyclerView.setLayoutManager(LinearLayoutManager(this))
+ veilRecyclerView.addVeiledItems(15)
+
+ // add profile times to adapter
+ adapter.addProfiles(ListItemUtils.getProfiles(this))
+
+ // delay-auto-unveil
+ val delay = Observable.just(0).delay(3000, TimeUnit.MILLISECONDS)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe { veilRecyclerView.unVeil() }
+ }
+
+ /** OnItemClickListener by Veiled Item */
+ override fun onItemClicked(pos: Int) {
+ Toast.makeText(this, getString(R.string.msg_loading), Toast.LENGTH_SHORT).show()
+ }
+
+ /** OnItemClickListener by User Item */
+ override fun onItemClickListener(profile: Profile) {
+ startActivity(Intent(this, DetailActivity::class.java))
+ }
+}
diff --git a/app/src/main/java/com/skydoves/androidveildemo/ShimmerUtils.kt b/app/src/main/java/com/skydoves/androidveildemo/ShimmerUtils.kt
new file mode 100644
index 0000000..e2be63a
--- /dev/null
+++ b/app/src/main/java/com/skydoves/androidveildemo/ShimmerUtils.kt
@@ -0,0 +1,21 @@
+package com.skydoves.androidveildemo
+
+import android.content.Context
+import android.support.v4.content.ContextCompat
+import com.facebook.shimmer.Shimmer
+
+/**
+ * Developed by skydoves on 2018-10-31.
+ * Copyright (c) 2018 skydoves rights reserved.
+ */
+
+object ShimmerUtils {
+ fun getGrayShimmer(context: Context): Shimmer {
+ return Shimmer.ColorHighlightBuilder()
+ .setBaseColor(ContextCompat.getColor(context, R.color.shimmerBase0))
+ .setHighlightColor(ContextCompat.getColor(context, R.color.shimmerHighlight0))
+ .setBaseAlpha(1f)
+ .setHighlightAlpha(1f)
+ .build()
+ }
+}
diff --git a/app/src/main/java/com/skydoves/androidveildemo/profile/ListItemUtils.kt b/app/src/main/java/com/skydoves/androidveildemo/profile/ListItemUtils.kt
new file mode 100644
index 0000000..7f55662
--- /dev/null
+++ b/app/src/main/java/com/skydoves/androidveildemo/profile/ListItemUtils.kt
@@ -0,0 +1,25 @@
+package com.skydoves.androidveildemo.profile
+
+import android.content.Context
+import android.support.v4.content.ContextCompat
+import com.skydoves.androidveildemo.R
+
+/**
+ * Developed by skydoves on 2018-10-30.
+ * Copyright (c) 2018 skydoves rights reserved.
+ */
+
+object ListItemUtils {
+ fun getProfiles(context: Context): List {
+ val list = ArrayList()
+ list.add(Profile(ContextCompat.getDrawable(context, R.drawable.person0), "The Little Prince", "And now here is my secret, a very simple secret: It is only with the heart that one can see rightly; what is essential is invisible to the eye."))
+ list.add(Profile(ContextCompat.getDrawable(context, R.drawable.person1), "Mia Vance", "All grown-ups were once children... but only few of them remember it."))
+ list.add(Profile(ContextCompat.getDrawable(context, R.drawable.person2), "Ryker Beil", "What makes the desert beautiful,' said the little prince, 'is that somewhere it hides a well..."))
+ list.add(Profile(ContextCompat.getDrawable(context, R.drawable.person3), "Kayden Bautista", "It is the time you have wasted for your rose that makes your rose so important."))
+ list.add(Profile(ContextCompat.getDrawable(context, R.drawable.person4), "Skylar Odom", "The most beautiful things in the world cannot be seen or touched, they are felt with the heart."))
+ list.add(Profile(ContextCompat.getDrawable(context, R.drawable.person5), "Autumn Villegas", "It is such a mysterious place, the land of tears."))
+ list.add(Profile(ContextCompat.getDrawable(context, R.drawable.person6), "Wyatt Sherman", "Well, I must endure the presence of a few caterpillars if I wish to become acquainted with the butterflies."))
+ list.add(Profile(ContextCompat.getDrawable(context, R.drawable.person7), "Rachel Alvarado", "You see, one loves the sunset when one is so sad."))
+ return list
+ }
+}
diff --git a/app/src/main/java/com/skydoves/androidveildemo/profile/Profile.kt b/app/src/main/java/com/skydoves/androidveildemo/profile/Profile.kt
new file mode 100644
index 0000000..f2fe79e
--- /dev/null
+++ b/app/src/main/java/com/skydoves/androidveildemo/profile/Profile.kt
@@ -0,0 +1,12 @@
+package com.skydoves.androidveildemo.profile
+
+import android.graphics.drawable.Drawable
+
+/**
+ * Developed by skydoves on 2018-10-30.
+ * Copyright (c) 2018 skydoves rights reserved.
+ */
+
+data class Profile(val image: Drawable?,
+ val name: String,
+ val content: String)
\ No newline at end of file
diff --git a/app/src/main/java/com/skydoves/androidveildemo/profile/ProfileAdapter.kt b/app/src/main/java/com/skydoves/androidveildemo/profile/ProfileAdapter.kt
new file mode 100644
index 0000000..ddc3f26
--- /dev/null
+++ b/app/src/main/java/com/skydoves/androidveildemo/profile/ProfileAdapter.kt
@@ -0,0 +1,32 @@
+package com.skydoves.androidveildemo.profile
+
+import android.view.View
+import com.skydoves.androidveildemo.R
+import com.skydoves.baserecyclerviewadapter.BaseAdapter
+import com.skydoves.baserecyclerviewadapter.BaseViewHolder
+import com.skydoves.baserecyclerviewadapter.SectionRow
+
+/**
+ * Developed by skydoves on 2018-10-30.
+ * Copyright (c) 2018 skydoves rights reserved.
+ */
+
+class ProfileAdapter(private val delegate: ProfileViewHolder.Delegate): BaseAdapter() {
+
+ init {
+ addSection(ArrayList())
+ }
+
+ fun addProfiles(profiles: List) {
+ addItemsOnSection(0, profiles)
+ notifyDataSetChanged()
+ }
+
+ override fun layout(sectionRow: SectionRow): Int {
+ return R.layout.item_profile
+ }
+
+ override fun viewHolder(layout: Int, view: View): BaseViewHolder {
+ return ProfileViewHolder(view, delegate)
+ }
+}
diff --git a/app/src/main/java/com/skydoves/androidveildemo/profile/ProfileViewHolder.kt b/app/src/main/java/com/skydoves/androidveildemo/profile/ProfileViewHolder.kt
new file mode 100644
index 0000000..9ba569e
--- /dev/null
+++ b/app/src/main/java/com/skydoves/androidveildemo/profile/ProfileViewHolder.kt
@@ -0,0 +1,45 @@
+package com.skydoves.androidveildemo.profile
+
+import android.view.View
+import com.skydoves.baserecyclerviewadapter.BaseViewHolder
+import kotlinx.android.synthetic.main.item_profile.view.*
+
+/**
+ * Developed by skydoves on 2018-10-30.
+ * Copyright (c) 2018 skydoves rights reserved.
+ */
+
+class ProfileViewHolder(val view: View,
+ private val delegate: Delegate): BaseViewHolder(view) {
+
+ interface Delegate {
+ fun onItemClickListener(profile: Profile)
+ }
+
+ private lateinit var profileItem: Profile
+
+ override fun bindData(data: Any) {
+ if(data is Profile) {
+ this.profileItem = data
+ drawItemUI()
+ }
+ }
+
+ private fun drawItemUI() {
+ itemView.run {
+ profileItem.image?.let { profile.setImageDrawable(it) }
+ name.text = profileItem.name
+ name.visibility = View.VISIBLE
+ content.text = profileItem.content
+ content.visibility = View.VISIBLE
+ }
+ }
+
+ override fun onClick(p0: View?) {
+ delegate.onItemClickListener(profile = profileItem)
+ }
+
+ override fun onLongClick(p0: View?): Boolean {
+ return false
+ }
+}
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..c7bd21d
--- /dev/null
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/bg1.jpg b/app/src/main/res/drawable/bg1.jpg
new file mode 100644
index 0000000..5d2ac59
Binary files /dev/null and b/app/src/main/res/drawable/bg1.jpg differ
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..d5fccc5
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/person0.png b/app/src/main/res/drawable/person0.png
new file mode 100644
index 0000000..a5f2a75
Binary files /dev/null and b/app/src/main/res/drawable/person0.png differ
diff --git a/app/src/main/res/drawable/person1.png b/app/src/main/res/drawable/person1.png
new file mode 100644
index 0000000..32e4df8
Binary files /dev/null and b/app/src/main/res/drawable/person1.png differ
diff --git a/app/src/main/res/drawable/person2.png b/app/src/main/res/drawable/person2.png
new file mode 100644
index 0000000..3d666e9
Binary files /dev/null and b/app/src/main/res/drawable/person2.png differ
diff --git a/app/src/main/res/drawable/person3.png b/app/src/main/res/drawable/person3.png
new file mode 100644
index 0000000..470b1c2
Binary files /dev/null and b/app/src/main/res/drawable/person3.png differ
diff --git a/app/src/main/res/drawable/person4.png b/app/src/main/res/drawable/person4.png
new file mode 100644
index 0000000..278a0a1
Binary files /dev/null and b/app/src/main/res/drawable/person4.png differ
diff --git a/app/src/main/res/drawable/person5.png b/app/src/main/res/drawable/person5.png
new file mode 100644
index 0000000..5784e16
Binary files /dev/null and b/app/src/main/res/drawable/person5.png differ
diff --git a/app/src/main/res/drawable/person6.png b/app/src/main/res/drawable/person6.png
new file mode 100644
index 0000000..da74445
Binary files /dev/null and b/app/src/main/res/drawable/person6.png differ
diff --git a/app/src/main/res/drawable/person7.png b/app/src/main/res/drawable/person7.png
new file mode 100644
index 0000000..f24cf7f
Binary files /dev/null and b/app/src/main/res/drawable/person7.png differ
diff --git a/app/src/main/res/layout/activity_detail.xml b/app/src/main/res/layout/activity_detail.xml
new file mode 100644
index 0000000..311e0c5
--- /dev/null
+++ b/app/src/main/res/layout/activity_detail.xml
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..903ec8a
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_profile.xml b/app/src/main/res/layout/item_profile.xml
new file mode 100644
index 0000000..ceb739e
--- /dev/null
+++ b/app/src/main/res/layout/item_profile.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/layout_item_test.xml b/app/src/main/res/layout/layout_item_test.xml
new file mode 100644
index 0000000..2a0e33e
--- /dev/null
+++ b/app/src/main/res/layout/layout_item_test.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a2f5908
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..1b52399
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..ff10afd
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..115a4c7
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..dcd3cd8
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..459ca60
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..8ca12fe
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..8e19b41
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b824ebd
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..4c19a13
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml
new file mode 100644
index 0000000..45c074c
--- /dev/null
+++ b/app/src/main/res/values-v21/styles.xml
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..def952b
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,13 @@
+
+
+ #3d95c9
+ #2485be
+ #3d95c9
+ #303030
+ #424242
+ #212121
+ #87ffffff
+ #b0abb0
+ #c2c2c2
+ #606060
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..62a7cd2
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ AndroidVeilDemo
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..2651899
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..3ad724e
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,35 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ ext {
+ kotlin_version = '1.2.71'
+ support_version = '28.0.0'
+ adapter_version = '0.1.1'
+ rxjava_version = '2.1.8'
+ rxandroid_version = '2.1.0'
+ shimmer_version = '0.3.0'
+ }
+
+ repositories {
+ google()
+ jcenter()
+ }
+
+ dependencies {
+ classpath "com.android.tools.build:gradle:3.1.3"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath 'com.novoda:bintray-release:0.8.1'
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+tasks.withType(Javadoc) {
+ excludes = ['**/*.kt']
+ options.addBooleanOption('Xdoclint:none', true)
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..743d692
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,13 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..7a3265e
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..3d54b49
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Oct 30 02:00:58 KST 2018
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..cccdd3d
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..fd8ea60
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+include ':app', ':androidveil'