package com.asha.nightowllib;
import android.app.Activity;
import android.support.annotation.NonNull;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import com.asha.nightowllib.handler.ISkinHandler;
import com.asha.nightowllib.handler.OwlHandlerManager;
import com.asha.nightowllib.inflater.Factory4InjectedInflater;
import com.asha.nightowllib.observer.IOwlObserver;
import com.asha.nightowllib.observer.OwlViewContext;
import com.asha.nightowllib.paint.ColorBox;
import com.asha.nightowllib.paint.OwlPaintManager;
import static com.asha.nightowllib.NightOwlUtil.checkNonNull;
import static com.asha.nightowllib.NightOwlUtil.checkViewCollected;
import static com.asha.nightowllib.NightOwlUtil.injectLayoutInflater;
import static com.asha.nightowllib.NightOwlUtil.insertEmptyTag;
import static com.asha.nightowllib.NightOwlUtil.insertViewContext;
import static com.asha.nightowllib.NightOwlUtil.obtainSkinBox;
import static com.asha.nightowllib.NightOwlUtil.obtainViewContext;
/**
* Created by hzqiujiadi on 15/11/5.
* hzqiujiadi ashqalcn@gmail.com
*/
public class NightOwl {
private static final String TAG = "NightOwl";
private static final String WINDOW_INFLATER = "mLayoutInflater";
private static final String THEME_INFLATER = "mInflater";
private static NightOwl sInstance;
static {
NightOwlTable.init();
}
private int mMode = 0;
private IOwlObserver mOwlObserver;
private NightOwl(){
}
public static void owlBeforeCreate(Activity activity){
Window window = activity.getWindow();
LayoutInflater layoutInflater = window.getLayoutInflater();
// replace the inflater in window
LayoutInflater injectLayoutInflater1 = Factory4InjectedInflater.newInstance(layoutInflater, activity);
injectLayoutInflater(injectLayoutInflater1
, activity.getWindow()
, activity.getWindow().getClass()
, WINDOW_INFLATER);
// replace the inflater in current ContextThemeWrapper
LayoutInflater injectLayoutInflater2 = injectLayoutInflater1.cloneInContext(activity);
injectLayoutInflater(injectLayoutInflater2
, activity
, ContextThemeWrapper.class
, THEME_INFLATER);
// insert owlViewContext into root view.
View v = activity.getWindow().getDecorView();
OwlViewContext owlObservable = new OwlViewContext();
insertViewContext(v, owlObservable);
}
public static void owlAfterCreate(Activity activity){
View root = activity.getWindow().getDecorView();
OwlViewContext viewContext = obtainViewContext(root);
checkNonNull(viewContext, "OwlViewContext can not be null!");
// setup some observer
viewContext.setupWithCurrentActivity(activity);
// init set
viewContext.notifyObserver(sharedInstance().mMode, activity);
}
public static void owlResume( Activity activity ){
NightOwl nightOwl = sharedInstance();
int targetMode = nightOwl.mMode;
owlDressUp(targetMode, activity);
}
public static void owlNewDress( @NonNull Activity activity ) {
int current = owlCurrentMode() + 1;
current %= 2;
owlDressUp(current, activity);
}
public static void owlRecyclerFix(View view){
int mode = owlCurrentMode();
innerRefreshSkin(mode, view);
}
private static void owlDressUp( int mode, @NonNull Activity activity ){
// View tree
NightOwl owl = sharedInstance();
View root = activity.getWindow().getDecorView();
OwlViewContext viewContext = obtainViewContext(root);
checkNonNull(viewContext, "OwlViewContext can not be null!");
if ( viewContext.needSync(mode) ){
// refresh skin
innerRefreshSkin(mode, root);
// OwlObserver
viewContext.notifyObserver(mode, activity);
}
owl.mMode = mode;
if ( owl.mOwlObserver != null ) owl.mOwlObserver.onSkinChange(mode,activity);
}
/**
* Register a custom view which created by new instance directly.
*
* @param view instanceof IOwlObserver & View
* NightOwl will trigger view.onSkinChange immediately.
*/
public static void owlRegisterCustom(@NonNull IOwlObserver view){
if ( view instanceof View ) {
View target = (View) view;
insertEmptyTag(target);
view.onSkinChange(owlCurrentMode(), null);
} else {
throw new IllegalArgumentException("owlRegisterCustom param must be a instance of View");
}
}
public static void owlRegisterHandler(Class<? extends ISkinHandler> clz, Class paintTable){
OwlHandlerManager.registerHandler(clz);
OwlPaintManager.registerPaint(paintTable);
}
public static int owlCurrentMode(){
return sharedInstance().mMode;
}
private static void innerRefreshSkin(int mode, View view ){
// refresh current view
if ( checkViewCollected(view) ){
ColorBox box = obtainSkinBox(view);
if ( box != null ) box.refreshSkin(mode, view);
if ( view instanceof IOwlObserver ){
((IOwlObserver) view).onSkinChange(mode,null);
}
}
// traversal view tree
if ( view instanceof ViewGroup){
ViewGroup vg = (ViewGroup) view;
View sub;
for (int i = 0; i < vg.getChildCount(); i++) {
sub = vg.getChildAt(i);
innerRefreshSkin(mode, sub);
}
}
}
private static NightOwl sharedInstance(){
checkNonNull(sInstance,"You must create NightOwl in Application onCreate.");
return sInstance;
}
public static Builder builder(){
return new Builder();
}
public static class Builder {
private int mode;
private IOwlObserver owlObserver;
public Builder defaultMode(int mode){
this.mode = mode;
return this;
}
/**
* Subscribed by a owlObserver to know the skin change.
*
* @param owlObserver do some persistent working here
* @return Builder
*/
public Builder subscribedBy(IOwlObserver owlObserver){
this.owlObserver = owlObserver;
return this;
}
public NightOwl create(){
if ( sInstance != null ) throw new RuntimeException("Do not create NightOwl again.");
sInstance = new NightOwl();
sInstance.mMode = mode;
sInstance.mOwlObserver = owlObserver;
return sInstance;
}
}
}