Skip to content
This repository has been archived by the owner on Aug 10, 2020. It is now read-only.

Commit

Permalink
添加动态换肤工具chameleon,完善已有模块。
Browse files Browse the repository at this point in the history
  • Loading branch information
Tears丶残阳 committed Dec 4, 2019
1 parent 122f368 commit 64787d6
Show file tree
Hide file tree
Showing 55 changed files with 720 additions and 429 deletions.
19 changes: 10 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,13 @@ allprojects {

模块|依赖
---|---
adapter|implementation 'com.github.xiazunyang.brick:adapter:1.4.0'
brick|implementation 'com.github.xiazunyang.brick:brick:1.4.0'
context-util|implementation 'com.github.xiazunyang.brick:context-util:1.4.0'
delegate|implementation 'com.github.xiazunyang.brick:delegate:1.4.0'
http|implementation 'com.github.xiazunyang.brick:http:1.4.0'
result|implementation 'com.github.xiazunyang.brick:result:1.4.0'
rx|implementation 'com.github.xiazunyang.brick:rx:1.4.0'
stateful-layout|implementation 'com.github.xiazunyang.brick:stateful-layout:1.4.0'
stateful-livedata|implementation 'com.github.xiazunyang.brick:stateful-livedata:1.4.0'
adapter|implementation 'com.github.xiazunyang.brick:adapter:1.4.1'
brick|implementation 'com.github.xiazunyang.brick:brick:1.4.1'
chameleon|implementation 'com.github.xiazunyang.brick:chameleon:1.4.1'
context-util|implementation 'com.github.xiazunyang.brick:context-util:1.4.1'
delegate|implementation 'com.github.xiazunyang.brick:delegate:1.4.1'
http|implementation 'com.github.xiazunyang.brick:http:1.4.1'
result|implementation 'com.github.xiazunyang.brick:result:1.4.1'
rx|implementation 'com.github.xiazunyang.brick:rx:1.4.1'
stateful-layout|implementation 'com.github.xiazunyang.brick:stateful-layout:1.4.1'
stateful-livedata|implementation 'com.github.xiazunyang.brick:stateful-livedata:1.4.1'
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.numeron.adapter

import androidx.paging.AsyncPagedListDiffer
import androidx.paging.PagedListAdapter
import androidx.recyclerview.widget.RecyclerView

@Suppress("UNCHECKED_CAST")
fun <T, VH : RecyclerView.ViewHolder> PagedListAdapter<T, VH>.getDiffer(): AsyncPagedListDiffer<T> {
val mDifferField = PagedListAdapter::class.java.getDeclaredField("mDiffer")
mDifferField.isAccessible = true
return mDifferField.get(this) as AsyncPagedListDiffer<T>
}
36 changes: 28 additions & 8 deletions adapter/src/main/java/com/numeron/adapter/SpaceItemDecoration.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,38 @@ class SpaceItemDecoration(
}

private fun setOutRectByGrid(rect: Rect, view: View, parent: RecyclerView) {
//获取当前View的位置
val position = parent.getChildAdapterPosition(view) - headerCount
val spanCount = getSpanCount(parent)
val column = position % spanCount
rect.left = space
rect.bottom = space
rect.top = if(position < spanCount) space else 0
rect.right = if(column == spanCount - 1) space else 0
//获取有多少个View
val itemCount = parent.adapter?.itemCount ?: 0
//获取有多少列
val columnCount = getSpanCount(parent)
//获取有多少行
val rowCount = getRowNumber(itemCount, columnCount)
//当前是第几列
val column = position % columnCount
//当前是第几行
val row = getRowNumber(position + 1, columnCount)
//计算平均间隔
val average = space / columnCount
rect.left = (columnCount - column) * average
rect.top = space
rect.right = (column + 1) * average
rect.bottom = if (row == rowCount) space else 0
}

private fun getRowNumber(countOrPosition: Int, spanCount: Int): Int {
return countOrPosition / spanCount + if (countOrPosition % spanCount > 0) 1 else 0
}

private fun getLinearLayoutOrientation(parent: RecyclerView): Int {
return (parent.layoutManager as LinearLayoutManager).orientation
}

private fun setOutRectByLinear(rect: Rect, view: View, parent: RecyclerView) {
rect.top = if (parent.getChildLayoutPosition(view) - headerCount == 0) space else 0
rect.left = space
val orientation = getLinearLayoutOrientation(parent)
rect.top = if (orientation == LinearLayoutManager.VERTICAL && parent.getChildLayoutPosition(view) - headerCount == 0) space else 0
rect.left = if (orientation == LinearLayoutManager.HORIZONTAL && parent.getChildLayoutPosition(view) - headerCount == 0) space else 0
rect.right = space
rect.bottom = space
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import com.numeron.adapter.BindingHolder
import com.numeron.adapter.PagedBindingAdapter
import com.numeron.adapter.SpaceItemDecoration
import com.numeron.brick.createViewModel
import com.numeron.delegate.ActivityExtraDelegate
import com.numeron.starter.startActivity
import com.numeron.util.ActivityExtraDelegate
import com.numeron.util.dp
import com.numeron.view.StatefulLayoutMessageObserver
import com.numeron.wandroid.entity.db.Article
import com.numeron.wandroid.other.*
import com.numeron.view.StatefulMessageObserver
import com.numeron.wandroid.R
import com.numeron.wandroid.contract.ArticleListParamProvider
import com.numeron.wandroid.contract.ArticleListViewModel
Expand Down Expand Up @@ -49,7 +49,7 @@ class ArticleListActivity : AppCompatActivity(), ArticleListParamProvider {
//替换默认的加载动画
articleListStatusLayout.setLoadingOperation(articleListRefreshLayout::setRefreshing)
articleListViewModel.articleListLiveData.observe(this, Observer(adapter::submitList))
articleListViewModel.loadStateLiveData.observe(this, StatefulMessageObserver(articleListStatusLayout))
articleListViewModel.loadStateLiveData.observe(this, StatefulLayoutMessageObserver(articleListStatusLayout))
}

private inner class ArticleAdapter : PagedBindingAdapter<Article,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import com.numeron.adapter.PagedBindingAdapter
import com.numeron.adapter.SpaceItemDecoration
import com.numeron.brick.createViewModel
import com.numeron.util.dp
import com.numeron.view.StatefulLayoutMessageObserver
import com.numeron.wandroid.entity.db.WeChatAuthor
import com.numeron.wandroid.other.*
import com.numeron.view.StatefulMessageObserver
import com.numeron.wandroid.R
import com.numeron.wandroid.contract.WeChatAuthorViewModel
import com.numeron.wandroid.databinding.RecyclerItemWeChatAuthorLayoutBinding
Expand All @@ -33,7 +33,7 @@ class WeChatAuthorActivity : AppCompatActivity() {
weChatAuthorRefreshLayout.isEnabled = connectivityManager.isDefaultNetworkActive
weChatAuthorStatusLayout.setLoadingOperation(weChatAuthorRefreshLayout::setRefreshing)
weChatAuthorViewModel.weChatAuthorLiveData.observe(this, Observer(adapter::submitList))
weChatAuthorViewModel.loadStatusLiveData.observe(this, StatefulMessageObserver(weChatAuthorStatusLayout))
weChatAuthorViewModel.loadStatusLiveData.observe(this, StatefulLayoutMessageObserver(weChatAuthorStatusLayout))
}

private inner class WeChatAuthorAdapter : PagedBindingAdapter<WeChatAuthor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList
import com.numeron.brick.ViewModel
import com.numeron.brick.createModel
import com.numeron.brick.stack
import com.numeron.wandroid.dao.ArticleDao
import com.numeron.wandroid.entity.ApiResponse
import com.numeron.wandroid.entity.Paged
Expand All @@ -26,7 +26,7 @@ interface ArticleListParamProvider {

class ArticleListViewModel(private val paramProvider: ArticleListParamProvider) : ViewModel() {

private val articleRepository = createModel<ArticleRepository>()
private val articleRepository = stack<ArticleRepository>()

private val pagedConfig = PagedList.Config.Builder()
.setPageSize(20)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList
import com.numeron.brick.ViewModel
import com.numeron.brick.createModel
import com.numeron.brick.stack
import com.numeron.wandroid.dao.WeChatAuthorDao
import com.numeron.wandroid.entity.ApiResponse
import com.numeron.wandroid.entity.db.WeChatAuthor
Expand All @@ -16,7 +16,7 @@ import retrofit2.http.GET

class WeChatAuthorViewModel : ViewModel() {

private val weChatAuthorRepository = createModel<WeChatAuthorRepository>()
private val weChatAuthorRepository = stack<WeChatAuthorRepository>()

val loadStatusLiveData = MutableLiveData<Pair<State, String>>()
val weChatAuthorLiveData =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

package com.numeron.wandroid.other

import com.numeron.util.PreferencesDelegate
import com.numeron.delegate.PreferencesDelegate


var userId: Long by PreferencesDelegate(preferences, 0)
Expand Down
4 changes: 3 additions & 1 deletion brick/src/main/java/com/numeron/brick/ApiFactory.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.numeron.brick;

import org.jetbrains.annotations.NotNull;

import java.lang.reflect.Method;

class ApiFactory implements IRetrofit {
Expand Down Expand Up @@ -33,7 +35,7 @@ static ApiFactory create(Object retrofit) {

@Override
@SuppressWarnings("unchecked")
public <T> T create(Class<T> clazz) {
public <T> T create(@NotNull Class<T> clazz) {
//尝试通过反射来创建Retrofit Api
if (isInitialized()) {
try {
Expand Down
18 changes: 16 additions & 2 deletions brick/src/main/java/com/numeron/brick/Brick.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package com.numeron.brick

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStore
import androidx.lifecycle.ViewModelStoreOwner


Expand All @@ -15,6 +16,13 @@ fun install(retrofit: Any, room: Any? = null) {
ModelFactory.install(retrofit, room)
}

/**
* 当使用多个数据库时,请在初始化前,使用此方法追加其它数据库
*/
fun addRoom(vararg room: Any) {
ModelFactory.addRoom(*room)
}


/**
* 供外部创建Model的实例的工厂方法
Expand All @@ -24,7 +32,7 @@ fun install(retrofit: Any, room: Any? = null) {
* @return Model 实例
*/
@JvmOverloads
fun <M> createModel(clazz: Class<M>, iRetrofit: Any? = null): M {
fun <M> stack(clazz: Class<M>, iRetrofit: Any? = null): M {
return ModelFactory.create(clazz, iRetrofit)
}

Expand All @@ -34,7 +42,13 @@ fun <M> createModel(clazz: Class<M>, iRetrofit: Any? = null): M {
* @param iRetrofit Any? 创建Model的实例时,用于创建Retrofit Api实例的Retrofit或其它工具类
* @return M Model的实例
*/
inline fun <reified M> createModel(iRetrofit: Any? = null) = createModel(M::class.java, iRetrofit)
inline fun <reified M> stack(iRetrofit: Any? = null) = stack(M::class.java, iRetrofit)

@JvmOverloads
fun <VM : ViewModel> createViewModel(clazz: Class<VM>, store: ViewModelStore, factory: ViewModelProvider.Factory = ViewModelFactory()): VM {
return ViewModelProvider(store, factory).get(clazz)
}


/**
* 创建ViewModel的工厂方法
Expand Down
5 changes: 4 additions & 1 deletion brick/src/main/java/com/numeron/brick/IRetrofit.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.numeron.brick;

import androidx.annotation.NonNull;

/**
* Retrofit中并没有提供相应的接口,所以此接口是对Retrofit中的create方法的代理
* 当项目中使用了二次封装的Retrofit工具类,让工具类实现此接口,在实现方法中调用Retrofit实际的create方法
Expand All @@ -8,8 +10,9 @@
*
* @see retrofit2.Retrofit#create(Class)
*/
@SuppressWarnings("JavadocReference")
public interface IRetrofit {

<T> T create(Class<T> clazz);
<T> T create(@NonNull Class<T> clazz);

}
37 changes: 28 additions & 9 deletions brick/src/main/java/com/numeron/brick/ModelFactory.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
package com.numeron.brick;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@SuppressWarnings("unchecked")
public final class ModelFactory {

private final ApiFactory apiFactory;
private final DaoFactory daoFactory;
private final List<DaoFactory> daoFactories = new ArrayList<>();

private static ModelFactory modelFactory = new ModelFactory(null, null);
private static ModelFactory modelFactory = new ModelFactory(null, Collections.EMPTY_LIST);

private ModelFactory(ApiFactory apiFactory, DaoFactory daoFactory) {
private ModelFactory(ApiFactory apiFactory, List<DaoFactory> daoFactories) {
this.apiFactory = apiFactory;
this.daoFactory = daoFactory;
this.daoFactories.addAll(daoFactories);
}

/**
Expand All @@ -26,10 +28,21 @@ private ModelFactory(ApiFactory apiFactory, DaoFactory daoFactory) {
* @see retrofit2.Retrofit#create(Class)
*/
@SuppressWarnings("JavadocReference")
static void install(Object retrofit, Object room) {
static void install(Object retrofit, Object... room) {
ApiFactory apiFactory = ApiFactory.create(retrofit);
DaoFactory daoFactory = DaoFactory.create(room);
modelFactory = new ModelFactory(apiFactory, daoFactory);
modelFactory = new ModelFactory(apiFactory, transfer(room));
}

static void addRoom(Object... rooms) {
modelFactory.daoFactories.addAll(transfer(rooms));
}

private static List<DaoFactory> transfer(Object... rooms) {
ArrayList<DaoFactory> list = new ArrayList<>();
for (Object room : rooms) {
list.add(DaoFactory.create(room));
}
return list;
}

/**
Expand Down Expand Up @@ -79,8 +92,14 @@ private Object createInstance(Class<?> clazz, IRetrofit iRetrofit) {
//如果接口继承了某一个接口,则说明是RoomDao接口
boolean hasParentInterface = clazz.getInterfaces().length > 0;
if (!hasAnnotation || hasParentInterface) {
if (daoFactory == null) throw new RuntimeException("Brick初始化时没有传入Room实例!");
return daoFactory.getDao(clazz);
if (daoFactories.isEmpty()) throw new RuntimeException("Brick初始化时没有传入Room实例!");
for (DaoFactory daoFactory : daoFactories) {
try {
return daoFactory.getDao(clazz);
} catch (Exception ignored) {
}
}
throw new RuntimeException("所有的Room实例中都没有返回值为" + clazz + "的方法!");
} else {
if (iRetrofit != null) {
return iRetrofit.create(clazz);
Expand Down
6 changes: 2 additions & 4 deletions brick/src/main/java/com/numeron/brick/ViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ package com.numeron.brick

import kotlinx.coroutines.*

/**
* 拥有一个Dispatchers.IO的协程域
*/
abstract class ViewModel : androidx.lifecycle.ViewModel(), CoroutineScope by CoroutineScope(SupervisorJob() + Dispatchers.IO) {
abstract class ViewModel : androidx.lifecycle.ViewModel(),
CoroutineScope by CoroutineScope(SupervisorJob() + Dispatchers.IO) {

override fun onCleared() {
cancel()
Expand Down
1 change: 1 addition & 0 deletions chameleon/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
29 changes: 29 additions & 0 deletions chameleon/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'com.github.dcendents.android-maven'

group = 'com.github.xiazunyang'
version = '0.1.0'

android {
compileSdkVersion 29

defaultConfig {
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "0.0.1"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}

}
1 change: 1 addition & 0 deletions chameleon/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<manifest package="com.numeron.chameleon" />
Loading

0 comments on commit 64787d6

Please sign in to comment.