Commit e46d5faa by 王宇航

首頁佈局

parent 0eb5f0e1
/*
* Copyright 2017 JessYan
*
* 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.jess.arms.base;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.View;
import com.jess.arms.base.delegate.IActivity;
import com.jess.arms.integration.cache.Cache;
import com.jess.arms.integration.cache.CacheType;
import com.jess.arms.integration.lifecycle.ActivityLifecycleable;
import com.jess.arms.mvp.IPresenter;
import com.jess.arms.utils.ArmsUtils;
import com.trello.rxlifecycle2.android.ActivityEvent;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentActivity;
import butterknife.ButterKnife;
import butterknife.Unbinder;
import io.reactivex.subjects.BehaviorSubject;
import io.reactivex.subjects.Subject;
import static com.jess.arms.utils.ThirdViewUtil.convertAutoView;
/**
* ================================================
* 因为 Java 只能单继承,所以如果要用到需要继承特定 {@link Activity} 的三方库,那你就需要自己自定义 {@link Activity}
* 继承于这个特定的 {@link Activity},然后再按照 {@link BaseFragmentActivity} 的格式,将代码复制过去,记住一定要实现{@link IActivity}
* <p>
* Created by JessYan on 22/03/2016
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* ================================================
*/
public abstract class BaseFragmentActivity<P extends IPresenter> extends FragmentActivity implements IActivity, ActivityLifecycleable {
protected final String TAG = this.getClass().getSimpleName();
private final BehaviorSubject<ActivityEvent> mLifecycleSubject = BehaviorSubject.create();
private Cache<String, Object> mCache;
protected Context mContext;
private Unbinder mUnbinder;
@Inject
@Nullable
protected P mPresenter;//如果当前页面逻辑简单, Presenter 可以为 null
@NonNull
@Override
public synchronized Cache<String, Object> provideCache() {
if (mCache == null) {
mCache = ArmsUtils.obtainAppComponentFromContext(this).cacheFactory().build(CacheType.ACTIVITY_CACHE);
}
return mCache;
}
@NonNull
@Override
public final Subject<ActivityEvent> provideLifecycleSubject() {
return mLifecycleSubject;
}
@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
View view = convertAutoView(name, context, attrs);
return view == null ? super.onCreateView(name, context, attrs) : view;
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
//DecorView的背景对我来说无用,但是会产生一次Overdraw,这里去掉(过度绘制优化)
getWindow().setBackgroundDrawable(null);
try {
int layoutResID = initView(savedInstanceState);
//如果initView返回0,框架则不会调用setContentView(),当然也不会 Bind ButterKnife
if (layoutResID != 0) {
setContentView(layoutResID);
//绑定到butterknife
mUnbinder = ButterKnife.bind(this);
}
} catch (Exception e) {
e.printStackTrace();
}
initIntent();
initTopBar();
initLanguage();
initLayoutParams();
initLayoutVisible();
initData(savedInstanceState);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mUnbinder != null && mUnbinder != Unbinder.EMPTY)
mUnbinder.unbind();
this.mUnbinder = null;
if (mPresenter != null)
mPresenter.onDestroy();//释放资源
this.mPresenter = null;
}
/**
* 是否使用eventBus,默认为使用(true),
*
* @return
*/
@Override
public boolean useEventBus() {
return true;
}
/**
* 这个Activity是否会使用Fragment,框架会根据这个属性判断是否注册
* 如果返回false,那意味着这个Activity不需要绑定Fragment,那你再在这个Activity中绑定继承于 {@link BaseFragment} 的Fragment将不起任何作用
*
* @return
*/
@Override
public boolean useFragment() {
return true;
}
}
......@@ -21,9 +21,10 @@ dependencies {
if (project.name != 'arms') {
implementation project(':arms')
}
if (project.name != 'public-base' && project.name != 'public-database' && project.name != 'public-network' && project.name != 'arms') {
//
if (project.name != 'public-database' && project.name != 'public-network' && project.name != 'arms') {
implementation rootProject.ext.dependencies["qmui"]
if (project.name != 'public-ui') {
if (project.name != 'public-ui' && project.name != 'public-base') {
implementation project(':public-ui')
}
}
......
......@@ -111,7 +111,7 @@ ext {
"canary-release" : "com.squareup.leakcanary:leakcanary-android-no-op:${version["canarySdkVersion"]}",
"umeng-analytics" : "com.umeng.analytics:analytics:6.0.1",
// QMUI
"qmui" : "com.qmuiteam:qmui:1.2.0",
"qmui" : "com.qmuiteam:qmui:2.0.0-alpha03",
"arms" : "me.jessyan:arms:2.5.2",
"fastjson" : "com.alibaba:fastjson:1.2.46",
"zxing" : "cn.yipianfengye.android:zxing-library:2.2"
......
......@@ -15,7 +15,7 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme.Base">
android:theme="@style/AppTheme">
<activity android:name=".mvp.ui.activity.MainActivity">
<intent-filter>
......
package com.gingersoft.gsa.cloud.main.di.component;
import dagger.BindsInstance;
import dagger.Component;
import com.jess.arms.di.component.AppComponent;
import com.gingersoft.gsa.cloud.main.di.module.HomeModule;
import com.gingersoft.gsa.cloud.main.mvp.contract.HomeContract;
import com.jess.arms.di.scope.FragmentScope;
import com.gingersoft.gsa.cloud.main.mvp.ui.fragment.HomeFragment;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 01/10/2020 15:02
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@FragmentScope
@Component(modules = HomeModule.class, dependencies = AppComponent.class)
public interface HomeComponent {
void inject(HomeFragment fragment);
@Component.Builder
interface Builder {
@BindsInstance
HomeComponent.Builder view(HomeContract.View view);
HomeComponent.Builder appComponent(AppComponent appComponent);
HomeComponent build();
}
}
\ No newline at end of file
package com.gingersoft.gsa.cloud.main.di.component;
import dagger.BindsInstance;
import dagger.Component;
import com.jess.arms.di.component.AppComponent;
import com.gingersoft.gsa.cloud.main.di.module.MyModule;
import com.gingersoft.gsa.cloud.main.mvp.contract.MyContract;
import com.jess.arms.di.scope.FragmentScope;
import com.gingersoft.gsa.cloud.main.mvp.ui.fragment.MyFragment;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 01/10/2020 15:04
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@FragmentScope
@Component(modules = MyModule.class, dependencies = AppComponent.class)
public interface MyComponent {
void inject(MyFragment fragment);
@Component.Builder
interface Builder {
@BindsInstance
MyComponent.Builder view(MyContract.View view);
MyComponent.Builder appComponent(AppComponent appComponent);
MyComponent build();
}
}
\ No newline at end of file
package com.gingersoft.gsa.cloud.main.di.component;
import dagger.BindsInstance;
import dagger.Component;
import com.jess.arms.di.component.AppComponent;
import com.gingersoft.gsa.cloud.main.di.module.ReportModule;
import com.gingersoft.gsa.cloud.main.mvp.contract.ReportContract;
import com.jess.arms.di.scope.FragmentScope;
import com.gingersoft.gsa.cloud.main.mvp.ui.fragment.ReportFragment;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 01/10/2020 15:03
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@FragmentScope
@Component(modules = ReportModule.class, dependencies = AppComponent.class)
public interface ReportComponent {
void inject(ReportFragment fragment);
@Component.Builder
interface Builder {
@BindsInstance
ReportComponent.Builder view(ReportContract.View view);
ReportComponent.Builder appComponent(AppComponent appComponent);
ReportComponent build();
}
}
\ No newline at end of file
package com.gingersoft.gsa.cloud.main.di.module;
import com.jess.arms.di.scope.FragmentScope;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import com.gingersoft.gsa.cloud.main.mvp.contract.HomeContract;
import com.gingersoft.gsa.cloud.main.mvp.model.HomeModel;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 01/10/2020 15:02
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@Module
public abstract class HomeModule {
@Binds
abstract HomeContract.Model bindHomeModel(HomeModel model);
}
\ No newline at end of file
package com.gingersoft.gsa.cloud.main.di.module;
import com.jess.arms.di.scope.FragmentScope;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import com.gingersoft.gsa.cloud.main.mvp.contract.MyContract;
import com.gingersoft.gsa.cloud.main.mvp.model.MyModel;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 01/10/2020 15:04
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@Module
public abstract class MyModule {
@Binds
abstract MyContract.Model bindMyModel(MyModel model);
}
\ No newline at end of file
package com.gingersoft.gsa.cloud.main.di.module;
import com.jess.arms.di.scope.FragmentScope;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import com.gingersoft.gsa.cloud.main.mvp.contract.ReportContract;
import com.gingersoft.gsa.cloud.main.mvp.model.ReportModel;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 01/10/2020 15:03
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@Module
public abstract class ReportModule {
@Binds
abstract ReportContract.Model bindReportModel(ReportModel model);
}
\ No newline at end of file
package com.gingersoft.gsa.cloud.main.mvp.contract;
import com.gingersoft.gsa.cloud.main.mvp.model.bean.HomeTurnoverBean;
import com.jess.arms.mvp.IView;
import com.jess.arms.mvp.IModel;
import java.util.Map;
import io.reactivex.Observable;
import okhttp3.RequestBody;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 01/10/2020 15:02
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
public interface HomeContract {
//对于经常使用的关于UI的方法可以定义到IView中,如显示隐藏进度条,和显示文字消息
interface View extends IView {
void loadBusinessInfo(Map<String, HomeTurnoverBean.DataBean> data);
}
//Model层定义接口,外部只需关心Model返回的数据,无需关心内部细节,即是否使用缓存
interface Model extends IModel {
Observable<HomeTurnoverBean> getRestaurantReport(RequestBody requestBody);
}
}
package com.gingersoft.gsa.cloud.main.mvp.contract;
import com.jess.arms.mvp.IView;
import com.jess.arms.mvp.IModel;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 01/10/2020 15:04
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
public interface MyContract {
//对于经常使用的关于UI的方法可以定义到IView中,如显示隐藏进度条,和显示文字消息
interface View extends IView {
}
//Model层定义接口,外部只需关心Model返回的数据,无需关心内部细节,即是否使用缓存
interface Model extends IModel {
}
}
package com.gingersoft.gsa.cloud.main.mvp.contract;
import com.jess.arms.mvp.IView;
import com.jess.arms.mvp.IModel;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 01/10/2020 15:03
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
public interface ReportContract {
//对于经常使用的关于UI的方法可以定义到IView中,如显示隐藏进度条,和显示文字消息
interface View extends IView {
}
//Model层定义接口,外部只需关心Model返回的数据,无需关心内部细节,即是否使用缓存
interface Model extends IModel {
}
}
package com.gingersoft.gsa.cloud.main.mvp.model;
import android.app.Application;
import com.gingersoft.gsa.cloud.main.mvp.model.bean.HomeTurnoverBean;
import com.gingersoft.gsa.cloud.main.mvp.model.service.HomeService;
import com.google.gson.Gson;
import com.jess.arms.integration.IRepositoryManager;
import com.jess.arms.mvp.BaseModel;
import com.jess.arms.di.scope.FragmentScope;
import javax.inject.Inject;
import com.gingersoft.gsa.cloud.main.mvp.contract.HomeContract;
import io.reactivex.Observable;
import me.jessyan.retrofiturlmanager.RetrofitUrlManager;
import okhttp3.RequestBody;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 01/10/2020 15:02
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@FragmentScope
public class HomeModel extends BaseModel implements HomeContract.Model {
@Inject
Gson mGson;
@Inject
Application mApplication;
@Inject
public HomeModel(IRepositoryManager repositoryManager) {
super(repositoryManager);
}
@Override
public void onDestroy() {
super.onDestroy();
this.mGson = null;
this.mApplication = null;
}
@Override
public Observable<HomeTurnoverBean> getRestaurantReport(RequestBody requestBody) {
RetrofitUrlManager.getInstance().putDomain("common", "https://m.ricepon.com/member-web/api/");
return mRepositoryManager.obtainRetrofitService(HomeService.class)
.getRestaurantReport(requestBody);
}
}
\ No newline at end of file
package com.gingersoft.gsa.cloud.main.mvp.model;
import android.app.Application;
import com.google.gson.Gson;
import com.jess.arms.integration.IRepositoryManager;
import com.jess.arms.mvp.BaseModel;
import com.jess.arms.di.scope.FragmentScope;
import javax.inject.Inject;
import com.gingersoft.gsa.cloud.main.mvp.contract.MyContract;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 01/10/2020 15:04
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@FragmentScope
public class MyModel extends BaseModel implements MyContract.Model {
@Inject
Gson mGson;
@Inject
Application mApplication;
@Inject
public MyModel(IRepositoryManager repositoryManager) {
super(repositoryManager);
}
@Override
public void onDestroy() {
super.onDestroy();
this.mGson = null;
this.mApplication = null;
}
}
\ No newline at end of file
package com.gingersoft.gsa.cloud.main.mvp.model;
import android.app.Application;
import com.google.gson.Gson;
import com.jess.arms.integration.IRepositoryManager;
import com.jess.arms.mvp.BaseModel;
import com.jess.arms.di.scope.FragmentScope;
import javax.inject.Inject;
import com.gingersoft.gsa.cloud.main.mvp.contract.ReportContract;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 01/10/2020 15:03
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@FragmentScope
public class ReportModel extends BaseModel implements ReportContract.Model {
@Inject
Gson mGson;
@Inject
Application mApplication;
@Inject
public ReportModel(IRepositoryManager repositoryManager) {
super(repositoryManager);
}
@Override
public void onDestroy() {
super.onDestroy();
this.mGson = null;
this.mApplication = null;
}
}
\ No newline at end of file
package com.gingersoft.gsa.cloud.main.mvp.model.bean;
import com.google.gson.annotations.SerializedName;
import java.util.Map;
/**
* Created by Wyh on 2020/1/10.
*/
public class HomeTurnoverBean {
/**
* success : true
* sysTime : 1578656177759
* data : {"2020-01-09":{"Business_amount":"2734.00","Bill_decimal":"0.00","discount":"-23.00","TipsAmount":"0.00","CreditCardAmount":"0.00","people":"62.00","sales":"2685.00","number_bill":"31.00","billNum_skyOder":"1.00","billPrice_table":"2623.00","billPrice_skyOder":"111.00","billNum_table":"30.00","servicecharge":"72.00"}}
*/
private boolean success;
private long sysTime;
private Map<String, DataBean> data;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public long getSysTime() {
return sysTime;
}
public void setSysTime(long sysTime) {
this.sysTime = sysTime;
}
public Map<String, DataBean> getData() {
return data;
}
public void setData(Map<String, DataBean> data) {
this.data = data;
}
public static class DataBean {
/**
* Business_amount : 2734.00
* Bill_decimal : 0.00
* discount : -23.00
* TipsAmount : 0.00
* CreditCardAmount : 0.00
* people : 62.00
* sales : 2685.00
* number_bill : 31.00
* billNum_skyOder : 1.00
* billPrice_table : 2623.00
* billPrice_skyOder : 111.00
* billNum_table : 30.00
* servicecharge : 72.00
*/
private String Business_amount;
private String Bill_decimal;
private String discount;
private String TipsAmount;
private String CreditCardAmount;
private String people;
private String sales;
private String number_bill;
private String billNum_skyOder;
private String billPrice_table;
private String billPrice_skyOder;
private String billNum_table;
private String servicecharge;
public String getBusiness_amount() {
return Business_amount;
}
public void setBusiness_amount(String Business_amount) {
this.Business_amount = Business_amount;
}
public String getBill_decimal() {
return Bill_decimal;
}
public void setBill_decimal(String Bill_decimal) {
this.Bill_decimal = Bill_decimal;
}
public String getDiscount() {
return discount;
}
public void setDiscount(String discount) {
this.discount = discount;
}
public String getTipsAmount() {
return TipsAmount;
}
public void setTipsAmount(String TipsAmount) {
this.TipsAmount = TipsAmount;
}
public String getCreditCardAmount() {
return CreditCardAmount;
}
public void setCreditCardAmount(String CreditCardAmount) {
this.CreditCardAmount = CreditCardAmount;
}
public String getPeople() {
return people;
}
public void setPeople(String people) {
this.people = people;
}
public String getSales() {
return sales;
}
public void setSales(String sales) {
this.sales = sales;
}
public String getNumber_bill() {
return number_bill;
}
public void setNumber_bill(String number_bill) {
this.number_bill = number_bill;
}
public String getBillNum_skyOder() {
return billNum_skyOder;
}
public void setBillNum_skyOder(String billNum_skyOder) {
this.billNum_skyOder = billNum_skyOder;
}
public String getBillPrice_table() {
return billPrice_table;
}
public void setBillPrice_table(String billPrice_table) {
this.billPrice_table = billPrice_table;
}
public String getBillPrice_skyOder() {
return billPrice_skyOder;
}
public void setBillPrice_skyOder(String billPrice_skyOder) {
this.billPrice_skyOder = billPrice_skyOder;
}
public String getBillNum_table() {
return billNum_table;
}
public void setBillNum_table(String billNum_table) {
this.billNum_table = billNum_table;
}
public String getServicecharge() {
return servicecharge;
}
public void setServicecharge(String servicecharge) {
this.servicecharge = servicecharge;
}
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* 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.gingersoft.gsa.cloud.main.mvp.model.bean;
import com.qmuiteam.qmui.widget.section.QMUISection.Model;
import java.util.Objects;
public class SectionHeader implements Model<SectionHeader> {
private final String text;
public SectionHeader(String text){
this.text = text;
}
public String getText() {
return text;
}
@Override
public SectionHeader cloneForDiff() {
return new SectionHeader(getText());
}
@Override
public boolean isSameItem(SectionHeader other) {
return Objects.equals(text, other.text);
}
@Override
public boolean isSameContent(SectionHeader other) {
return true;
}
}
package com.gingersoft.gsa.cloud.main.mvp.model.bean;
import com.qmuiteam.qmui.widget.section.QMUISection.Model;
import java.util.Objects;
public class SectionItem implements Model<SectionItem> {
private int image;
private String text;
public SectionItem(int image, String text) {
this.image = image;
this.text = text;
}
public String getText() {
return text;
}
public int getImage() {
return image;
}
@Override
public SectionItem cloneForDiff() {
return new SectionItem(getImage(), getText());
}
@Override
public boolean isSameItem(SectionItem other) {
return Objects.equals(text, other.text);
}
@Override
public boolean isSameContent(SectionItem other) {
return true;
}
}
package com.gingersoft.gsa.cloud.main.mvp.model.service;
import com.gingersoft.gsa.cloud.main.mvp.model.bean.HomeTurnoverBean;
import io.reactivex.Observable;
import me.jessyan.retrofiturlmanager.RetrofitUrlManager;
import okhttp3.RequestBody;
import retrofit2.http.Body;
import retrofit2.http.POST;
/**
* Created by Wyh on 2020/1/10.
*/
public interface HomeService {
// @GET("wx/findTransactionSummaryChartLine" + RetrofitUrlManager.IDENTIFICATION_PATH_SIZE + 2)
@POST("wx/doBusiness" + RetrofitUrlManager.IDENTIFICATION_PATH_SIZE + 2)
Observable<HomeTurnoverBean> getRestaurantReport(@Body RequestBody requestBody);
}
package com.gingersoft.gsa.cloud.main.mvp.presenter;
import android.app.Application;
import android.util.Log;
import com.gingersoft.gsa.cloud.base.application.GsaCloudApplication;
import com.gingersoft.gsa.cloud.main.mvp.model.bean.HomeTurnoverBean;
import com.jess.arms.integration.AppManager;
import com.jess.arms.di.scope.FragmentScope;
import com.jess.arms.mvp.BasePresenter;
import com.jess.arms.http.imageloader.ImageLoader;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.schedulers.Schedulers;
import me.jessyan.rxerrorhandler.core.RxErrorHandler;
import me.jessyan.rxerrorhandler.handler.ErrorHandleSubscriber;
import okhttp3.FormBody;
import okhttp3.RequestBody;
import javax.inject.Inject;
import com.gingersoft.gsa.cloud.main.mvp.contract.HomeContract;
import com.jess.arms.utils.RxLifecycleUtils;
import java.util.HashMap;
import java.util.Map;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 01/10/2020 15:02
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@FragmentScope
public class HomePresenter extends BasePresenter<HomeContract.Model, HomeContract.View> {
@Inject
RxErrorHandler mErrorHandler;
@Inject
Application mApplication;
@Inject
ImageLoader mImageLoader;
@Inject
AppManager mAppManager;
@Inject
public HomePresenter(HomeContract.Model model, HomeContract.View rootView) {
super(model, rootView);
}
@Override
public void onDestroy() {
super.onDestroy();
this.mErrorHandler = null;
this.mAppManager = null;
this.mImageLoader = null;
this.mApplication = null;
}
public void getRestaurantReport(String restaurantId){
RequestBody requestBody = new FormBody.Builder()
.add("restaurantId", restaurantId)
.add("startTime", "2020-01-09")
.add("endTime", "2020-01-10")
.build();
mModel.getRestaurantReport(requestBody)
.subscribeOn(Schedulers.io())
.doOnSubscribe(disposable -> mRootView.showLoading(""))
.subscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
.doAfterTerminate(() -> mRootView.hideLoading())
.compose(RxLifecycleUtils.bindToLifecycle(mRootView))
.subscribe(new ErrorHandleSubscriber<HomeTurnoverBean>(mErrorHandler) {
@Override
public void onNext(@NonNull HomeTurnoverBean info) {
mRootView.loadBusinessInfo(info.getData());
}
});
}
}
package com.gingersoft.gsa.cloud.main.mvp.presenter;
import android.app.Application;
import com.jess.arms.integration.AppManager;
import com.jess.arms.di.scope.FragmentScope;
import com.jess.arms.mvp.BasePresenter;
import com.jess.arms.http.imageloader.ImageLoader;
import me.jessyan.rxerrorhandler.core.RxErrorHandler;
import javax.inject.Inject;
import com.gingersoft.gsa.cloud.main.mvp.contract.MyContract;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 01/10/2020 15:04
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@FragmentScope
public class MyPresenter extends BasePresenter<MyContract.Model, MyContract.View> {
@Inject
RxErrorHandler mErrorHandler;
@Inject
Application mApplication;
@Inject
ImageLoader mImageLoader;
@Inject
AppManager mAppManager;
@Inject
public MyPresenter(MyContract.Model model, MyContract.View rootView) {
super(model, rootView);
}
@Override
public void onDestroy() {
super.onDestroy();
this.mErrorHandler = null;
this.mAppManager = null;
this.mImageLoader = null;
this.mApplication = null;
}
}
package com.gingersoft.gsa.cloud.main.mvp.presenter;
import android.app.Application;
import com.jess.arms.integration.AppManager;
import com.jess.arms.di.scope.FragmentScope;
import com.jess.arms.mvp.BasePresenter;
import com.jess.arms.http.imageloader.ImageLoader;
import me.jessyan.rxerrorhandler.core.RxErrorHandler;
import javax.inject.Inject;
import com.gingersoft.gsa.cloud.main.mvp.contract.ReportContract;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 01/10/2020 15:03
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
@FragmentScope
public class ReportPresenter extends BasePresenter<ReportContract.Model, ReportContract.View> {
@Inject
RxErrorHandler mErrorHandler;
@Inject
Application mApplication;
@Inject
ImageLoader mImageLoader;
@Inject
AppManager mAppManager;
@Inject
public ReportPresenter(ReportContract.Model model, ReportContract.View rootView) {
super(model, rootView);
}
@Override
public void onDestroy() {
super.onDestroy();
this.mErrorHandler = null;
this.mAppManager = null;
this.mImageLoader = null;
this.mApplication = null;
}
}
......@@ -3,28 +3,31 @@ package com.gingersoft.gsa.cloud.main.mvp.ui.activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.BaseAdapter;
import android.widget.GridView;
import com.billy.cc.core.component.CC;
import com.gingersoft.gsa.cloud.database.bean.Function;
import com.gingersoft.gsa.cloud.database.utils.FunctionDaoUtils;
import com.gingersoft.gsa.cloud.base.qmui.arch.QMUIFragmentPagerAdapter;
import com.gingersoft.gsa.cloud.main.R;
import com.gingersoft.gsa.cloud.main.R2;
import com.gingersoft.gsa.cloud.main.di.component.DaggerMainComponent;
import com.gingersoft.gsa.cloud.main.mvp.contract.MainContract;
import com.gingersoft.gsa.cloud.main.mvp.presenter.MainPresenter;
import com.jess.arms.base.BaseActivity;
import com.gingersoft.gsa.cloud.main.mvp.ui.fragment.HomeFragment;
import com.gingersoft.gsa.cloud.main.mvp.ui.fragment.MyFragment;
import com.gingersoft.gsa.cloud.main.mvp.ui.fragment.ReportFragment;
import com.jess.arms.base.BaseFragmentActivity;
import com.jess.arms.di.component.AppComponent;
import com.jess.arms.utils.ArmsUtils;
import com.qmuiteam.qmui.widget.QMUITopBar;
import java.util.List;
import com.qmuiteam.qmui.util.QMUIDisplayHelper;
import com.qmuiteam.qmui.widget.QMUIViewPager;
import com.qmuiteam.qmui.widget.tab.QMUITab;
import com.qmuiteam.qmui.widget.tab.QMUITabBuilder;
import com.qmuiteam.qmui.widget.tab.QMUITabSegment;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import androidx.fragment.app.Fragment;
import butterknife.BindView;
import static com.jess.arms.utils.Preconditions.checkNotNull;
......@@ -40,13 +43,16 @@ import static com.jess.arms.utils.Preconditions.checkNotNull;
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
public class MainActivity extends BaseActivity<MainPresenter> implements MainContract.View {
@BindView(R2.id.topbar)
QMUITopBar mTopBar;
@BindView(R2.id.gv_function)
GridView gv_function;
public class MainActivity extends BaseFragmentActivity<MainPresenter> implements MainContract.View {
// @BindView(R2.id.topbar)
// QMUITopBar mTopBar;
// @BindView(R2.id.gv_function)
// GridView gv_function;
@BindView(R.id.main_pager)
QMUIViewPager mViewPager;
@BindView(R.id.main_tabs)
QMUITabSegment mTabSegment;
@Override
public void setupActivityComponent(@NonNull AppComponent appComponent) {
......@@ -65,11 +71,70 @@ public class MainActivity extends BaseActivity<MainPresenter> implements MainCon
@Override
public void initData(@Nullable Bundle savedInstanceState) {
initTabs();
initPagers();
// mPresenter.initAdapter(this);
// mPresenter.initItemClickListener(this);
}
private void initPagers() {
QMUIFragmentPagerAdapter pagerAdapter = new QMUIFragmentPagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment createFragment(int position) {
switch (position) {
case 0:
return HomeFragment.newInstance();
case 1:
return ReportFragment.newInstance();
case 2:
default:
return MyFragment.newInstance();
}
}
@Override
public int getCount() {
return 3;
}
@Override
public CharSequence getPageTitle(int position) {
return "";
}
};
mViewPager.setAdapter(pagerAdapter);
mTabSegment.setupWithViewPager(mViewPager, false);
mPresenter.initAdapter(this);
mPresenter.initItemClickListener(this);
}
private void initTabs() {
QMUITabBuilder builder = mTabSegment.tabBuilder();
builder
.setSelectedIconScale(1.0f)
.setTextSize(QMUIDisplayHelper.sp2px(mContext, 14), QMUIDisplayHelper.sp2px(mContext, 14))
.setNormalIconSizeInfo(75, 75)
.setDynamicChangeIconColor(false);
QMUITab home = builder
.setNormalDrawable(ContextCompat.getDrawable(mContext, R.drawable.ic_normal_main))
.setSelectedDrawable(ContextCompat.getDrawable(mContext, R.drawable.ic_selected_main))
.setText(getString(R.string.main))
.build(mContext);
QMUITab report = builder
.setNormalDrawable(ContextCompat.getDrawable(mContext, R.drawable.ic_normal_report))
.setSelectedDrawable(ContextCompat.getDrawable(mContext, R.drawable.ic_selected_report))
.setText(getString(R.string.report))
.build(mContext);
QMUITab my = builder
.setNormalDrawable(ContextCompat.getDrawable(mContext, R.drawable.ic_normal_main))
.setSelectedDrawable(ContextCompat.getDrawable(mContext, R.drawable.ic_selected_my))
.setText(getString(R.string.my))
.build(mContext);
mTabSegment.addTab(home)
.addTab(report)
.addTab(my);
}
@Override
public void initIntent() {
......@@ -78,18 +143,18 @@ public class MainActivity extends BaseActivity<MainPresenter> implements MainCon
@Override
public void initTopBar() {
mTopBar.setBackgroundColor(ContextCompat.getColor(this, R.color.theme_color));
mTopBar.addLeftBackImageButton().setVisibility(View.INVISIBLE);
mTopBar.setTitle("首頁");
mTopBar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CC.obtainBuilder("Component.Table")
.setActionName("showTableActivity")
.build()
.call();
}
});
// mTopBar.setBackgroundColor(ContextCompat.getColor(this, R.color.theme_color));
// mTopBar.addLeftBackImageButton().setVisibility(View.INVISIBLE);
// mTopBar.setTitle("首頁");
// mTopBar.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// CC.obtainBuilder("Component.Table")
// .setActionName("showTableActivity")
// .build()
// .call();
// }
// });
}
@Override
......@@ -136,11 +201,12 @@ public class MainActivity extends BaseActivity<MainPresenter> implements MainCon
@Override
public void setFunctionAdapter(BaseAdapter adapter) {
gv_function.setAdapter(adapter);
// gv_function.setAdapter(adapter);
}
private long mExitTime;
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
......
package com.gingersoft.gsa.cloud.main.mvp.ui.adapter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.gingersoft.gsa.cloud.main.R;
import com.gingersoft.gsa.cloud.main.mvp.model.bean.SectionHeader;
import com.gingersoft.gsa.cloud.main.mvp.model.bean.SectionItem;
import com.gingersoft.gsa.cloud.main.mvp.ui.view.HomeFunctionHead;
import com.qmuiteam.qmui.widget.section.QMUIDefaultStickySectionAdapter;
import com.qmuiteam.qmui.widget.section.QMUISection;
import com.qmuiteam.qmui.widget.section.QMUIStickySectionAdapter;
import androidx.annotation.NonNull;
import butterknife.BindView;
import butterknife.ButterKnife;
/**
* Created by Wyh on 2020/1/10.
*/
public class HomeFunctionAdapter extends QMUIDefaultStickySectionAdapter<SectionHeader, SectionItem> {
@NonNull
@Override
protected QMUIStickySectionAdapter.ViewHolder onCreateSectionHeaderViewHolder(@NonNull ViewGroup viewGroup) {
return new QMUIStickySectionAdapter.ViewHolder(new HomeFunctionHead(viewGroup.getContext()));
}
@NonNull
@Override
protected ViewHolder onCreateSectionItemViewHolder(@NonNull ViewGroup viewGroup) {
return new ViewHolder(View.inflate(viewGroup.getContext(), R.layout.main_home_funcation_item, null));
}
@Override
protected void onBindSectionHeader(QMUIStickySectionAdapter.ViewHolder holder, int position, QMUISection<SectionHeader, SectionItem> section) {
super.onBindSectionHeader(holder, position, section);
HomeFunctionHead itemView = (HomeFunctionHead) holder.itemView;
itemView.render(section.getHeader(), section.isFold());
}
@Override
protected void onBindSectionItem(QMUIStickySectionAdapter.ViewHolder holder, int position, QMUISection<SectionHeader, SectionItem> section, int itemIndex) {
super.onBindSectionItem(holder, position, section, itemIndex);
ViewHolder viewHolder = (ViewHolder) holder;
viewHolder.ivFun.setImageResource(section.getItemAt(itemIndex).getImage());
viewHolder.tvFun.setText(section.getItemAt(itemIndex).getText());
}
class ViewHolder extends QMUIStickySectionAdapter.ViewHolder {
@BindView(R.id.iv_main_home_item_function_icon)
ImageView ivFun;//功能圖標
@BindView(R.id.tv_main_home_item_function_name)
TextView tvFun;//功能名
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
//package com.gingersoft.gsa.cloud.main.mvp.ui.adapter;
//
//import android.annotation.SuppressLint;
//import android.view.View;
//import android.view.ViewGroup;
//
//import com.qmuiteam.qmui.widget.QMUIPagerAdapter;
//
//import androidx.annotation.NonNull;
//import androidx.fragment.app.Fragment;
//import androidx.fragment.app.FragmentManager;
//import androidx.fragment.app.FragmentTransaction;
//
///**
// * Created by Wyh on 2020/1/10.
// */
//public abstract class MainPagerAdapter extends QMUIPagerAdapter {
//
// private final FragmentManager mFragmentManager;
// private FragmentTransaction mCurrentTransaction;
// private Fragment mCurrentPrimaryItem = null;
//
// public QMUIFragmentPagerAdapter(@NonNull FragmentManager fm) {
// mFragmentManager = fm;
// }
//
// public abstract QMUIFragment createFragment(int position);
//
// @Override
// public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
// return view == ((Fragment) object).getView();
// }
//
// @SuppressLint("CommitTransaction")
// @Override
// @NonNull
// protected Object hydrate(@NonNull ViewGroup container, int position) {
// String name = makeFragmentName(container.getId(), position);
// if (mCurrentTransaction == null) {
// mCurrentTransaction = mFragmentManager.beginTransaction();
// }
// Fragment fragment = mFragmentManager.findFragmentByTag(name);
// if (fragment != null) {
// return fragment;
// }
// return createFragment(position);
// }
//
// @SuppressLint("CommitTransaction")
// @Override
// protected void populate(@NonNull ViewGroup container, @NonNull Object item, int position) {
// String name = makeFragmentName(container.getId(), position);
// if (mCurrentTransaction == null) {
// mCurrentTransaction = mFragmentManager.beginTransaction();
// }
// Fragment fragment = mFragmentManager.findFragmentByTag(name);
// if (fragment != null) {
// mCurrentTransaction.attach(fragment);
// if (fragment.getView() != null && fragment.getView().getWidth() == 0) {
// fragment.getView().requestLayout();
// }
// } else {
// fragment = (Fragment) item;
// mCurrentTransaction.add(container.getId(), fragment, name);
// }
// if (fragment != mCurrentPrimaryItem) {
// fragment.setMenuVisibility(false);
// fragment.setUserVisibleHint(false);
// }
// }
//
// @SuppressLint("CommitTransaction")
// @Override
// protected void destroy(@NonNull ViewGroup container, int position, @NonNull Object object) {
// if (mCurrentTransaction == null) {
// mCurrentTransaction = mFragmentManager.beginTransaction();
// }
// mCurrentTransaction.detach((Fragment) object);
// }
//
// @Override
// public int getCount() {
// return 0;
// }
//
// @Override
// public void startUpdate(@NonNull ViewGroup container) {
// if (container.getId() == View.NO_ID) {
// throw new IllegalStateException("ViewPager with adapter " + this
// + " requires a view id");
// }
// }
//
// @Override
// public void finishUpdate(@NonNull ViewGroup container) {
// if (mCurrentTransaction != null) {
// mCurrentTransaction.commitNowAllowingStateLoss();
// mCurrentTransaction = null;
// }
// }
//
// @Override
// public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
// Fragment fragment = (Fragment) object;
// if (fragment != mCurrentPrimaryItem) {
// if (mCurrentPrimaryItem != null) {
// mCurrentPrimaryItem.setMenuVisibility(false);
// mCurrentPrimaryItem.setUserVisibleHint(false);
// }
// fragment.setMenuVisibility(true);
// fragment.setUserVisibleHint(true);
// mCurrentPrimaryItem = fragment;
// }
// }
//
// private String makeFragmentName(int viewId, long id) {
// return "QMUIFragmentPagerAdapter:" + viewId + ":" + id;
// }
//}
package com.gingersoft.gsa.cloud.main.mvp.ui.fragment;
import android.content.Intent;
import android.os.Bundle;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.gingersoft.gsa.cloud.base.utils.time.TimeUtils;
import com.gingersoft.gsa.cloud.main.di.component.DaggerHomeComponent;
import com.gingersoft.gsa.cloud.main.mvp.model.bean.HomeTurnoverBean;
import com.gingersoft.gsa.cloud.main.mvp.model.bean.SectionHeader;
import com.gingersoft.gsa.cloud.main.mvp.model.bean.SectionItem;
import com.gingersoft.gsa.cloud.main.mvp.ui.adapter.HomeFunctionAdapter;
import com.jess.arms.base.BaseFragment;
import com.jess.arms.di.component.AppComponent;
import com.jess.arms.utils.ArmsUtils;
import com.gingersoft.gsa.cloud.main.mvp.contract.HomeContract;
import com.gingersoft.gsa.cloud.main.mvp.presenter.HomePresenter;
import com.gingersoft.gsa.cloud.main.R;
import com.qmuiteam.qmui.widget.QMUITopBarLayout;
import com.qmuiteam.qmui.widget.section.QMUISection;
import com.qmuiteam.qmui.widget.section.QMUIStickySectionAdapter;
import com.qmuiteam.qmui.widget.section.QMUIStickySectionLayout;
import org.w3c.dom.Text;
import java.util.ArrayList;
import java.util.Map;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import retrofit2.http.Body;
import static com.jess.arms.utils.Preconditions.checkNotNull;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 01/10/2020 15:02
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
* 首頁
*/
public class HomeFragment extends BaseFragment<HomePresenter> implements HomeContract.View, View.OnClickListener {
@BindView(R.id.main_home_bar)
QMUITopBarLayout mTopBar;
@BindView(R.id.tv_main_home_today_turnover)
TextView tvTurnover;
@BindView(R.id.tv_main_home_cutoff_text)
TextView tvCutoff;
@BindView(R.id.tv_main_home_total_amount_project)
TextView tvProjectTotalAmount;
@BindView(R.id.tv_main_home_consumers_number)
TextView tvConsumersNum;
@BindView(R.id.tv_main_home_bill_number)
TextView tvBillNum;
@BindView(R.id.section_layout)
QMUIStickySectionLayout mSectionLayout;
private RecyclerView.LayoutManager mLayoutManager;
private HomeFunctionAdapter mAdapter;
public static HomeFragment newInstance() {
HomeFragment fragment = new HomeFragment();
return fragment;
}
@Override
public void setupFragmentComponent(@NonNull AppComponent appComponent) {
DaggerHomeComponent //如找不到该类,请编译一下项目
.builder()
.appComponent(appComponent)
.view(this)
.build()
.inject(this);
}
@Override
public View initView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.main_fragment_home, container, false);
}
@Override
public void initData(@Nullable Bundle savedInstanceState) {
mPresenter.getRestaurantReport("26");
initTopBar();
initStickyLayout();
}
private void initTopBar() {
mTopBar.addLeftImageButton(R.drawable.ic_main_home_refresh, R.id.main_home_refresh);
mTopBar.setTitle("店鋪名稱");
mTopBar.addRightImageButton(R.drawable.selector_msg, R.id.main_home_msg).setOnClickListener(this);
}
/**
* 初始化功能列表
*/
private void initStickyLayout() {
mLayoutManager = createLayoutManager();
mSectionLayout.setLayoutManager(mLayoutManager);
mAdapter = new HomeFunctionAdapter();
mAdapter.setCallback(new QMUIStickySectionAdapter.Callback<SectionHeader, SectionItem>() {
@Override
public void loadMore(QMUISection<SectionHeader, SectionItem> section, boolean loadMoreBefore) {
}
@Override
public void onItemClick(QMUIStickySectionAdapter.ViewHolder holder, int position) {
}
@Override
public boolean onItemLongClick(QMUIStickySectionAdapter.ViewHolder holder, int position) {
return false;
}
});
String[] title = new String[]{"點餐", "管理", "員工"};
mSectionLayout.setAdapter(mAdapter, true);
ArrayList<QMUISection<SectionHeader, SectionItem>> list = new ArrayList<>();
for (String s : title) {
list.add(createSection(s));
}
mAdapter.setData(list);
}
private QMUISection<SectionHeader, SectionItem> createSection(String headerText) {
SectionHeader header = new SectionHeader(headerText);
ArrayList<SectionItem> contents = new ArrayList<>();
for (int i = 0; i < 5; i++) {
contents.add(new SectionItem(R.drawable.ic_dining_table, "item " + i));
}
QMUISection<SectionHeader, SectionItem> section = new QMUISection<>(header, contents, false);
// if test load more, you can open the code
// section.setExistAfterDataToLoad(true);
// section.setExistBeforeDataToLoad(true);
return section;
}
private RecyclerView.LayoutManager createLayoutManager() {
final GridLayoutManager layoutManager = new GridLayoutManager(getContext(), 4);
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int i) {
return mAdapter.getItemIndex(i) < 0 ? layoutManager.getSpanCount() : 1;
}
});
return layoutManager;
}
@Override
public void setData(@Nullable Object data) {
}
@Override
public void showLoading(String message) {
}
@Override
public void hideLoading() {
}
@Override
public void showMessage(@NonNull String message) {
checkNotNull(message);
ArmsUtils.snackbarText(message);
}
@Override
public void launchActivity(@NonNull Intent intent) {
checkNotNull(intent);
ArmsUtils.startActivity(intent);
}
@Override
public void killMyself() {
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.main_home_refresh:
//刷新
break;
case R.id.main_home_msg:
//消息
break;
}
}
@Override
public void loadBusinessInfo(Map<String, HomeTurnoverBean.DataBean> data) {
// tvTurnover.setText(data.get("2020-01-09").getSales());//TimeUtils.getCurrentTimeInString(TimeUtils.DATE_FORMAT_DATE)
}
}
package com.gingersoft.gsa.cloud.main.mvp.ui.fragment;
import android.content.Intent;
import android.os.Bundle;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.gingersoft.gsa.cloud.main.R;
import com.gingersoft.gsa.cloud.main.di.component.DaggerMyComponent;
import com.gingersoft.gsa.cloud.main.mvp.contract.MyContract;
import com.gingersoft.gsa.cloud.main.mvp.presenter.MyPresenter;
import com.jess.arms.base.BaseFragment;
import com.jess.arms.di.component.AppComponent;
import com.jess.arms.utils.ArmsUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import static com.jess.arms.utils.Preconditions.checkNotNull;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 01/10/2020 15:04
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
*/
public class MyFragment extends BaseFragment<MyPresenter> implements MyContract.View {
public static MyFragment newInstance() {
MyFragment fragment = new MyFragment();
return fragment;
}
@Override
public void setupFragmentComponent(@NonNull AppComponent appComponent) {
DaggerMyComponent //如找不到该类,请编译一下项目
.builder()
.appComponent(appComponent)
.view(this)
.build()
.inject(this);
}
@Override
public View initView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.main_fragment_my, container, false);
}
@Override
public void initData(@Nullable Bundle savedInstanceState) {
}
/**
* 通过此方法可以使 Fragment 能够与外界做一些交互和通信, 比如说外部的 Activity 想让自己持有的某个 Fragment 对象执行一些方法,
* 建议在有多个需要与外界交互的方法时, 统一传 {@link Message}, 通过 what 字段来区分不同的方法, 在 {@link #setData(Object)}
* 方法中就可以 {@code switch} 做不同的操作, 这样就可以用统一的入口方法做多个不同的操作, 可以起到分发的作用
* <p>
* 调用此方法时请注意调用时 Fragment 的生命周期, 如果调用 {@link #setData(Object)} 方法时 {@link Fragment#onCreate(Bundle)} 还没执行
* 但在 {@link #setData(Object)} 里却调用了 Presenter 的方法, 是会报空的, 因为 Dagger 注入是在 {@link Fragment#onCreate(Bundle)} 方法中执行的
* 然后才创建的 Presenter, 如果要做一些初始化操作,可以不必让外部调用 {@link #setData(Object)}, 在 {@link #initData(Bundle)} 中初始化就可以了
* <p>
* Example usage:
* <pre>
* public void setData(@Nullable Object data) {
* if (data != null && data instanceof Message) {
* switch (((Message) data).what) {
* case 0:
* loadData(((Message) data).arg1);
* break;
* case 1:
* refreshUI();
* break;
* default:
* //do something
* break;
* }
* }
* }
*
* // call setData(Object):
* Message data = new Message();
* data.what = 0;
* data.arg1 = 1;
* fragment.setData(data);
* </pre>
*
* @param data 当不需要参数时 {@code data} 可以为 {@code null}
*/
@Override
public void setData(@Nullable Object data) {
}
@Override
public void showLoading(String message) {
}
@Override
public void hideLoading() {
}
@Override
public void showMessage(@NonNull String message) {
checkNotNull(message);
ArmsUtils.snackbarText(message);
}
@Override
public void launchActivity(@NonNull Intent intent) {
checkNotNull(intent);
ArmsUtils.startActivity(intent);
}
@Override
public void killMyself() {
}
}
package com.gingersoft.gsa.cloud.main.mvp.ui.fragment;
import android.content.Intent;
import android.os.Bundle;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.gingersoft.gsa.cloud.main.R;
import com.gingersoft.gsa.cloud.main.di.component.DaggerReportComponent;
import com.gingersoft.gsa.cloud.main.mvp.contract.ReportContract;
import com.gingersoft.gsa.cloud.main.mvp.presenter.ReportPresenter;
import com.jess.arms.base.BaseFragment;
import com.jess.arms.di.component.AppComponent;
import com.jess.arms.utils.ArmsUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import static com.jess.arms.utils.Preconditions.checkNotNull;
/**
* ================================================
* Description:
* <p>
* Created by MVPArmsTemplate on 01/10/2020 15:03
* <a href="mailto:jess.yan.effort@gmail.com">Contact me</a>
* <a href="https://github.com/JessYanCoding">Follow me</a>
* <a href="https://github.com/JessYanCoding/MVPArms">Star me</a>
* <a href="https://github.com/JessYanCoding/MVPArms/wiki">See me</a>
* <a href="https://github.com/JessYanCoding/MVPArmsTemplate">模版请保持更新</a>
* ================================================
* 報表
*/
public class ReportFragment extends BaseFragment<ReportPresenter> implements ReportContract.View {
public static ReportFragment newInstance() {
ReportFragment fragment = new ReportFragment();
return fragment;
}
@Override
public void setupFragmentComponent(@NonNull AppComponent appComponent) {
DaggerReportComponent //如找不到该类,请编译一下项目
.builder()
.appComponent(appComponent)
.view(this)
.build()
.inject(this);
}
@Override
public View initView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.main_fragment_report, container, false);
}
@Override
public void initData(@Nullable Bundle savedInstanceState) {
}
/**
* 通过此方法可以使 Fragment 能够与外界做一些交互和通信, 比如说外部的 Activity 想让自己持有的某个 Fragment 对象执行一些方法,
* 建议在有多个需要与外界交互的方法时, 统一传 {@link Message}, 通过 what 字段来区分不同的方法, 在 {@link #setData(Object)}
* 方法中就可以 {@code switch} 做不同的操作, 这样就可以用统一的入口方法做多个不同的操作, 可以起到分发的作用
* <p>
* 调用此方法时请注意调用时 Fragment 的生命周期, 如果调用 {@link #setData(Object)} 方法时 {@link Fragment#onCreate(Bundle)} 还没执行
* 但在 {@link #setData(Object)} 里却调用了 Presenter 的方法, 是会报空的, 因为 Dagger 注入是在 {@link Fragment#onCreate(Bundle)} 方法中执行的
* 然后才创建的 Presenter, 如果要做一些初始化操作,可以不必让外部调用 {@link #setData(Object)}, 在 {@link #initData(Bundle)} 中初始化就可以了
* <p>
* Example usage:
* <pre>
* public void setData(@Nullable Object data) {
* if (data != null && data instanceof Message) {
* switch (((Message) data).what) {
* case 0:
* loadData(((Message) data).arg1);
* break;
* case 1:
* refreshUI();
* break;
* default:
* //do something
* break;
* }
* }
* }
*
* // call setData(Object):
* Message data = new Message();
* data.what = 0;
* data.arg1 = 1;
* fragment.setData(data);
* </pre>
*
* @param data 当不需要参数时 {@code data} 可以为 {@code null}
*/
@Override
public void setData(@Nullable Object data) {
}
@Override
public void showLoading(String message) {
}
@Override
public void hideLoading() {
}
@Override
public void showMessage(@NonNull String message) {
checkNotNull(message);
ArmsUtils.snackbarText(message);
}
@Override
public void launchActivity(@NonNull Intent intent) {
checkNotNull(intent);
ArmsUtils.startActivity(intent);
}
@Override
public void killMyself() {
}
}
package com.gingersoft.gsa.cloud.main.mvp.ui.view;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.gingersoft.gsa.cloud.main.R;
import com.gingersoft.gsa.cloud.main.mvp.model.bean.SectionHeader;
import com.qmuiteam.qmui.util.QMUIDisplayHelper;
import androidx.annotation.Nullable;
/**
* Created by Wyh on 2020/1/10.
*/
public class HomeFunctionHead extends LinearLayout {
private TextView mTitleTv;
// private ImageView mArrowView;
// private int headerHeight = QMUIDisplayHelper.dp2px(getContext(), 56);
public HomeFunctionHead(Context context) {
this(context, null);
}
public HomeFunctionHead(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
setOrientation(LinearLayout.HORIZONTAL);
setGravity(Gravity.CENTER_VERTICAL);
setBackgroundColor(Color.WHITE);
int paddingHor = QMUIDisplayHelper.dp2px(context, 5);
int paddingVer = QMUIDisplayHelper.dp2px(context, 5);
mTitleTv = new TextView(getContext());
mTitleTv.setTextSize(14);
mTitleTv.setTypeface(Typeface.DEFAULT_BOLD);
mTitleTv.setTextColor(getColor(context, R.color.theme_color));
mTitleTv.setPadding(paddingHor, paddingVer, paddingHor, paddingVer);
addView(mTitleTv, new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f));
setBackgroundColor(getColor(context, R.color.main_home_function_head_bg));
// mArrowView = new AppCompatImageView(context);
// mArrowView.setImageDrawable(QMUIResHelper.getAttrDrawable(getContext(), R.attr.qmui_common_list_item_chevron));
// mArrowView.setScaleType(ImageView.ScaleType.CENTER);
// addView(mArrowView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
private int getColor(Context context, int colorId) {
return context.getResources().getColor(colorId);
}
// public ImageView getArrowView() {
// return mArrowView;
// }
public void render(SectionHeader header, boolean isFold) {
mTitleTv.setText(header.getText());
// mArrowView.setRotation(isFold ? 0f : 90f);
}
//
// @Override
// protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(headerHeight, MeasureSpec.EXACTLY));
// }
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_main_home_msg_selected" android:state_pressed="true" />
<item android:drawable="@drawable/ic_main_home_msg_selected" android:state_checkable="true" />
<item android:drawable="@drawable/ic_main_home_msg_normal" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<com.qmuiteam.qmui.widget.QMUIWindowInsetLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
android:background="?attr/app_primary_color">
<com.qmuiteam.qmui.widget.QMUITopBar
android:id="@+id/topbar"
android:layout_width="match_parent"
android:layout_height="?attr/qmui_topbar_height"
app:layout_constraintTop_toTopOf="parent"/>
<com.gingersoft.gsa.cloud.base.widget.NoScrollGridView
android:id="@+id/gv_function"
<com.qmuiteam.qmui.widget.QMUIViewPager
android:id="@+id/main_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/qmui_topbar_height"
android:background="@color/theme_white_color"
android:numColumns="2" />
android:layout_marginBottom="@dimen/head_height"
android:background="?attr/app_content_bg_color"
android:fitsSystemWindows="true" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.qmuiteam.qmui.widget.tab.QMUITabSegment
android:id="@+id/main_tabs"
android:layout_width="match_parent"
android:layout_height="@dimen/head_height"
android:layout_gravity="bottom"
android:textSize="12sp"
android:background="@color/white"
app:qmui_tab_icon_position="top"
app:qmui_tab_normal_text_size="14sp"
app:qmui_tab_selected_text_size="16sp" />
</com.qmuiteam.qmui.widget.QMUIWindowInsetLayout>
<?xml version="1.0" encoding="utf-8"?>
<com.qmuiteam.qmui.widget.QMUIWindowInsetLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/qmui_config_color_white">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- 標題欄-->
<com.qmuiteam.qmui.widget.QMUITopBarLayout
android:id="@+id/main_home_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/head_height"
android:fitsSystemWindows="true" />
<!-- 營業額-->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/main_home_business_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_20"
android:layout_marginBottom="@dimen/dp_20"
android:paddingLeft="@dimen/dp_18"
android:paddingRight="@dimen/dp_18">
<TextView
android:id="@+id/tv_main_home_today_turnover_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/turnover_today"
android:textColor="@color/normal_color"
android:textSize="@dimen/sp_16"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_main_home_today_turnover"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="96,999,9"
android:textColor="@color/normal_color"
android:textSize="@dimen/sp_20"
app:layout_constraintBottom_toBottomOf="@id/tv_main_home_cutoff_text"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_main_home_today_turnover_text" />
<TextView
android:id="@+id/tv_main_home_cutoff_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_10"
android:text="@string/cutoff"
android:textColor="@color/normal_color"
android:textSize="@dimen/sp_16"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_main_home_today_turnover_text" />
<View
android:id="@+id/line_main_home_turnover"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_1"
android:layout_marginTop="@dimen/dp_15"
android:background="@color/line_color"
app:layout_constraintTop_toBottomOf="@id/tv_main_home_cutoff_text" />
<TextView
android:id="@+id/tv_main_home_total_amount_project_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_15"
android:gravity="center"
android:text="@string/total_amount_of_project"
android:textColor="@color/normal_color"
android:textSize="@dimen/sp_16"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/tv_main_home_consumers_number_text"
app:layout_constraintTop_toBottomOf="@id/line_main_home_turnover" />
<TextView
android:id="@+id/tv_main_home_consumers_number_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/number_of_consumers"
android:textColor="@color/normal_color"
android:textSize="@dimen/sp_16"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/tv_main_home_total_amount_project_text"
app:layout_constraintRight_toLeftOf="@id/tv_main_home_bill_number_text"
app:layout_constraintTop_toTopOf="@id/tv_main_home_total_amount_project_text" />
<TextView
android:id="@+id/tv_main_home_bill_number_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/bill_number"
android:textColor="@color/normal_color"
android:textSize="@dimen/sp_16"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/tv_main_home_consumers_number_text"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/tv_main_home_total_amount_project_text" />
<TextView
android:id="@+id/tv_main_home_total_amount_project"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_5"
android:text="98,568,0"
android:textColor="@color/normal_color"
android:textSize="@dimen/sp_16"
app:layout_constraintLeft_toLeftOf="@id/tv_main_home_total_amount_project_text"
app:layout_constraintRight_toRightOf="@id/tv_main_home_total_amount_project_text"
app:layout_constraintTop_toBottomOf="@id/tv_main_home_total_amount_project_text" />
<TextView
android:id="@+id/tv_main_home_consumers_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2812"
android:textColor="@color/normal_color"
android:textSize="@dimen/sp_16"
app:layout_constraintLeft_toLeftOf="@id/tv_main_home_consumers_number_text"
app:layout_constraintRight_toRightOf="@id/tv_main_home_consumers_number_text"
app:layout_constraintTop_toBottomOf="@id/tv_main_home_consumers_number_text"
app:layout_constraintTop_toTopOf="@id/tv_main_home_total_amount_project" />
<TextView
android:id="@+id/tv_main_home_bill_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="198"
android:textColor="@color/normal_color"
android:textSize="@dimen/sp_16"
app:layout_constraintLeft_toLeftOf="@id/tv_main_home_bill_number_text"
app:layout_constraintRight_toRightOf="@id/tv_main_home_bill_number_text"
app:layout_constraintTop_toBottomOf="@id/tv_main_home_bill_number_text"
app:layout_constraintTop_toTopOf="@id/tv_main_home_total_amount_project" />
</androidx.constraintlayout.widget.ConstraintLayout>
<!-- 功能列表-->
<com.qmuiteam.qmui.widget.section.QMUIStickySectionLayout
android:id="@+id/section_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</com.qmuiteam.qmui.widget.QMUIWindowInsetLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我的" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="報表" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:paddingTop="@dimen/dp_10"
android:paddingBottom="@dimen/dp_10">
<ImageView
android:id="@+id/iv_main_home_item_function_icon"
android:layout_width="@dimen/dp_50"
android:layout_height="@dimen/dp_50"
android:src="@drawable/ic_dining_table" />
<TextView
android:id="@+id/tv_main_home_item_function_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="餐檯模式"
android:textColor="@color/normal_color"
android:textSize="@dimen/sp_14" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="main_home_refresh" type="id"/>
<item name="main_home_msg" type="id"/>
</resources>
\ No newline at end of file
<resources>
<string name="main_app_name">GSA-Cloud</string>
<string name="main">首頁</string>
<string name="report">报表</string>
<string name="my">我的</string>
<string name="turnover_today">今日營業額($)</string>
<string name="cutoff">截止%1$s</string>
<string name="total_amount_of_project">項目總金額</string>
<string name="number_of_consumers">消費人數</string>
<string name="bill_number">賬單數</string>
<string name="main_action_settings">Settings</string>
<string name="configuration">配置</string>
......
......@@ -3,11 +3,16 @@ package com.joe.print.print;
import android.content.Context;
import android.graphics.Bitmap;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.joe.print.LayoutToBitmapUtils;
import com.joe.print.R;
import com.joe.print.utils.ImageUtils;
import com.joe.print.adapter.BillAdapter;
import com.joe.print.adapter.FoodAdapter;
import com.joe.print.bean.BillingBean;
import com.joe.print.bean.FoodBean;
import com.joe.print.utils.BitmapUtil;
import java.util.ArrayList;
import java.util.List;
......@@ -17,6 +22,8 @@ import am.util.printer.PrinterUtils;
import am.util.printer.PrinterWriter;
import am.util.printer.PrinterWriter58mm;
import am.util.printer.PrinterWriter80mm;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
/**
* Created by Wyh on 2020/1/9.
......@@ -44,11 +51,50 @@ public class SendPrint implements PrintDataMaker {
data.add(printer.getDataAndReset());
View view = LinearLayout.inflate(context, R.layout.print_layout_print, null);
LayoutToBitmapUtils.layoutView(context, view);//先测量
Bitmap bitmap = LayoutToBitmapUtils.loadBitmapFromView(view);//轉bitmap
ArrayList<byte[]> image1 = PrinterUtils.decodeBitmapToDataList(ImageUtils.zoomDrawable(bitmap, width, bitmap.getHeight()), parting);
RecyclerView rvFood = view.findViewById(R.id.rv_food);
RecyclerView rvBill = view.findViewById(R.id.rv_bill_amount);
List<FoodBean> foodBeans = new ArrayList<>();
foodBeans.add(new FoodBean("包子(主項)", 1, 13.54));
foodBeans.add(new FoodBean("番薯爸爸", 2, 8.0));
foodBeans.add(new FoodBean("包子(主項)", 3, 37.34));
foodBeans.add(new FoodBean("測卡很快就酸辣粉十大減肥和思考", 33, 1334.2254));
FoodAdapter foodAdapter = new FoodAdapter(foodBeans);
rvFood.setLayoutManager(new LinearLayoutManager(context));
rvFood.setAdapter(foodAdapter);
List<BillingBean> billingBeans = new ArrayList<>();
billingBeans.add(new BillingBean("合計", 58.88));
billingBeans.add(new BillingBean("10%服務費", 5.08));
billingBeans.add(new BillingBean("賬單小數", -0.06));
billingBeans.add(new BillingBean("上課交電話費扣水電費可接受的咖啡機", 837248.8829372));
BillAdapter billAdapter = new BillAdapter(billingBeans);
rvBill.setLayoutManager(new LinearLayoutManager(context));
rvBill.setAdapter(billAdapter);
//加载条形码
ImageView ivBarCode = view.findViewById(R.id.iv_bar_code);
ivBarCode.setImageBitmap(BitmapUtil.generateBitmap("12312112131", 2, 450, 150));
LayoutToBitmapUtils.layoutView(context, view);//先测量view
Bitmap bitmap = LayoutToBitmapUtils.loadBitmapFromView(view);//将view轉bitmap
ArrayList<byte[]> image1 = PrinterUtils.decodeBitmapToDataList(bitmap, parting);//bitmap转字节码
data.addAll(image1);
// String bitmapPath = FileUtils.getExternalFilesDir(context, "Temp") + "tmp_qr.jpg";
// if (QRCodeUtil.createQRImage(qr, 380, 380, null, bitmapPath)) {
// ArrayList<byte[]> image2 = printer.getImageByte(bitmapPath);
// data.addAll(image2);
// } else {
// ArrayList<byte[]> image2 = printer
// .getImageByte(context.getResources(), R.drawable.ic_printer_qr);
// data.addAll(image2);
// }
printer.printLineFeed();
printer.printLineFeed();
printer.printLineFeed();
......
......@@ -83,9 +83,7 @@ public class BitmapUtil {
}
}
return Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.RGB_565);
} catch (WriterException e) {
e.printStackTrace();
} catch (IllegalArgumentException e){
} catch (WriterException | IllegalArgumentException e) {
e.printStackTrace();
}
return null;
......
package com.joe.print.utils;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Map;
/**
* 二维码生成工具类
* Created by Alex on 2016/10/10.
*/
public class QRCodeUtil {
/**
* 生成二维码Bitmap
*
* @param content 内容
* @param widthPix 图片宽度
* @param heightPix 图片高度
* @param logoBm 二维码中心的Logo图标(可以为null)
* @param filePath 用于存储二维码图片的文件路径
* @return 生成二维码及保存文件是否成功
*/
public static boolean createQRImage(String content, int widthPix, int heightPix, Bitmap logoBm, String filePath) {
try {
if (content == null || content.length() <= 0) {
return false;
}
//配置参数
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
//容错级别
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
//设置空白边距的宽度
// hints.put(EncodeHintType.MARGIN, 2); //default is 4
// 图像数据转换,使用了矩阵转换
BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, widthPix, heightPix, hints);
int[] pixels = new int[widthPix * heightPix];
// 下面这里按照二维码的算法,逐个生成二维码的图片,
// 两个for循环是图片横列扫描的结果
for (int y = 0; y < heightPix; y++) {
for (int x = 0; x < widthPix; x++) {
if (bitMatrix.get(x, y)) {
pixels[y * widthPix + x] = 0xff000000;
} else {
pixels[y * widthPix + x] = 0xffffffff;
}
}
}
// 生成二维码图片的格式,使用ARGB_8888
Bitmap bitmap = Bitmap.createBitmap(widthPix, heightPix, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, widthPix, 0, 0, widthPix, heightPix);
if (logoBm != null) {
bitmap = addLogo(bitmap, logoBm);
}
//必须使用compress方法将bitmap保存到文件中再进行读取。直接返回的bitmap是没有任何压缩的,内存消耗巨大!
return bitmap != null && bitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(filePath));
} catch (Exception e) {
return false;
}
}
/**
* 在二维码中间添加Logo图案
*/
private static Bitmap addLogo(Bitmap src, Bitmap logo) {
if (src == null) {
return null;
}
if (logo == null) {
return src;
}
//获取图片的宽高
int srcWidth = src.getWidth();
int srcHeight = src.getHeight();
int logoWidth = logo.getWidth();
int logoHeight = logo.getHeight();
if (srcWidth == 0 || srcHeight == 0) {
return null;
}
if (logoWidth == 0 || logoHeight == 0) {
return src;
}
//logo大小为二维码整体大小的1/5
float scaleFactor = srcWidth * 1.0f / 5 / logoWidth;
Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888);
try {
Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(src, 0, 0, null);
canvas.scale(scaleFactor, scaleFactor, srcWidth / 2, srcHeight / 2);
canvas.drawBitmap(logo, (srcWidth - logoWidth) / 2, (srcHeight - logoHeight) / 2, null);
canvas.save();//Canvas.ALL_SAVE_FLAG
canvas.restore();
} catch (Exception e) {
bitmap = null;
e.getStackTrace();
}
return bitmap;
}
}
\ No newline at end of file
......@@ -265,6 +265,7 @@
android:id="@+id/tv_checkout_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="2020-01-09 上午 11:16:15"
android:textColor="#333"
android:textSize="16sp"
......@@ -272,5 +273,14 @@
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_thank_you_text" />
<ImageView
android:id="@+id/iv_bar_code"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_50"
android:layout_marginTop="@dimen/dp_10"
android:layout_marginRight="@dimen/dp_50"
app:layout_constraintTop_toBottomOf="@+id/tv_checkout_time" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
\ No newline at end of file
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* 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.gingersoft.gsa.cloud.base.qmui.arch;
import android.annotation.SuppressLint;
import android.content.res.Configuration;
import android.os.Build;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
//Fix the bug: Only fullscreen activities can request orientation in Android version 26, 27
class InnerBaseActivity extends AppCompatActivity {
private static int NO_REQUESTED_ORIENTATION_SET = -100;
private boolean mConvertToTranslucentCauseOrientationChanged = false;
private int mPendingRequestedOrientation = NO_REQUESTED_ORIENTATION_SET;
void convertToTranslucentCauseOrientationChanged() {
Utils.convertActivityToTranslucent(this);
mConvertToTranslucentCauseOrientationChanged = true;
}
@Override
public void setRequestedOrientation(int requestedOrientation) {
if (mConvertToTranslucentCauseOrientationChanged && (Build.VERSION.SDK_INT == Build.VERSION_CODES.O
|| Build.VERSION.SDK_INT == Build.VERSION_CODES.O_MR1)) {
Log.i("InnerBaseActivity", "setRequestedOrientation when activity is translucent");
mPendingRequestedOrientation = requestedOrientation;
} else {
super.setRequestedOrientation(requestedOrientation);
}
}
@SuppressLint("WrongConstant")
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (mConvertToTranslucentCauseOrientationChanged) {
mConvertToTranslucentCauseOrientationChanged = false;
Utils.convertActivityFromTranslucent(this);
if (mPendingRequestedOrientation != NO_REQUESTED_ORIENTATION_SET) {
super.setRequestedOrientation(mPendingRequestedOrientation);
mPendingRequestedOrientation = NO_REQUESTED_ORIENTATION_SET;
}
}
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* 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.gingersoft.gsa.cloud.base.qmui.arch;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.gingersoft.gsa.cloud.base.R;
import com.qmuiteam.qmui.util.QMUIStatusBarHelper;
import static com.gingersoft.gsa.cloud.base.qmui.arch.SwipeBackLayout.EDGE_LEFT;
import androidx.annotation.Nullable;
public class QMUIActivity extends InnerBaseActivity {
private static final String TAG = "QMUIActivity";
private SwipeBackLayout.ListenerRemover mListenerRemover;
private SwipeBackgroundView mSwipeBackgroundView;
private boolean mIsInSwipeBack = false;
private SwipeBackLayout.SwipeListener mSwipeListener = new SwipeBackLayout.SwipeListener() {
@Override
public void onScrollStateChange(int state, float scrollPercent) {
Log.i(TAG, "SwipeListener:onScrollStateChange: state = " + state + " ;scrollPercent = " + scrollPercent);
mIsInSwipeBack = state != SwipeBackLayout.STATE_IDLE;
if (state == SwipeBackLayout.STATE_IDLE) {
if (mSwipeBackgroundView != null) {
if (scrollPercent <= 0.0F) {
mSwipeBackgroundView.unBind();
mSwipeBackgroundView = null;
} else if (scrollPercent >= 1.0F) {
// unBind mSwipeBackgroundView until onDestroy
finish();
int exitAnim = mSwipeBackgroundView.hasChildWindow() ?
R.anim.swipe_back_exit_still : R.anim.swipe_back_exit;
overridePendingTransition(R.anim.swipe_back_enter, exitAnim);
}
}
}
}
@Override
public void onScroll(int edgeFlag, float scrollPercent) {
if (mSwipeBackgroundView != null) {
scrollPercent = Math.max(0f, Math.min(1f, scrollPercent));
int targetOffset = (int) (Math.abs(backViewInitOffset()) * (1 - scrollPercent));
SwipeBackLayout.offsetInScroll(mSwipeBackgroundView, edgeFlag, targetOffset);
}
}
@Override
public void onEdgeTouch(int edgeFlag) {
Log.i(TAG, "SwipeListener:onEdgeTouch: edgeFlag = " + edgeFlag);
onDragStart();
ViewGroup decorView = (ViewGroup) getWindow().getDecorView();
if (decorView != null) {
Activity prevActivity = QMUISwipeBackActivityManager.getInstance()
.getPenultimateActivity(QMUIActivity.this);
if (decorView.getChildAt(0) instanceof SwipeBackgroundView) {
mSwipeBackgroundView = (SwipeBackgroundView) decorView.getChildAt(0);
} else {
mSwipeBackgroundView = new SwipeBackgroundView(QMUIActivity.this);
decorView.addView(mSwipeBackgroundView, 0, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
}
mSwipeBackgroundView.bind(prevActivity, QMUIActivity.this, restoreSubWindowWhenDragBack());
SwipeBackLayout.offsetInEdgeTouch(mSwipeBackgroundView, edgeFlag,
Math.abs(backViewInitOffset()));
}
}
@Override
public void onScrollOverThreshold() {
Log.i(TAG, "SwipeListener:onEdgeTouch:onScrollOverThreshold");
}
};
private SwipeBackLayout.Callback mSwipeCallback = new SwipeBackLayout.Callback() {
@Override
public boolean canSwipeBack() {
return QMUISwipeBackActivityManager.getInstance().canSwipeBack() && canDragBack();
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
QMUIStatusBarHelper.translucent(this);
}
@Override
public void setContentView(View view) {
super.setContentView(newSwipeBackLayout(view));
}
@Override
public void setContentView(int layoutResID) {
SwipeBackLayout swipeBackLayout = SwipeBackLayout.wrap(this,
layoutResID, dragBackEdge(), mSwipeCallback);
if (translucentFull()) {
swipeBackLayout.getContentView().setFitsSystemWindows(false);
} else {
swipeBackLayout.getContentView().setFitsSystemWindows(true);
}
mListenerRemover = swipeBackLayout.addSwipeListener(mSwipeListener);
super.setContentView(swipeBackLayout);
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
super.setContentView(newSwipeBackLayout(view), params);
}
private View newSwipeBackLayout(View view) {
if (translucentFull()) {
view.setFitsSystemWindows(false);
} else {
view.setFitsSystemWindows(true);
}
final SwipeBackLayout swipeBackLayout = SwipeBackLayout.wrap(view, dragBackEdge(), mSwipeCallback);
mListenerRemover = swipeBackLayout.addSwipeListener(mSwipeListener);
return swipeBackLayout;
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mListenerRemover != null) {
mListenerRemover.remove();
}
if (mSwipeBackgroundView != null) {
mSwipeBackgroundView.unBind();
mSwipeBackgroundView = null;
}
}
/**
* final this method, if need override this method, use doOnBackPressed as an alternative
*/
@Override
public final void onBackPressed() {
if (!mIsInSwipeBack) {
doOnBackPressed();
}
}
protected void doOnBackPressed() {
super.onBackPressed();
}
public boolean isInSwipeBack() {
return mIsInSwipeBack;
}
/**
* disable or enable drag back
*
* @return
*/
protected boolean canDragBack() {
return true;
}
/**
* if enable drag back,
*
* @return
*/
protected int backViewInitOffset() {
return 0;
}
/**
* called when drag back started.
*/
protected void onDragStart() {
}
protected int dragBackEdge() {
return EDGE_LEFT;
}
/**
* Immersive processing
*
* @return if true, the area under status bar belongs to content; otherwise it belongs to padding
*/
protected boolean translucentFull() {
return false;
}
/**
* restore sub window(e.g dialog) when drag back to previous activity
*
* @return
*/
protected boolean restoreSubWindowWhenDragBack() {
return true;
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* 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.gingersoft.gsa.cloud.base.qmui.arch;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import com.gingersoft.gsa.cloud.base.R;
import com.qmuiteam.qmui.QMUILog;
import com.qmuiteam.qmui.util.QMUIKeyboardHelper;
import com.qmuiteam.qmui.util.QMUIViewHelper;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.arch.core.util.Function;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.LifecycleOwner;
import androidx.viewpager.widget.ViewPager;
import static com.gingersoft.gsa.cloud.base.qmui.arch.SwipeBackLayout.EDGE_LEFT;
/**
* With the use of {@link QMUIFragmentActivity}, {@link QMUIFragment} brings more features,
* such as swipe back, transition config, and so on.
* <p>
* Created by cgspine on 15/9/14.
*/
public abstract class QMUIFragment extends Fragment implements QMUIFragmentLazyLifecycleOwner.Callback {
private static final String SWIPE_BACK_VIEW = "swipe_back_view";
private static final String TAG = QMUIFragment.class.getSimpleName();
protected static final TransitionConfig SLIDE_TRANSITION_CONFIG = new TransitionConfig(
R.anim.slide_in_right, R.anim.slide_out_left,
R.anim.slide_in_left, R.anim.slide_out_right);
protected static final TransitionConfig SCALE_TRANSITION_CONFIG = new TransitionConfig(
R.anim.scale_enter, R.anim.slide_still,
R.anim.slide_still, R.anim.scale_exit);
public static final int RESULT_CANCELED = Activity.RESULT_CANCELED;
public static final int RESULT_OK = Activity.RESULT_OK;
public static final int RESULT_FIRST_USER = Activity.RESULT_FIRST_USER;
public static final int ANIMATION_ENTER_STATUS_NOT_START = -1;
public static final int ANIMATION_ENTER_STATUS_STARTED = 0;
public static final int ANIMATION_ENTER_STATUS_END = 1;
private static final int NO_REQUEST_CODE = 0;
private int mSourceRequestCode = NO_REQUEST_CODE;
private Intent mResultData = null;
private int mResultCode = RESULT_CANCELED;
private QMUIFragment mChildTargetFragment;
private View mBaseView;
private SwipeBackLayout mCacheSwipeBackLayout;
private View mCacheRootView;
private boolean isCreateForSwipeBack = false;
private int mBackStackIndex = 0;
private SwipeBackLayout.ListenerRemover mListenerRemover;
private SwipeBackgroundView mSwipeBackgroundView;
private boolean mIsInSwipeBack = false;
private int mEnterAnimationStatus = ANIMATION_ENTER_STATUS_NOT_START;
private boolean mCalled = true;
private ArrayList<Runnable> mDelayRenderRunnableList = new ArrayList<>();
private QMUIFragmentLazyLifecycleOwner mLazyViewLifecycleOwner;
public QMUIFragment() {
super();
}
public final QMUIFragmentActivity getBaseFragmentActivity() {
return (QMUIFragmentActivity) getActivity();
}
public boolean isAttachedToActivity() {
return !isRemoving() && mBaseView != null;
}
@Override
public void onDestroyView() {
super.onDestroyView();
mBaseView = null;
}
protected void startFragmentAndDestroyCurrent(QMUIFragment fragment) {
startFragmentAndDestroyCurrent(fragment, true);
}
/**
* see {@link QMUIFragmentActivity#startFragmentAndDestroyCurrent(QMUIFragment, boolean)}
*
* @param fragment
* @param useNewTransitionConfigWhenPop
*/
protected void startFragmentAndDestroyCurrent(QMUIFragment fragment, boolean useNewTransitionConfigWhenPop) {
if (getTargetFragment() != null) {
// transfer target fragment
fragment.setTargetFragment(getTargetFragment(), getTargetRequestCode());
setTargetFragment(null, 0);
}
QMUIFragmentActivity baseFragmentActivity = this.getBaseFragmentActivity();
if (baseFragmentActivity != null) {
if (this.isAttachedToActivity()) {
ViewCompat.setTranslationZ(mCacheSwipeBackLayout, --mBackStackIndex);
baseFragmentActivity.startFragmentAndDestroyCurrent(fragment, useNewTransitionConfigWhenPop);
} else {
Log.e("QMUIFragment", "fragment not attached:" + this);
}
} else {
Log.e("QMUIFragment", "startFragment null:" + this);
}
}
protected void startFragment(QMUIFragment fragment) {
QMUIFragmentActivity baseFragmentActivity = this.getBaseFragmentActivity();
if (baseFragmentActivity != null) {
if (this.isAttachedToActivity()) {
baseFragmentActivity.startFragment(fragment);
} else {
Log.e("QMUIFragment", "fragment not attached:" + this);
}
} else {
Log.e("QMUIFragment", "startFragment null:" + this);
}
}
/**
* simulate the behavior of startActivityForResult/onActivityResult:
* 1. Jump fragment1 to fragment2 via startActivityForResult(fragment2, requestCode)
* 2. Pass data from fragment2 to fragment1 via setFragmentResult(RESULT_OK, data)
* 3. Get data in fragment1 through onFragmentResult(requestCode, resultCode, data)
*
* @param fragment target fragment
* @param requestCode request code
*/
public void startFragmentForResult(QMUIFragment fragment, int requestCode) {
if (requestCode == NO_REQUEST_CODE) {
throw new RuntimeException("requestCode can not be " + NO_REQUEST_CODE);
}
QMUIFragmentActivity baseFragmentActivity = this.getBaseFragmentActivity();
if (baseFragmentActivity != null) {
FragmentManager targetFragmentManager = baseFragmentActivity.getSupportFragmentManager();
Fragment topFragment = this;
Fragment parent = this;
while (parent != null) {
topFragment = parent;
if (parent.getFragmentManager() == targetFragmentManager) {
break;
}
parent = parent.getParentFragment();
}
mSourceRequestCode = requestCode;
if (topFragment == this) {
mChildTargetFragment = null;
fragment.setTargetFragment(this, requestCode);
} else if (topFragment.getFragmentManager() == targetFragmentManager) {
QMUIFragment qmuiFragment = (QMUIFragment) topFragment;
qmuiFragment.mSourceRequestCode = requestCode;
qmuiFragment.mChildTargetFragment = this;
fragment.setTargetFragment(qmuiFragment, requestCode);
} else {
throw new RuntimeException("fragment manager not matched");
}
startFragment(fragment);
}
}
public void setFragmentResult(int resultCode, Intent data) {
int targetRequestCode = getTargetRequestCode();
if (targetRequestCode == 0) {
QMUILog.w(TAG, "call setFragmentResult, but not requestCode exists");
return;
}
Fragment fragment = getTargetFragment();
if (!(fragment instanceof QMUIFragment)) {
return;
}
QMUIFragment targetFragment = (QMUIFragment) fragment;
if (targetFragment.mSourceRequestCode == targetRequestCode) {
if (targetFragment.mChildTargetFragment != null) {
targetFragment = targetFragment.mChildTargetFragment;
}
targetFragment.mResultCode = resultCode;
targetFragment.mResultData = data;
}
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fragmentManager = getFragmentManager();
if (fragmentManager != null) {
int backStackEntryCount = fragmentManager.getBackStackEntryCount();
for (int i = backStackEntryCount - 1; i >= 0; i--) {
FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(i);
if (getClass().getSimpleName().equals(entry.getName())) {
mBackStackIndex = i;
break;
}
}
}
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mLazyViewLifecycleOwner = new QMUIFragmentLazyLifecycleOwner(this);
mLazyViewLifecycleOwner.setViewVisible(getUserVisibleHint());
getViewLifecycleOwner().getLifecycle().addObserver(mLazyViewLifecycleOwner);
}
@Override
public void onStart() {
super.onStart();
int requestCode = mSourceRequestCode;
int resultCode = mResultCode;
Intent data = mResultData;
QMUIFragment childTargetFragment = mChildTargetFragment;
mSourceRequestCode = NO_REQUEST_CODE;
mResultCode = RESULT_CANCELED;
mResultData = null;
mChildTargetFragment = null;
if (requestCode != NO_REQUEST_CODE) {
if (childTargetFragment == null) {
// only handle the result when there is not child target.
onFragmentResult(requestCode, resultCode, data);
}
}
}
private SwipeBackLayout newSwipeBackLayout() {
View rootView = mCacheRootView;
if (rootView == null) {
rootView = onCreateView();
mCacheRootView = rootView;
} else {
if (rootView.getParent() != null) {
((ViewGroup) rootView.getParent()).removeView(rootView);
}
}
if (translucentFull()) {
rootView.setFitsSystemWindows(false);
} else {
rootView.setFitsSystemWindows(true);
}
final SwipeBackLayout swipeBackLayout = SwipeBackLayout.wrap(rootView, dragBackEdge(),
new SwipeBackLayout.Callback() {
@Override
public boolean canSwipeBack() {
if (mEnterAnimationStatus != ANIMATION_ENTER_STATUS_END) {
return false;
}
if (!canDragBack()) {
return false;
}
if (getParentFragment() != null) {
return false;
}
View view = getView();
if (view == null) {
return false;
}
// if the Fragment is in ViewPager, then stop drag back
ViewParent parent = view.getParent();
while (parent != null) {
if (parent instanceof ViewPager) {
return false;
}
parent = parent.getParent();
}
FragmentManager fragmentManager = getFragmentManager();
if (fragmentManager == null || fragmentManager.getBackStackEntryCount() <= 1) {
return QMUISwipeBackActivityManager.getInstance().canSwipeBack();
}
return true;
}
});
mListenerRemover = swipeBackLayout.addSwipeListener(mSwipeListener);
return swipeBackLayout;
}
private SwipeBackLayout.SwipeListener mSwipeListener = new SwipeBackLayout.SwipeListener() {
private QMUIFragment mModifiedFragment = null;
@Override
public void onScrollStateChange(int state, float scrollPercent) {
Log.i(TAG, "SwipeListener:onScrollStateChange: state = " + state + " ;scrollPercent = " + scrollPercent);
ViewGroup container = getBaseFragmentActivity().getFragmentContainer();
mIsInSwipeBack = state != SwipeBackLayout.STATE_IDLE;
if (state == SwipeBackLayout.STATE_IDLE) {
if (mSwipeBackgroundView != null) {
if (scrollPercent <= 0.0F) {
mSwipeBackgroundView.unBind();
mSwipeBackgroundView = null;
} else if (scrollPercent >= 1.0F) {
// unbind mSwipeBackgroundView util onDestroy
if (getActivity() != null) {
getActivity().finish();
int exitAnim = mSwipeBackgroundView.hasChildWindow() ?
R.anim.swipe_back_exit_still : R.anim.swipe_back_exit;
getActivity().overridePendingTransition(R.anim.swipe_back_enter, exitAnim);
}
}
return;
}
if (scrollPercent <= 0.0F) {
handleSwipeBackCancelOrFinished(container);
} else if (scrollPercent >= 1.0F) {
handleSwipeBackCancelOrFinished(container);
FragmentManager fragmentManager = getFragmentManager();
Utils.findAndModifyOpInBackStackRecord(fragmentManager, -1, new Utils.OpHandler() {
@Override
public boolean handle(Object op) {
Field cmdField;
try {
cmdField = op.getClass().getDeclaredField("cmd");
cmdField.setAccessible(true);
int cmd = (int) cmdField.get(op);
if (cmd == 1) {
Field popEnterAnimField = op.getClass().getDeclaredField("popExitAnim");
popEnterAnimField.setAccessible(true);
popEnterAnimField.set(op, 0);
} else if (cmd == 3) {
Field popExitAnimField = op.getClass().getDeclaredField("popEnterAnim");
popExitAnimField.setAccessible(true);
popExitAnimField.set(op, 0);
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return false;
}
@Override
public boolean needReNameTag() {
return false;
}
@Override
public String newTagName() {
return null;
}
});
popBackStack();
}
}
}
@Override
public void onScroll(int edgeFlag, float scrollPercent) {
scrollPercent = Math.max(0f, Math.min(1f, scrollPercent));
int targetOffset = (int) (Math.abs(backViewInitOffset()) * (1 - scrollPercent));
ViewGroup container = getBaseFragmentActivity().getFragmentContainer();
int childCount = container.getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
View view = container.getChildAt(i);
Object tag = view.getTag(R.id.qmui_arch_swipe_layout_in_back);
if (SWIPE_BACK_VIEW.equals(tag)) {
SwipeBackLayout.offsetInScroll(view, edgeFlag, targetOffset);
}
}
if (mSwipeBackgroundView != null) {
SwipeBackLayout.offsetInScroll(mSwipeBackgroundView, edgeFlag, targetOffset);
}
}
@SuppressLint("PrivateApi")
@Override
public void onEdgeTouch(int edgeFlag) {
Log.i(TAG, "SwipeListener:onEdgeTouch: edgeFlag = " + edgeFlag);
FragmentManager fragmentManager = getFragmentManager();
if (fragmentManager == null) {
return;
}
QMUIKeyboardHelper.hideKeyboard(mBaseView);
onDragStart();
int backStackCount = fragmentManager.getBackStackEntryCount();
if (backStackCount > 1) {
try {
FragmentManager.BackStackEntry backStackEntry = fragmentManager.getBackStackEntryAt(backStackCount - 1);
Field opsField = backStackEntry.getClass().getDeclaredField("mOps");
opsField.setAccessible(true);
Object opsObj = opsField.get(backStackEntry);
if (opsObj instanceof List<?>) {
List<?> ops = (List<?>) opsObj;
for (Object op : ops) {
Field cmdField = op.getClass().getDeclaredField("cmd");
cmdField.setAccessible(true);
int cmd = (int) cmdField.get(op);
if (cmd == 3) {
Field popEnterAnimField = op.getClass().getDeclaredField("popEnterAnim");
popEnterAnimField.setAccessible(true);
popEnterAnimField.set(op, 0);
Field fragmentField = op.getClass().getDeclaredField("fragment");
fragmentField.setAccessible(true);
Object fragmentObject = fragmentField.get(op);
if (fragmentObject instanceof QMUIFragment) {
mModifiedFragment = (QMUIFragment) fragmentObject;
ViewGroup container = getBaseFragmentActivity().getFragmentContainer();
mModifiedFragment.isCreateForSwipeBack = true;
View baseView = mModifiedFragment.onCreateView(LayoutInflater.from(getContext()), container, null);
mModifiedFragment.isCreateForSwipeBack = false;
if (baseView != null) {
addViewInSwipeBack(container, baseView, 0);
handleChildFragmentListWhenSwipeBackStart(baseView);
SwipeBackLayout.offsetInEdgeTouch(baseView, edgeFlag,
Math.abs(backViewInitOffset()));
}
}
}
}
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} else if (getParentFragment() == null) {
Activity currentActivity = getActivity();
if (currentActivity != null) {
ViewGroup decorView = (ViewGroup) currentActivity.getWindow().getDecorView();
Activity prevActivity = QMUISwipeBackActivityManager.getInstance()
.getPenultimateActivity(currentActivity);
if (decorView.getChildAt(0) instanceof SwipeBackgroundView) {
mSwipeBackgroundView = (SwipeBackgroundView) decorView.getChildAt(0);
} else {
mSwipeBackgroundView = new SwipeBackgroundView(getContext());
decorView.addView(mSwipeBackgroundView, 0, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
}
mSwipeBackgroundView.bind(prevActivity, currentActivity, restoreSubWindowWhenDragBack());
SwipeBackLayout.offsetInEdgeTouch(mSwipeBackgroundView, edgeFlag,
Math.abs(backViewInitOffset()));
}
}
}
@Override
public void onScrollOverThreshold() {
Log.i(TAG, "SwipeListener:onEdgeTouch:onScrollOverThreshold");
}
private void addViewInSwipeBack(ViewGroup parent, View child) {
addViewInSwipeBack(parent, child, -1);
}
private void addViewInSwipeBack(ViewGroup parent, View child, int index) {
if (parent != null && child != null) {
child.setTag(R.id.qmui_arch_swipe_layout_in_back, SWIPE_BACK_VIEW);
parent.addView(child, index);
}
}
private void removeViewInSwipeBack(ViewGroup parent, Function<View, Void> onRemove) {
if (parent != null) {
int childCount = parent.getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
View view = parent.getChildAt(i);
Object tag = view.getTag(R.id.qmui_arch_swipe_layout_in_back);
if (SWIPE_BACK_VIEW.equals(tag)) {
if (onRemove != null) {
onRemove.apply(view);
}
parent.removeView(view);
}
}
}
}
private void handleChildFragmentListWhenSwipeBackStart(View baseView) throws
NoSuchFieldException, IllegalAccessException {
// handle issue #235
if (baseView instanceof ViewGroup) {
ViewGroup childMainContainer = (ViewGroup) baseView;
FragmentManager childFragmentManager = mModifiedFragment.getChildFragmentManager();
List<Fragment> childFragmentList = childFragmentManager.getFragments();
int childContainerId = 0;
ViewGroup childContainer = null;
for (Fragment fragment : childFragmentList) {
if (fragment instanceof QMUIFragment) {
QMUIFragment qmuiFragment = (QMUIFragment) fragment;
Field containerIdField = Fragment.class.getDeclaredField("mContainerId");
containerIdField.setAccessible(true);
int containerId = containerIdField.getInt(qmuiFragment);
if (containerId != 0) {
if (childContainerId != containerId) {
childContainerId = containerId;
childContainer = childMainContainer.findViewById(containerId);
}
if (childContainer != null) {
qmuiFragment.isCreateForSwipeBack = true;
View childView = fragment.onCreateView(
LayoutInflater.from(childContainer.getContext()), childContainer, null);
qmuiFragment.isCreateForSwipeBack = false;
addViewInSwipeBack(childContainer, childView);
}
}
}
}
}
}
private void handleSwipeBackCancelOrFinished(ViewGroup container) {
removeViewInSwipeBack(container, new Function<View, Void>() {
@Override
public Void apply(View input) {
if (mModifiedFragment == null) {
return null;
}
if (input instanceof ViewGroup) {
ViewGroup childMainContainer = (ViewGroup) input;
FragmentManager childFragmentManager = mModifiedFragment.getChildFragmentManager();
List<Fragment> childFragmentList = childFragmentManager.getFragments();
int childContainerId = 0;
try {
for (Fragment fragment : childFragmentList) {
if (fragment instanceof QMUIFragment) {
QMUIFragment qmuiFragment = (QMUIFragment) fragment;
Field containerIdField = Fragment.class.getDeclaredField("mContainerId");
containerIdField.setAccessible(true);
int containerId = containerIdField.getInt(qmuiFragment);
if (containerId != 0 && childContainerId != containerId) {
childContainerId = containerId;
ViewGroup childContainer = childMainContainer.findViewById(containerId);
removeViewInSwipeBack(childContainer, null);
}
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
return null;
}
});
mModifiedFragment = null;
}
};
private boolean canNotUseCacheViewInCreateView() {
return mCacheSwipeBackLayout.getParent() != null || ViewCompat.isAttachedToWindow(mCacheSwipeBackLayout);
}
public boolean isInSwipeBack() {
return mIsInSwipeBack;
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
SwipeBackLayout swipeBackLayout;
if (mCacheSwipeBackLayout == null) {
swipeBackLayout = newSwipeBackLayout();
mCacheSwipeBackLayout = swipeBackLayout;
} else {
if (canNotUseCacheViewInCreateView()) {
// try removeView first
container.removeView(mCacheSwipeBackLayout);
}
if (canNotUseCacheViewInCreateView()) {
// give up!!!
Log.i(TAG, "can not use cache swipeBackLayout, this may happen " +
"if invoke popBackStack duration fragment transition");
mCacheSwipeBackLayout.clearSwipeListeners();
swipeBackLayout = newSwipeBackLayout();
mCacheSwipeBackLayout = swipeBackLayout;
} else {
swipeBackLayout = mCacheSwipeBackLayout;
}
}
if (!isCreateForSwipeBack) {
mBaseView = swipeBackLayout.getContentView();
swipeBackLayout.setTag(R.id.qmui_arch_swipe_layout_in_back, null);
}
ViewCompat.setTranslationZ(swipeBackLayout, mBackStackIndex);
Log.i(TAG, getClass().getSimpleName() + " onCreateView: mBackStackIndex = " + mBackStackIndex);
swipeBackLayout.setFitsSystemWindows(false);
if (getActivity() != null) {
QMUIViewHelper.requestApplyInsets(getActivity().getWindow());
}
return swipeBackLayout;
}
protected void onBackPressed() {
popBackStack();
}
protected void popBackStack() {
if (mEnterAnimationStatus != ANIMATION_ENTER_STATUS_END) {
return;
}
getBaseFragmentActivity().popBackStack();
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
return false;
}
public boolean onKeyUp(int keyCode, KeyEvent event) {
return false;
}
@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
if (!enter && getParentFragment() != null && getParentFragment().isRemoving()) {
// This is a workaround for the bug where child fragments disappear when
// the parent is removed (as all children are first removed from the parent)
// See https://code.google.com/p/android/issues/detail?id=55228
Animation doNothingAnim = new AlphaAnimation(1, 1);
int duration = getResources().getInteger(R.integer.qmui_anim_duration);
doNothingAnim.setDuration(duration);
return doNothingAnim;
}
Animation animation = null;
if (enter) {
try {
animation = AnimationUtils.loadAnimation(getContext(), nextAnim);
} catch (Resources.NotFoundException ignored) {
} catch (RuntimeException ignored) {
}
if (animation != null) {
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
onEnterAnimationStart(animation);
}
@Override
public void onAnimationEnd(Animation animation) {
checkAndCallOnEnterAnimationEnd(animation);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
} else {
onEnterAnimationStart(null);
checkAndCallOnEnterAnimationEnd(null);
}
}
return animation;
}
private void checkAndCallOnEnterAnimationEnd(@Nullable Animation animation) {
mCalled = false;
onEnterAnimationEnd(animation);
if (!mCalled) {
throw new RuntimeException("QMUIFragment " + this + " did not call through to super.onEnterAnimationEnd(Animation)");
}
}
/**
* onCreateView
*/
protected abstract View onCreateView();
/**
* Will be performed in onStart
*
* @param requestCode request code
* @param resultCode result code
* @param data extra data
*/
protected void onFragmentResult(int requestCode, int resultCode, Intent data) {
}
/**
* disable or enable drag back
*
* @return
*/
protected boolean canDragBack() {
return true;
}
/**
* if enable drag back,
*
* @return
*/
protected int backViewInitOffset() {
return 0;
}
/**
* called when drag back started.
*/
protected void onDragStart() {
}
protected int dragBackEdge() {
return EDGE_LEFT;
}
/**
* the action will be performed before the start of the enter animation start or after the
* enter animation is finished
*
* @param runnable the action to perform
*/
public void runAfterAnimation(Runnable runnable) {
runAfterAnimation(runnable, false);
}
/**
* When data is rendered duration the transition animation, it will cause a choppy. this method
* will promise the data is rendered before or after transition animation
*
* @param runnable the action to perform
* @param onlyEnd if true, the action is only performed after the enter animation is finished,
* otherwise it can be performed before the start of the enter animation start
* or after the enter animation is finished.
*/
public void runAfterAnimation(Runnable runnable, boolean onlyEnd) {
Utils.assertInMainThread();
boolean ok = onlyEnd ? mEnterAnimationStatus == ANIMATION_ENTER_STATUS_END :
mEnterAnimationStatus != ANIMATION_ENTER_STATUS_STARTED;
if (ok) {
runnable.run();
} else {
mDelayRenderRunnableList.add(runnable);
}
}
protected void onEnterAnimationStart(@Nullable Animation animation) {
mEnterAnimationStatus = ANIMATION_ENTER_STATUS_STARTED;
}
protected void onEnterAnimationEnd(@Nullable Animation animation) {
if (mCalled) {
throw new IllegalAccessError("don't call #onEnterAnimationEnd() directly");
}
mCalled = true;
if (mDelayRenderRunnableList.size() > 0) {
for (int i = 0; i < mDelayRenderRunnableList.size(); i++) {
mDelayRenderRunnableList.get(i).run();
}
mDelayRenderRunnableList.clear();
}
mEnterAnimationStatus = ANIMATION_ENTER_STATUS_END;
}
@Override
public void onDestroy() {
super.onDestroy();
if (mListenerRemover != null) {
mListenerRemover.remove();
}
if (mSwipeBackgroundView != null) {
mSwipeBackgroundView.unBind();
mSwipeBackgroundView = null;
}
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
notifyFragmentVisibleToUserChanged(isParentVisibleToUser() && isVisibleToUser);
}
@Override
public boolean isVisibleToUser() {
return getUserVisibleHint() && isParentVisibleToUser();
}
/**
* @return true if parentFragments is visible to user
*/
private boolean isParentVisibleToUser() {
Fragment parentFragment = getParentFragment();
while (parentFragment != null) {
if (!parentFragment.getUserVisibleHint()) {
return false;
}
parentFragment = parentFragment.getParentFragment();
}
return true;
}
private void notifyFragmentVisibleToUserChanged(boolean isVisibleToUser) {
if (mLazyViewLifecycleOwner != null) {
mLazyViewLifecycleOwner.setViewVisible(isVisibleToUser);
}
if (isAdded()) {
List<Fragment> childFragments = getChildFragmentManager().getFragments();
for (Fragment fragment : childFragments) {
if (fragment instanceof QMUIFragment) {
((QMUIFragment) fragment).notifyFragmentVisibleToUserChanged(
isVisibleToUser && fragment.getUserVisibleHint());
}
}
}
}
public LifecycleOwner getLazyViewLifecycleOwner() {
if (mLazyViewLifecycleOwner == null) {
throw new IllegalStateException("Can't access the QMUIFragment View's LifecycleOwner when "
+ "getView() is null i.e., before onViewCreated() or after onDestroyView()");
}
return mLazyViewLifecycleOwner;
}
/**
* Immersive processing
*
* @return if true, the area under status bar belongs to content; otherwise it belongs to padding
*/
protected boolean translucentFull() {
return false;
}
/**
* When finishing to pop back last fragment, let activity have a chance to do something
* like start a new fragment
*
* @return QMUIFragment to start a new fragment or Intent to start a new Activity
*/
@SuppressWarnings("SameReturnValue")
public Object onLastFragmentFinish() {
return null;
}
/**
* restore sub window(e.g dialog) when drag back to previous activity
*
* @return
*/
protected boolean restoreSubWindowWhenDragBack() {
return true;
}
/**
* Fragment Transition Controller
*/
public TransitionConfig onFetchTransitionConfig() {
return SLIDE_TRANSITION_CONFIG;
}
public static final class TransitionConfig {
public final int enter;
public final int exit;
public final int popenter;
public final int popout;
public TransitionConfig(int enter, int popout) {
this(enter, 0, 0, popout);
}
public TransitionConfig(int enter, int exit, int popenter, int popout) {
this.enter = enter;
this.exit = exit;
this.popenter = popenter;
this.popout = popout;
}
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* 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.gingersoft.gsa.cloud.base.qmui.arch;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.FrameLayout;
import com.qmuiteam.qmui.util.QMUIStatusBarHelper;
import com.qmuiteam.qmui.widget.QMUIWindowInsetLayout;
import java.lang.reflect.Field;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
/**
* the container activity for {@link QMUIFragment}.
* Created by cgspine on 15/9/14.
*/
public abstract class QMUIFragmentActivity extends InnerBaseActivity {
private static final String TAG = "QMUIFragmentActivity";
private QMUIWindowInsetLayout mFragmentContainer;
@SuppressWarnings("SameReturnValue")
protected abstract int getContextViewId();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
QMUIStatusBarHelper.translucent(this);
mFragmentContainer = new QMUIWindowInsetLayout(this);
mFragmentContainer.setId(getContextViewId());
setContentView(mFragmentContainer);
}
public FrameLayout getFragmentContainer() {
return mFragmentContainer;
}
@Override
public void onBackPressed() {
QMUIFragment fragment = getCurrentFragment();
if (fragment != null && !fragment.isInSwipeBack()) {
fragment.onBackPressed();
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
QMUIFragment fragment = getCurrentFragment();
if (fragment != null && !fragment.isInSwipeBack() && fragment.onKeyDown(keyCode, event)) {
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
QMUIFragment fragment = getCurrentFragment();
if (fragment != null && !fragment.isInSwipeBack() && fragment.onKeyUp(keyCode, event)) {
return true;
}
return super.onKeyUp(keyCode, event);
}
/**
* get the current Fragment.
*/
public QMUIFragment getCurrentFragment() {
return (QMUIFragment) getSupportFragmentManager().findFragmentById(getContextViewId());
}
/**
* start a new fragment and then destroy current fragment.
* assume there is a fragment stack(A->B->C), and you use this method to start a new
* fragment D and destroy fragment C. Now you are in fragment D, if you want call
* {@link #popBackStack()} to back to B, what the animation should be? Sometimes we hope run
* animation generated by transition B->C, but sometimes we hope run animation generated by
* transition C->D. this why second parameter exists.
*
* @param fragment new fragment to start
* @param useNewTransitionConfigWhenPop if true, use animation generated by transition C->D,
* else, use animation generated by transition B->C
*/
public int startFragmentAndDestroyCurrent(final QMUIFragment fragment, final boolean useNewTransitionConfigWhenPop) {
final QMUIFragment.TransitionConfig transitionConfig = fragment.onFetchTransitionConfig();
String tagName = fragment.getClass().getSimpleName();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction()
.setCustomAnimations(transitionConfig.enter, transitionConfig.exit,
transitionConfig.popenter, transitionConfig.popout)
.replace(getContextViewId(), fragment, tagName);
int index = transaction.commit();
Utils.findAndModifyOpInBackStackRecord(fragmentManager, -1, new Utils.OpHandler() {
@Override
public boolean handle(Object op) {
Field cmdField = null;
try {
cmdField = op.getClass().getDeclaredField("cmd");
cmdField.setAccessible(true);
int cmd = (int) cmdField.get(op);
if (cmd == 1) {
if (useNewTransitionConfigWhenPop) {
Field popEnterAnimField = op.getClass().getDeclaredField("popEnterAnim");
popEnterAnimField.setAccessible(true);
popEnterAnimField.set(op, transitionConfig.popenter);
Field popExitAnimField = op.getClass().getDeclaredField("popExitAnim");
popExitAnimField.setAccessible(true);
popExitAnimField.set(op, transitionConfig.popout);
}
Field oldFragmentField = op.getClass().getDeclaredField("fragment");
oldFragmentField.setAccessible(true);
Object fragmentObj = oldFragmentField.get(op);
oldFragmentField.set(op, fragment);
Field backStackNestField = Fragment.class.getDeclaredField("mBackStackNesting");
backStackNestField.setAccessible(true);
int oldFragmentBackStackNest = (int) backStackNestField.get(fragmentObj);
backStackNestField.set(fragment, oldFragmentBackStackNest);
backStackNestField.set(fragmentObj, --oldFragmentBackStackNest);
return true;
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return false;
}
@Override
public boolean needReNameTag() {
return true;
}
@Override
public String newTagName() {
return fragment.getClass().getSimpleName();
}
});
return index;
}
public int startFragment(QMUIFragment fragment) {
Log.i(TAG, "startFragment");
QMUIFragment.TransitionConfig transitionConfig = fragment.onFetchTransitionConfig();
String tagName = fragment.getClass().getSimpleName();
return getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(transitionConfig.enter, transitionConfig.exit, transitionConfig.popenter, transitionConfig.popout)
.replace(getContextViewId(), fragment, tagName)
.addToBackStack(tagName)
.commit();
}
/**
* Exit the current Fragment。
*/
public void popBackStack() {
Log.i(TAG, "popBackStack: getSupportFragmentManager().getBackStackEntryCount() = " + getSupportFragmentManager().getBackStackEntryCount());
if (getSupportFragmentManager().getBackStackEntryCount() <= 1) {
QMUIFragment fragment = getCurrentFragment();
if (fragment == null) {
finish();
return;
}
QMUIFragment.TransitionConfig transitionConfig = fragment.onFetchTransitionConfig();
Object toExec = fragment.onLastFragmentFinish();
if (toExec != null) {
if (toExec instanceof QMUIFragment) {
QMUIFragment mFragment = (QMUIFragment) toExec;
startFragment(mFragment);
} else if (toExec instanceof Intent) {
Intent intent = (Intent) toExec;
finish();
startActivity(intent);
overridePendingTransition(transitionConfig.popenter, transitionConfig.popout);
} else {
throw new Error("can not handle the result in onLastFragmentFinish");
}
} else {
finish();
overridePendingTransition(transitionConfig.popenter, transitionConfig.popout);
}
} else {
getSupportFragmentManager().popBackStackImmediate();
}
}
/**
* pop back to a clazz type fragment
* <p>
* Assuming there is a back stack: Home -> List -> Detail. Perform popBackStack(Home.class),
* Home is the current fragment
* <p>
* if the clazz type fragment doest not exist in back stack, this method is Equivalent
* to popBackStack()
*
* @param clazz the type of fragment
*/
public void popBackStack(Class<? extends QMUIFragment> clazz) {
getSupportFragmentManager().popBackStack(clazz.getSimpleName(), 0);
}
/**
* pop back to a non-clazz type Fragment
*
* @param clazz the type of fragment
*/
public void popBackStackInclusive(Class<? extends QMUIFragment> clazz) {
getSupportFragmentManager().popBackStack(clazz.getSimpleName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
}
\ No newline at end of file
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* 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.gingersoft.gsa.cloud.base.qmui.arch;
import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import androidx.lifecycle.OnLifecycleEvent;
public class QMUIFragmentLazyLifecycleOwner implements LifecycleOwner, LifecycleObserver {
private LifecycleRegistry mLifecycleRegistry = null;
private boolean mIsViewVisible = true;
private Lifecycle.State mViewState = Lifecycle.State.INITIALIZED;
private Callback mCallback;
public QMUIFragmentLazyLifecycleOwner(@NonNull Callback callback){
mCallback = callback;
}
/**
* Initializes the underlying Lifecycle if it hasn't already been created.
*/
void initialize() {
if (mLifecycleRegistry == null) {
mLifecycleRegistry = new LifecycleRegistry(this);
}
}
void setViewVisible(boolean viewVisible) {
if(mViewState.compareTo(Lifecycle.State.CREATED) < 0 || !isInitialized()){
// not trust it before onCreate
return;
}
mIsViewVisible = viewVisible;
if (viewVisible) {
mLifecycleRegistry.markState(mViewState);
} else {
if (mViewState.compareTo(Lifecycle.State.CREATED) > 0) {
mLifecycleRegistry.markState(Lifecycle.State.CREATED);
} else {
mLifecycleRegistry.markState(mViewState);
}
}
}
/**
* @return True if the Lifecycle has been initialized.
*/
boolean isInitialized() {
return mLifecycleRegistry != null;
}
@NonNull
@Override
public Lifecycle getLifecycle() {
initialize();
return mLifecycleRegistry;
}
private void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
initialize();
mLifecycleRegistry.handleLifecycleEvent(event);
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
void onCreate(LifecycleOwner owner) {
mIsViewVisible = mCallback.isVisibleToUser();
mViewState = Lifecycle.State.CREATED;
handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
void onStart(LifecycleOwner owner) {
mViewState = Lifecycle.State.STARTED;
if (mIsViewVisible) {
handleLifecycleEvent(Lifecycle.Event.ON_START);
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
void onResume(LifecycleOwner owner) {
mViewState = Lifecycle.State.RESUMED;
if (mIsViewVisible && mLifecycleRegistry.getCurrentState() == Lifecycle.State.STARTED) {
handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
void onPause(LifecycleOwner owner) {
mViewState = Lifecycle.State.STARTED;
if (mLifecycleRegistry.getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void onStop(LifecycleOwner owner) {
mViewState = Lifecycle.State.CREATED;
if (mLifecycleRegistry.getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
handleLifecycleEvent(Lifecycle.Event.ON_STOP);
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
void onDestroy(LifecycleOwner owner) {
mViewState = Lifecycle.State.DESTROYED;
handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
}
interface Callback {
boolean isVisibleToUser();
}
}
\ No newline at end of file
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* 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.gingersoft.gsa.cloud.base.qmui.arch;
import android.annotation.SuppressLint;
import android.view.View;
import android.view.ViewGroup;
import com.qmuiteam.qmui.widget.QMUIPagerAdapter;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
public abstract class QMUIFragmentPagerAdapter extends QMUIPagerAdapter {
private final FragmentManager mFragmentManager;
private FragmentTransaction mCurrentTransaction;
private Fragment mCurrentPrimaryItem = null;
public QMUIFragmentPagerAdapter(@NonNull FragmentManager fm) {
mFragmentManager = fm;
}
public abstract Fragment createFragment(int position);
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view == ((Fragment) object).getView();
}
@SuppressLint("CommitTransaction")
@Override
@NonNull
protected Object hydrate(@NonNull ViewGroup container, int position) {
String name = makeFragmentName(container.getId(), position);
if (mCurrentTransaction == null) {
mCurrentTransaction = mFragmentManager.beginTransaction();
}
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
return fragment;
}
return createFragment(position);
}
@SuppressLint("CommitTransaction")
@Override
protected void populate(@NonNull ViewGroup container, @NonNull Object item, int position) {
String name = makeFragmentName(container.getId(), position);
if (mCurrentTransaction == null) {
mCurrentTransaction = mFragmentManager.beginTransaction();
}
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
mCurrentTransaction.attach(fragment);
if (fragment.getView() != null && fragment.getView().getWidth() == 0) {
fragment.getView().requestLayout();
}
} else {
fragment = (Fragment) item;
mCurrentTransaction.add(container.getId(), fragment, name);
}
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
}
@SuppressLint("CommitTransaction")
@Override
protected void destroy(@NonNull ViewGroup container, int position, @NonNull Object object) {
if (mCurrentTransaction == null) {
mCurrentTransaction = mFragmentManager.beginTransaction();
}
mCurrentTransaction.detach((Fragment) object);
}
@Override
public void startUpdate(@NonNull ViewGroup container) {
if (container.getId() == View.NO_ID) {
throw new IllegalStateException("ViewPager with adapter " + this
+ " requires a view id");
}
}
@Override
public void finishUpdate(@NonNull ViewGroup container) {
if (mCurrentTransaction != null) {
mCurrentTransaction.commitNowAllowingStateLoss();
mCurrentTransaction = null;
}
}
@Override
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
Fragment fragment = (Fragment) object;
if (fragment != mCurrentPrimaryItem) {
if (mCurrentPrimaryItem != null) {
mCurrentPrimaryItem.setMenuVisibility(false);
mCurrentPrimaryItem.setUserVisibleHint(false);
}
fragment.setMenuVisibility(true);
fragment.setUserVisibleHint(true);
mCurrentPrimaryItem = fragment;
}
}
private String makeFragmentName(int viewId, long id) {
return "QMUIFragmentPagerAdapter:" + viewId + ":" + id;
}
}
\ No newline at end of file
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* 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.gingersoft.gsa.cloud.base.qmui.arch;
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import java.util.Stack;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class QMUISwipeBackActivityManager implements Application.ActivityLifecycleCallbacks {
private static QMUISwipeBackActivityManager sInstance;
private Stack<Activity> mActivityStack = new Stack<>();
@MainThread
public static QMUISwipeBackActivityManager getInstance() {
if (sInstance == null) {
throw new IllegalAccessError("the QMUISwipeBackActivityManager is not initialized; " +
"please call QMUISwipeBackActivityManager.init(Application) in your application.");
}
return sInstance;
}
private QMUISwipeBackActivityManager() {
}
public static void init(@NonNull Application application) {
if (sInstance == null) {
sInstance = new QMUISwipeBackActivityManager();
application.registerActivityLifecycleCallbacks(sInstance);
}
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
mActivityStack.add(activity);
}
@Override
public void onActivityDestroyed(Activity activity) {
mActivityStack.remove(activity);
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
/**
*
* refer to https://github.com/bingoogolapple/BGASwipeBackLayout-Android/
* @param currentActivity the last activity
* @return
*/
@Nullable
public Activity getPenultimateActivity(Activity currentActivity) {
Activity activity = null;
try {
if (mActivityStack.size() > 1) {
activity = mActivityStack.get(mActivityStack.size() - 2);
if (currentActivity.equals(activity)) {
int index = mActivityStack.indexOf(currentActivity);
if (index > 0) {
// if memory leaks or the last activity is being finished
activity = mActivityStack.get(index - 1);
} else if (mActivityStack.size() == 2) {
// if screen orientation changes, there may be an error sequence in the stack
activity = mActivityStack.lastElement();
}
}
}
} catch (Exception ignored) {
}
return activity;
}
public boolean canSwipeBack() {
return mActivityStack.size() > 1;
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* 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.gingersoft.gsa.cloud.base.qmui.arch;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.gingersoft.gsa.cloud.base.R;
import com.qmuiteam.qmui.widget.QMUIWindowInsetLayout;
import java.util.ArrayList;
import java.util.List;
import androidx.core.view.ViewCompat;
import androidx.customview.widget.ViewDragHelper;
/**
* Created by cgspine on 2018/1/7.
* <p>
* modified from https://github.com/ikew0ng/SwipeBackLayout
*/
public class SwipeBackLayout extends QMUIWindowInsetLayout {
/**
* Minimum velocity that will be detected as a fling
*/
private static final int MIN_FLING_VELOCITY = 400; // dips per second
private static final int DEFAULT_SCRIM_COLOR = 0x99000000;
private static final int FULL_ALPHA = 255;
/**
* Edge flag indicating that the left edge should be affected.
*/
public static final int EDGE_LEFT = ViewDragHelper.EDGE_LEFT;
/**
* Edge flag indicating that the right edge should be affected.
*/
public static final int EDGE_RIGHT = ViewDragHelper.EDGE_RIGHT;
/**
* Edge flag indicating that the bottom edge should be affected.
*/
public static final int EDGE_BOTTOM = ViewDragHelper.EDGE_BOTTOM;
/**
* Edge flag set indicating all edges should be affected.
*/
public static final int EDGE_ALL = EDGE_LEFT | EDGE_RIGHT | EDGE_BOTTOM;
/**
* A view is not currently being dragged or animating as a result of a
* fling/snap.
*/
public static final int STATE_IDLE = ViewDragHelper.STATE_IDLE;
/**
* A view is currently being dragged. The position is currently changing as
* a result of user input or simulated user input.
*/
public static final int STATE_DRAGGING = ViewDragHelper.STATE_DRAGGING;
/**
* A view is currently settling into place as a result of a fling or
* predefined non-interactive motion.
*/
public static final int STATE_SETTLING = ViewDragHelper.STATE_SETTLING;
/**
* Default threshold of scroll
*/
private static final float DEFAULT_SCROLL_THRESHOLD = 0.3f;
private static final int OVERSCROLL_DISTANCE = 10;
private static final int[] EDGE_FLAGS = {
EDGE_LEFT, EDGE_RIGHT, EDGE_BOTTOM, EDGE_ALL
};
private int mEdgeFlag;
/**
* Threshold of scroll, we will close the activity, when scrollPercent over
* this value;
*/
private float mScrollThreshold = DEFAULT_SCROLL_THRESHOLD;
private View mContentView;
private ViewDragHelper mDragHelper;
private float mScrollPercent;
private int mContentLeft;
private int mContentTop;
/**
* The set of listeners to be sent events through.
*/
private List<SwipeListener> mListeners;
private Drawable mShadowLeft;
private Drawable mShadowRight;
private Drawable mShadowBottom;
private float mScrimOpacity;
private int mScrimColor = DEFAULT_SCRIM_COLOR;
private boolean mInLayout;
private Rect mTmpRect = new Rect();
/**
* Edge being dragged
*/
private int mTrackingEdge;
private Callback mCallback;
private boolean mPreventSwipeBackWhenDown = false;
private boolean mLayoutFrozen = false;
private boolean mLayoutWasDefered;
public SwipeBackLayout(Context context) {
this(context, null);
}
public SwipeBackLayout(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.SwipeBackLayoutStyle);
}
public SwipeBackLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs);
mDragHelper = ViewDragHelper.create(this, new ViewDragCallback());
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwipeBackLayout, defStyle,
R.style.SwipeBackLayout);
int mode = EDGE_FLAGS[a.getInt(R.styleable.SwipeBackLayout_edge_flag, 0)];
setEdgeTrackingEnabled(mode);
int shadowLeft = a.getResourceId(R.styleable.SwipeBackLayout_shadow_left,
R.drawable.shadow_left);
int shadowRight = a.getResourceId(R.styleable.SwipeBackLayout_shadow_right,
R.drawable.shadow_right);
int shadowBottom = a.getResourceId(R.styleable.SwipeBackLayout_shadow_bottom,
R.drawable.shadow_bottom);
setShadow(shadowLeft, EDGE_LEFT);
setShadow(shadowRight, EDGE_RIGHT);
setShadow(shadowBottom, EDGE_BOTTOM);
a.recycle();
final float density = getResources().getDisplayMetrics().density;
final float minVel = MIN_FLING_VELOCITY * density;
mDragHelper.setMinVelocity(minVel);
}
/**
* Set up contentView which will be moved by user gesture
*
* @param view
*/
private void setContentView(View view) {
mContentView = view;
}
public View getContentView() {
return mContentView;
}
public void setCallback(Callback callback) {
mCallback = callback;
}
private boolean canSwipeBack() {
return mCallback == null || mCallback.canSwipeBack();
}
/**
* Enable edge tracking for the selected edges of the parent view. The
* callback's
* {@link ViewDragHelper.Callback#onEdgeTouched(int, int)}
* and
* {@link ViewDragHelper.Callback#onEdgeDragStarted(int, int)}
* methods will only be invoked for edges for which edge tracking has been
* enabled.
*
* @param edgeFlags Combination of edge flags describing the edges to watch
* @see #EDGE_LEFT
* @see #EDGE_RIGHT
* @see #EDGE_BOTTOM
*/
public void setEdgeTrackingEnabled(int edgeFlags) {
mEdgeFlag = edgeFlags;
mDragHelper.setEdgeTrackingEnabled(mEdgeFlag);
}
/**
* Set a color to use for the scrim that obscures primary content while a
* drawer is open.
*
* @param color Color to use in 0xAARRGGBB format.
*/
public void setScrimColor(int color) {
mScrimColor = color;
invalidate();
}
/**
* Add a callback to be invoked when a swipe event is sent to this view.
*
* @param listener the swipe listener to attach to this view
*/
public ListenerRemover addSwipeListener(final SwipeListener listener) {
if (mListeners == null) {
mListeners = new ArrayList<>();
}
mListeners.add(listener);
return new ListenerRemover() {
@Override
public void remove() {
mListeners.remove(listener);
}
};
}
/**
* Removes a listener from the set of listeners
*
* @param listener
*/
public void removeSwipeListener(SwipeListener listener) {
if (mListeners == null) {
return;
}
mListeners.remove(listener);
}
public void clearSwipeListeners() {
if (mListeners == null) {
return;
}
mListeners.clear();
mListeners = null;
}
public interface SwipeListener {
/**
* Invoke when state change
*
* @param state flag to describe scroll state
* @param scrollPercent scroll percent of this view
* @see #STATE_IDLE
* @see #STATE_DRAGGING
* @see #STATE_SETTLING
*/
void onScrollStateChange(int state, float scrollPercent);
/**
* Invoke when scrolling
*
* @param edgeFlag flag to describe edge
* @param scrollPercent scroll percent of this view
*/
void onScroll(int edgeFlag, float scrollPercent);
/**
* Invoke when edge touched
*
* @param edgeFlag edge flag describing the edge being touched
* @see #EDGE_LEFT
* @see #EDGE_RIGHT
* @see #EDGE_BOTTOM
*/
void onEdgeTouch(int edgeFlag);
/**
* Invoke when scroll percent over the threshold for the first time
*/
void onScrollOverThreshold();
}
/**
* Set scroll threshold, we will close the activity, when scrollPercent over
* this value
*
* @param threshold
*/
public void setScrollThresHold(float threshold) {
if (threshold >= 1.0f || threshold <= 0) {
throw new IllegalArgumentException("Threshold value should be between 0 and 1.0");
}
mScrollThreshold = threshold;
}
/**
* Set a drawable used for edge shadow.
*
* @param shadow Drawable to use
* @param edgeFlag Combination of edge flags describing the edge to set
* @see #EDGE_LEFT
* @see #EDGE_RIGHT
* @see #EDGE_BOTTOM
*/
public void setShadow(Drawable shadow, int edgeFlag) {
if ((edgeFlag & EDGE_LEFT) != 0) {
mShadowLeft = shadow;
} else if ((edgeFlag & EDGE_RIGHT) != 0) {
mShadowRight = shadow;
} else if ((edgeFlag & EDGE_BOTTOM) != 0) {
mShadowBottom = shadow;
}
invalidate();
}
/**
* Set a drawable used for edge shadow.
*
* @param resId Resource of drawable to use
* @param edgeFlag Combination of edge flags describing the edge to set
* @see #EDGE_LEFT
* @see #EDGE_RIGHT
* @see #EDGE_BOTTOM
*/
public void setShadow(int resId, int edgeFlag) {
setShadow(getResources().getDrawable(resId), edgeFlag);
}
private boolean preventSwipeBack(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mPreventSwipeBackWhenDown = !canSwipeBack();
return mPreventSwipeBackWhenDown;
} else {
return !canSwipeBack() || mPreventSwipeBackWhenDown;
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (preventSwipeBack(event)) {
return false;
}
try {
return mDragHelper.shouldInterceptTouchEvent(event);
} catch (ArrayIndexOutOfBoundsException e) {
return false;
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (preventSwipeBack(event)) {
return false;
}
mDragHelper.processTouchEvent(event);
return true;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
mInLayout = true;
if (mContentView != null)
mContentView.layout(mContentLeft, mContentTop,
mContentLeft + mContentView.getMeasuredWidth(),
mContentTop + mContentView.getMeasuredHeight());
mInLayout = false;
}
@Override
public void requestLayout() {
if (!mLayoutFrozen) {
super.requestLayout();
} else {
mLayoutWasDefered = true;
}
}
private void setLayoutFrozen(boolean frozen) {
if (frozen != mLayoutFrozen) {
if (!frozen) {
mLayoutFrozen = false;
if (mLayoutWasDefered) {
requestLayout();
}
mLayoutWasDefered = false;
} else {
mLayoutFrozen = true;
}
}
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
final boolean drawContent = child == mContentView;
boolean ret = super.drawChild(canvas, child, drawingTime);
if (mScrimOpacity > 0 && drawContent
&& mDragHelper.getViewDragState() != ViewDragHelper.STATE_IDLE) {
drawShadow(canvas, child);
drawScrim(canvas, child);
}
return ret;
}
private void drawScrim(Canvas canvas, View child) {
final int baseAlpha = (mScrimColor & 0xff000000) >>> 24;
final int alpha = (int) (baseAlpha * mScrimOpacity);
final int color = alpha << 24 | (mScrimColor & 0xffffff);
if ((mTrackingEdge & EDGE_LEFT) != 0) {
canvas.clipRect(0, 0, child.getLeft(), getHeight());
} else if ((mTrackingEdge & EDGE_RIGHT) != 0) {
canvas.clipRect(child.getRight(), 0, getRight(), getHeight());
} else if ((mTrackingEdge & EDGE_BOTTOM) != 0) {
canvas.clipRect(child.getLeft(), child.getBottom(), getRight(), getHeight());
}
canvas.drawColor(color);
}
private void drawShadow(Canvas canvas, View child) {
final Rect childRect = mTmpRect;
child.getHitRect(childRect);
if ((mEdgeFlag & EDGE_LEFT) != 0) {
mShadowLeft.setBounds(childRect.left - mShadowLeft.getIntrinsicWidth(),
childRect.top, childRect.left, childRect.bottom);
mShadowLeft.setAlpha((int) (mScrimOpacity * FULL_ALPHA));
mShadowLeft.draw(canvas);
}
if ((mEdgeFlag & EDGE_RIGHT) != 0) {
mShadowRight.setBounds(childRect.right, childRect.top,
childRect.right + mShadowRight.getIntrinsicWidth(), childRect.bottom);
mShadowRight.setAlpha((int) (mScrimOpacity * FULL_ALPHA));
mShadowRight.draw(canvas);
}
if ((mEdgeFlag & EDGE_BOTTOM) != 0) {
mShadowBottom.setBounds(childRect.left, childRect.bottom, childRect.right,
childRect.bottom + mShadowBottom.getIntrinsicHeight());
mShadowBottom.setAlpha((int) (mScrimOpacity * FULL_ALPHA));
mShadowBottom.draw(canvas);
}
}
@Override
public void computeScroll() {
mScrimOpacity = 1 - mScrollPercent;
if (mDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
private class ViewDragCallback extends ViewDragHelper.Callback {
private boolean mIsScrollOverValid;
@Override
public boolean tryCaptureView(View view, int i) {
boolean ret = mDragHelper.isEdgeTouched(mEdgeFlag, i);
if (ret) {
if (mDragHelper.isEdgeTouched(EDGE_LEFT, i)) {
mTrackingEdge = EDGE_LEFT;
} else if (mDragHelper.isEdgeTouched(EDGE_RIGHT, i)) {
mTrackingEdge = EDGE_RIGHT;
} else if (mDragHelper.isEdgeTouched(EDGE_BOTTOM, i)) {
mTrackingEdge = EDGE_BOTTOM;
}
if (mListeners != null && !mListeners.isEmpty()) {
for (SwipeListener listener : mListeners) {
listener.onEdgeTouch(mTrackingEdge);
}
}
mIsScrollOverValid = true;
}
boolean directionCheck = false;
if (mEdgeFlag == EDGE_LEFT || mEdgeFlag == EDGE_RIGHT) {
directionCheck = !mDragHelper.checkTouchSlop(ViewDragHelper.DIRECTION_VERTICAL, i);
} else if (mEdgeFlag == EDGE_BOTTOM) {
directionCheck = !mDragHelper
.checkTouchSlop(ViewDragHelper.DIRECTION_HORIZONTAL, i);
} else if (mEdgeFlag == EDGE_ALL) {
directionCheck = true;
}
return ret & directionCheck;
}
@Override
public int getViewHorizontalDragRange(View child) {
return mEdgeFlag & (EDGE_LEFT | EDGE_RIGHT);
}
@Override
public int getViewVerticalDragRange(View child) {
return mEdgeFlag & EDGE_BOTTOM;
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
if ((mTrackingEdge & EDGE_LEFT) != 0) {
mScrollPercent = Math.abs((float) left
/ (mContentView.getWidth() + mShadowLeft.getIntrinsicWidth()));
} else if ((mTrackingEdge & EDGE_RIGHT) != 0) {
mScrollPercent = Math.abs((float) left
/ (mContentView.getWidth() + mShadowRight.getIntrinsicWidth()));
} else if ((mTrackingEdge & EDGE_BOTTOM) != 0) {
mScrollPercent = Math.abs((float) top
/ (mContentView.getHeight() + mShadowBottom.getIntrinsicHeight()));
}
mContentLeft = left;
mContentTop = top;
invalidate();
if (mScrollPercent < mScrollThreshold && !mIsScrollOverValid) {
mIsScrollOverValid = true;
}
if (mListeners != null && !mListeners.isEmpty()) {
if (mDragHelper.getViewDragState() == STATE_DRAGGING &&
mScrollPercent >= mScrollThreshold && mIsScrollOverValid) {
mIsScrollOverValid = false;
for (SwipeListener listener : mListeners) {
listener.onScrollOverThreshold();
}
}
for (SwipeListener listener : mListeners) {
listener.onScroll(mTrackingEdge, mScrollPercent);
}
}
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
final int childWidth = releasedChild.getWidth();
final int childHeight = releasedChild.getHeight();
int left = 0, top = 0;
if ((mTrackingEdge & EDGE_LEFT) != 0) {
left = xvel > 0 || xvel == 0 && mScrollPercent > mScrollThreshold ? childWidth
+ mShadowLeft.getIntrinsicWidth() + OVERSCROLL_DISTANCE : 0;
} else if ((mTrackingEdge & EDGE_RIGHT) != 0) {
left = xvel < 0 || xvel == 0 && mScrollPercent > mScrollThreshold ? -(childWidth
+ mShadowLeft.getIntrinsicWidth() + OVERSCROLL_DISTANCE) : 0;
} else if ((mTrackingEdge & EDGE_BOTTOM) != 0) {
top = yvel < 0 || yvel == 0 && mScrollPercent > mScrollThreshold ? -(childHeight
+ mShadowBottom.getIntrinsicHeight() + OVERSCROLL_DISTANCE) : 0;
}
mDragHelper.settleCapturedViewAt(left, top);
invalidate();
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
int ret = 0;
if ((mEdgeFlag & EDGE_LEFT) != 0) {
ret = Math.min(child.getWidth(), Math.max(left, 0));
} else if ((mEdgeFlag & EDGE_RIGHT) != 0) {
ret = Math.min(0, Math.max(left, -child.getWidth()));
}
return ret;
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
int ret = 0;
if ((mEdgeFlag & EDGE_BOTTOM) != 0) {
ret = Math.min(0, Math.max(top, -child.getHeight()));
}
return ret;
}
@Override
public void onViewDragStateChanged(int state) {
super.onViewDragStateChanged(state);
if (mListeners != null && !mListeners.isEmpty()) {
for (SwipeListener listener : mListeners) {
listener.onScrollStateChange(state, mScrollPercent);
}
}
setLayoutFrozen(state != STATE_IDLE);
}
}
public static SwipeBackLayout wrap(View child, int edgeFlag, Callback callback) {
SwipeBackLayout wrapper = new SwipeBackLayout(child.getContext());
wrapper.setEdgeTrackingEnabled(edgeFlag);
wrapper.addView(child, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
wrapper.setContentView(child);
wrapper.setCallback(callback);
return wrapper;
}
public static SwipeBackLayout wrap(Context context, int childRes, int edgeFlag, Callback callback) {
SwipeBackLayout wrapper = new SwipeBackLayout(context);
wrapper.setEdgeTrackingEnabled(edgeFlag);
View child = LayoutInflater.from(context).inflate(childRes, wrapper, false);
wrapper.addView(child, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
wrapper.setContentView(child);
wrapper.setCallback(callback);
return wrapper;
}
static void offsetInEdgeTouch(View view, int edgeFlag, int offset) {
if (edgeFlag == EDGE_BOTTOM) {
ViewCompat.offsetTopAndBottom(view, offset);
} else if (edgeFlag == EDGE_RIGHT) {
ViewCompat.offsetLeftAndRight(view, offset);
} else {
ViewCompat.offsetLeftAndRight(view, -1 * offset);
}
}
static void offsetInScroll(View view, int edgeFlag, int targetOffset) {
if (edgeFlag == EDGE_BOTTOM) {
ViewCompat.offsetTopAndBottom(view, targetOffset - view.getTop());
} else if (edgeFlag == EDGE_RIGHT) {
ViewCompat.offsetLeftAndRight(view, targetOffset - view.getLeft());
} else {
ViewCompat.offsetLeftAndRight(view, -targetOffset - view.getLeft());
}
}
public interface Callback {
boolean canSwipeBack();
}
public interface ListenerRemover {
void remove();
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* 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.gingersoft.gsa.cloud.base.qmui.arch;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.IBinder;
import android.util.AttributeSet;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import com.qmuiteam.qmui.util.QMUIColorHelper;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
class SwipeBackgroundView extends View {
private ArrayList<ViewInfo> mViewWeakReference;
private boolean mDoRotate = false;
public SwipeBackgroundView(Context context) {
super(context);
}
public SwipeBackgroundView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public void bind(Activity activity, Activity swipeActivity, boolean restoreForSubWindow) {
mDoRotate = false;
if (mViewWeakReference != null) {
mViewWeakReference.clear();
}
int orientation = activity.getResources().getConfiguration().orientation;
if (orientation != getResources().getConfiguration().orientation) {
// the screen orientation changed, reMeasure and reLayout
int requestedOrientation = activity.getRequestedOrientation();
if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ||
requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
// TODO is it suitable for fixed screen orientation
// the prev activity has locked the screen orientation
mDoRotate = true;
} else if (swipeActivity instanceof InnerBaseActivity) {
swipeActivity.getWindow().getDecorView().setBackgroundColor(0);
((InnerBaseActivity) swipeActivity).convertToTranslucentCauseOrientationChanged();
invalidate();
return;
}
}
if (!restoreForSubWindow) {
View contentView = activity.findViewById(Window.ID_ANDROID_CONTENT);
if (mViewWeakReference == null) {
mViewWeakReference = new ArrayList<>();
}
mViewWeakReference.add(new ViewInfo(contentView, null, true));
invalidate();
return;
}
try {
IBinder windowToken = activity.getWindow().getDecorView().getWindowToken();
Field windowManagerGlobalField = activity.getWindowManager().getClass().getDeclaredField("mGlobal");
windowManagerGlobalField.setAccessible(true);
Object windowManagerGlobal = windowManagerGlobalField.get(activity.getWindowManager());
if (windowManagerGlobal != null) {
Field viewsField = windowManagerGlobal.getClass().getDeclaredField("mViews");
viewsField.setAccessible(true);
Field paramsField = windowManagerGlobal.getClass().getDeclaredField("mParams");
paramsField.setAccessible(true);
List<WindowManager.LayoutParams> params = (List<WindowManager.LayoutParams>) paramsField.get(windowManagerGlobal);
List<View> views = (List<View>) viewsField.get(windowManagerGlobal);
IBinder activityToken = null;
// reverse order
for (int i = params.size() - 1; i >= 0; i--) {
WindowManager.LayoutParams lp = params.get(i);
View view = views.get(i);
if (view.getWindowToken() == windowToken) {
activityToken = lp.token;
break;
}
}
if (activityToken != null) {
// reverse order
for (int i = params.size() - 1; i >= 0; i--) {
WindowManager.LayoutParams lp = params.get(i);
View view = views.get(i);
boolean isMain = view.getWindowToken() == windowToken;
// Dialog use activityToken in lp
// PopupWindow use windowToken in lp
if (isMain || lp.token == activityToken || lp.token == windowToken) {
View prevContentView = view.findViewById(Window.ID_ANDROID_CONTENT);
if (mViewWeakReference == null) {
mViewWeakReference = new ArrayList<>();
}
if (prevContentView != null) {
mViewWeakReference.add(new ViewInfo(prevContentView, lp, isMain));
}else {
// PopupWindow doest not exist a descendant view with id Window.ID_ANDROID_CONTENT
mViewWeakReference.add(new ViewInfo(view, lp, isMain));
}
}
}
}
}
} catch (Exception ignored) {
} finally {
// sure get one view
if (mViewWeakReference == null || mViewWeakReference.isEmpty()) {
View contentView = activity.findViewById(Window.ID_ANDROID_CONTENT);
if (mViewWeakReference == null) {
mViewWeakReference = new ArrayList<>();
}
mViewWeakReference.add(new ViewInfo(contentView, null, true));
}
}
invalidate();
}
public void unBind() {
if (mViewWeakReference != null) {
mViewWeakReference.clear();
}
mViewWeakReference = null;
mDoRotate = false;
}
boolean hasChildWindow() {
return mViewWeakReference != null && mViewWeakReference.size() > 1;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mViewWeakReference != null && mViewWeakReference.size() > 0) {
if (mDoRotate) {
canvas.translate(0, getHeight());
canvas.rotate(-90, 0, 0);
}
// reverse order
for (int i = mViewWeakReference.size() - 1; i >= 0; i--) {
mViewWeakReference.get(i).draw(canvas);
}
}
}
static class ViewInfo {
WeakReference<View> viewRef;
WindowManager.LayoutParams lp;
boolean isMain;
private int[] tempLocations = new int[2];
public ViewInfo(@NonNull View view, @Nullable WindowManager.LayoutParams lp, boolean isMain) {
this.viewRef = new WeakReference<>(view);
this.lp = lp;
this.isMain = isMain;
}
void draw(Canvas canvas) {
View view = viewRef.get();
if (view != null) {
if (isMain || lp == null) {
view.draw(canvas);
} else {
canvas.drawColor(QMUIColorHelper.setColorAlpha(Color.BLACK, lp.dimAmount));
view.getLocationOnScreen(tempLocations);
canvas.translate(tempLocations[0], tempLocations[1]);
view.draw(canvas);
canvas.translate(-tempLocations[0], -tempLocations[1]);
}
}
}
}
}
/*
* Tencent is pleased to support the open source community by making QMUI_Android available.
*
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the MIT License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://opensource.org/licenses/MIT
*
* 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.gingersoft.gsa.cloud.base.qmui.arch;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ActivityOptions;
import android.os.Build;
import android.os.Looper;
import com.qmuiteam.qmui.QMUILog;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import androidx.fragment.app.FragmentManager;
/**
* Created by Chaojun Wang on 6/9/14.
*/
public class Utils {
private Utils() {
}
/**
* Convert a translucent themed Activity
* {@link android.R.attr#windowIsTranslucent} to a fullscreen opaque
* Activity.
* <p>
* Call this whenever the background of a translucent Activity has changed
* to become opaque. Doing so will allow the {@link android.view.Surface} of
* the Activity behind to be released.
* <p>
* This call has no effect on non-translucent activities or on activities
* with the {@link android.R.attr#windowIsFloating} attribute.
*/
public static void convertActivityFromTranslucent(Activity activity) {
try {
@SuppressLint("PrivateApi") Method method = Activity.class.getDeclaredMethod("convertFromTranslucent");
method.setAccessible(true);
method.invoke(activity);
} catch (Throwable ignore) {
}
}
/**
* Convert a translucent themed Activity
* {@link android.R.attr#windowIsTranslucent} back from opaque to
* translucent following a call to
* {@link #convertActivityFromTranslucent(Activity)} .
* <p>
* Calling this allows the Activity behind this one to be seen again. Once
* all such Activities have been redrawn
* <p>
* This call has no effect on non-translucent activities or on activities
* with the {@link android.R.attr#windowIsFloating} attribute.
*/
public static void convertActivityToTranslucent(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
convertActivityToTranslucentAfterL(activity);
} else {
convertActivityToTranslucentBeforeL(activity);
}
}
/**
* Calling the convertToTranslucent method on platforms before Android 5.0
*/
private static void convertActivityToTranslucentBeforeL(Activity activity) {
try {
Class<?>[] classes = Activity.class.getDeclaredClasses();
Class<?> translucentConversionListenerClazz = null;
for (Class clazz : classes) {
if (clazz.getSimpleName().contains("TranslucentConversionListener")) {
translucentConversionListenerClazz = clazz;
}
}
@SuppressLint("PrivateApi") Method method = Activity.class.getDeclaredMethod("convertToTranslucent",
translucentConversionListenerClazz);
method.setAccessible(true);
method.invoke(activity, new Object[]{
null
});
} catch (Throwable ignore) {
}
}
/**
* Calling the convertToTranslucent method on platforms after Android 5.0
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static void convertActivityToTranslucentAfterL(Activity activity) {
try {
@SuppressLint("PrivateApi") Method getActivityOptions = Activity.class.getDeclaredMethod("getActivityOptions");
getActivityOptions.setAccessible(true);
Object options = getActivityOptions.invoke(activity);
Class<?>[] classes = Activity.class.getDeclaredClasses();
Class<?> translucentConversionListenerClazz = null;
for (Class clazz : classes) {
if (clazz.getSimpleName().contains("TranslucentConversionListener")) {
translucentConversionListenerClazz = clazz;
}
}
@SuppressLint("PrivateApi") Method convertToTranslucent = Activity.class.getDeclaredMethod("convertToTranslucent",
translucentConversionListenerClazz, ActivityOptions.class);
convertToTranslucent.setAccessible(true);
convertToTranslucent.invoke(activity, null, options);
} catch (Throwable ignore) {
}
}
public static void assertInMainThread() {
if (Looper.myLooper() != Looper.getMainLooper()) {
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
String methodMsg = null;
if (elements != null && elements.length >= 4) {
methodMsg = elements[3].toString();
}
throw new IllegalStateException("Call the method must be in main thread: " + methodMsg);
}
}
static void findAndModifyOpInBackStackRecord(FragmentManager fragmentManager, int backStackIndex, OpHandler handler) {
if (fragmentManager == null || handler == null) {
return;
}
int backStackCount = fragmentManager.getBackStackEntryCount();
if (backStackCount > 0) {
if (backStackIndex >= backStackCount || backStackIndex < -backStackCount) {
QMUILog.d("findAndModifyOpInBackStackRecord", "backStackIndex error: " +
"backStackIndex = " + backStackIndex + " ; backStackCount = " + backStackCount);
return;
}
if (backStackIndex < 0) {
backStackIndex = backStackCount + backStackIndex;
}
try {
FragmentManager.BackStackEntry backStackEntry = fragmentManager.getBackStackEntryAt(backStackIndex);
if (handler.needReNameTag()) {
Field nameField = backStackEntry.getClass().getDeclaredField("mName");
nameField.setAccessible(true);
nameField.set(backStackEntry, handler.newTagName());
}
Field opsField = backStackEntry.getClass().getDeclaredField("mOps");
opsField.setAccessible(true);
Object opsObj = opsField.get(backStackEntry);
if (opsObj instanceof List<?>) {
List<?> ops = (List<?>) opsObj;
for (Object op : ops) {
if (handler.handle(op)) {
return;
}
}
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
interface OpHandler {
boolean handle(Object op);
boolean needReNameTag();
String newTagName();
}
}
package com.gingersoft.gsa.cloud.base.utils.time;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @ClassName: TimeUtils
* @Description: TODO(时间工具类)
*/
public class TimeUtils {
public static final SimpleDateFormat DEFAULT_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//, Locale.CHINESE
public static final SimpleDateFormat DATE_FORMAT_DATE = new SimpleDateFormat("yyyy-MM-dd");
public static final SimpleDateFormat DATE_FORMAT_DATE1 = new SimpleDateFormat(
"HH:mm");
private TimeUtils() {
throw new AssertionError();
}
/**
* long time to string
*
* @param timeInMillis
* @param dateFormat
* @return
*/
public static String getTime(long timeInMillis, SimpleDateFormat dateFormat) {
return dateFormat.format(new Date(timeInMillis));
}
/**
* long time to string, format is {@link #DEFAULT_DATE_FORMAT}
*
* @param timeInMillis
* @return
*/
public static String getCurrentTime(long timeInMillis) {
return getTime(timeInMillis, DEFAULT_DATE_FORMAT);
}
/**
* get current time in milliseconds
*
* @return
*/
public static long getCurrentTimeInLong() {
return System.currentTimeMillis();
}
/**
* get current time in milliseconds
*
* @return
*/
public static String getCurrentTimeInString(SimpleDateFormat dateFormat) {
return getTime(getCurrentTimeInLong(), dateFormat);
}
/**
* 把日期型字符串转换为数字型字符串
*
* @param time
* @return
*/
public static String tranTime(String time) {
if (time != null) {
String year;
String month;
String day;
String hour;
String minute;
String second;
year = time.substring(0, 4);
month = time.substring(5, 7);
day = time.substring(8, 10);
hour = time.substring(11, 13);
minute = time.substring(14, 16);
second = time.substring(17, 19);
String newTime = String.format("%s%s%s%s%s%s", year, month, day,
hour, minute, second);
return newTime;
} else
return time;
}
/**
* 字符串转换成日期
*
* @param str
* @return date
*/
public static Date StrToDate(String str) {
Date date = null;
try {
date = DEFAULT_DATE_FORMAT.parse(str);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
/**
* 把日期转为字符串
*
* @param date
* @return
* @Title: ConverToString
* @Description: TODO(这里用一句话描述这个方法的作用)
*/
public static String ConverToString(Date date) {
return DATE_FORMAT_DATE1.format(date);
}
/**
* 日期转换成秒数
*/
public static long getSecondsFromDate(String expireDate) {
if (expireDate == null || expireDate.trim().equals(""))
return 0;
Date date = null;
try {
date = DEFAULT_DATE_FORMAT.parse(expireDate);
return (long) (date.getTime() / 1000);
} catch (ParseException e) {
e.printStackTrace();
return 0L;
}
}
//
// /**
// * 时间戳格式转换
// */
// static String dayNames[] = {app.getString(R.string.sunday), app.getString(R.string.monday),
// app.getString(R.string.tuesday), app.getString(R.string.wednesday), app.getString(R.string.thursday),
// app.getString(R.string.friday), app.getString(R.string.saturday)};
//
// public static String getNewChatTime(long timesamp) {
// String result = "";
// Calendar todayCalendar = Calendar.getInstance();
// Calendar otherCalendar = Calendar.getInstance();
// otherCalendar.setTimeInMillis(timesamp);
// String timeFormat = "M" + app.getString(R.string.month) + "d" + app.getString(R.string.day) + " " + "HH:mm";
// String yearTimeFormat = "yyyy" + app.getString(R.string.year) + "M" + app.getString(R.string.month) + "d" + app.getString(R.string.day) + " " + "HH:mm";
// String am_pm = "";
// int hour = otherCalendar.get(Calendar.HOUR_OF_DAY);
// if (hour >= 0 && hour < 6) {
// am_pm = app.getString(R.string.early_morning);
// } else if (hour >= 6 && hour < 12) {
// am_pm = app.getString(R.string.morning);
// } else if (hour == 12) {
// am_pm = app.getString(R.string.noon);
// } else if (hour > 12 && hour < 18) {
// am_pm = app.getString(R.string.afternoon);
// } else if (hour >= 18) {
// am_pm = app.getString(R.string.at_night);
// }
// timeFormat = "M" + app.getString(R.string.month) + "d" + app.getString(R.string.day) + " " + am_pm + "HH:mm";
// yearTimeFormat = "yyyy" + app.getString(R.string.year) + "M" + app.getString(R.string.month) + "d" + app.getString(R.string.day) + " " + am_pm + "HH:mm";
//
// boolean yearTemp = todayCalendar.get(Calendar.YEAR) == otherCalendar.get(Calendar.YEAR);
// if (yearTemp) {
// int todayMonth = todayCalendar.get(Calendar.MONTH);
// int otherMonth = otherCalendar.get(Calendar.MONTH);
// if (todayMonth == otherMonth) {//表示是同一个月
// int temp = todayCalendar.get(Calendar.DATE) - otherCalendar.get(Calendar.DATE);
// switch (temp) {
// case 0:
// result = am_pm + " " + getHourAndMin(timesamp);
// break;
// case 1:
// result = app.getString(R.string.yesterday) + " " + am_pm + " " + getHourAndMin(timesamp);
// break;
// case 2:
// case 3:
// case 4:
// case 5:
// case 6:
// int dayOfMonth = otherCalendar.get(Calendar.WEEK_OF_MONTH);
// int todayOfMonth = todayCalendar.get(Calendar.WEEK_OF_MONTH);
// if (dayOfMonth == todayOfMonth) {//表示是同一周
//// int dayOfWeek=otherCalendar.get(Calendar.DAY_OF_WEEK);
//// if(dayOfWeek!=1){//判断当前是不是星期日 如想显示为:周日 12:09 可去掉此判断
// result = dayNames[otherCalendar.get(Calendar.DAY_OF_WEEK) - 1] + " " + am_pm + " " + getHourAndMin(timesamp);
//// }else{
//// result = getTime(timesamp,timeFormat);
//// }
// } else {
// result = getTime(timesamp, timeFormat);
// }
// break;
// default:
// result = getTime(timesamp, timeFormat);
// break;
// }
// } else {
// result = getTime(timesamp, timeFormat);
// }
// } else {
// result = getYearTime(timesamp, yearTimeFormat);
// }
// return result;
// }
/**
* 当天的显示时间格式
*
* @param time
* @return
*/
public static String getHourAndMin(long time) {
SimpleDateFormat format = new SimpleDateFormat("HH:mm");
return format.format(new Date(time));
}
/**
* 不同一周的显示时间格式
*
* @param time
* @param timeFormat
* @return
*/
public static String getTime(long time, String timeFormat) {
SimpleDateFormat format = new SimpleDateFormat(timeFormat);
return format.format(new Date(time));
}
/**
* 不同年的显示时间格式
*
* @param time
* @param yearTimeFormat
* @return
*/
public static String getYearTime(long time, String yearTimeFormat) {
SimpleDateFormat format = new SimpleDateFormat(yearTimeFormat);
return format.format(new Date(time));
}
}
<?xml version="1.0" encoding="utf-8"?>
<!--
Tencent is pleased to support the open source community by making QMUI_Android available.
Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://opensource.org/licenses/MIT
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.
-->
<decelerateInterpolator
xmlns:android="http://schemas.android.com/apk/res/android"
android:factor="1.4" />
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Tencent is pleased to support the open source community by making QMUI_Android available.
Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://opensource.org/licenses/MIT
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.
-->
<decelerateInterpolator
xmlns:android="http://schemas.android.com/apk/res/android"
android:factor="1.1" />
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Tencent is pleased to support the open source community by making QMUI_Android available.
Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://opensource.org/licenses/MIT
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.
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@android:color/transparent">
<scale
android:duration="@integer/qmui_anim_duration"
android:fromXScale="0.9"
android:fromYScale="0.9"
android:interpolator="@android:interpolator/decelerate_cubic"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.0"
android:toYScale="1.0" />
<alpha
android:duration="@integer/qmui_anim_duration"
android:fromAlpha="0.0"
android:interpolator="@android:interpolator/decelerate_cubic"
android:toAlpha="1.0" />
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Tencent is pleased to support the open source community by making QMUI_Android available.
Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://opensource.org/licenses/MIT
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.
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@android:color/transparent">
<scale
android:duration="@integer/qmui_anim_duration"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:interpolator="@android:interpolator/decelerate_quad"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="0.8"
android:toYScale="0.8" />
<alpha
android:duration="@integer/qmui_anim_duration"
android:fromAlpha="1.0"
android:interpolator="@android:interpolator/decelerate_quad"
android:toAlpha="0.0" />
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Tencent is pleased to support the open source community by making QMUI_Android available.
Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://opensource.org/licenses/MIT
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.
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_factor_interpolator">
<translate
android:duration="@integer/qmui_anim_duration"
android:fromXDelta="-40%p"
android:toXDelta="0%p" />
<alpha
android:duration="@integer/qmui_anim_duration"
android:fromAlpha="0.85"
android:toAlpha="1" />
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Tencent is pleased to support the open source community by making QMUI_Android available.
Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://opensource.org/licenses/MIT
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.
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_factor_interpolator">
<translate
android:duration="@integer/qmui_anim_duration"
android:fromXDelta="100%p"
android:toXDelta="0%p"/>
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Tencent is pleased to support the open source community by making QMUI_Android available.
Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://opensource.org/licenses/MIT
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.
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_low_factor_interpolator">
<translate
android:duration="@integer/qmui_anim_duration"
android:fromXDelta="0%p"
android:toXDelta="-100%p" />
<alpha
android:duration="@integer/qmui_anim_duration"
android:fromAlpha="1"
android:toAlpha="0.85" />
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Tencent is pleased to support the open source community by making QMUI_Android available.
Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://opensource.org/licenses/MIT
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.
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_factor_interpolator">
<translate
android:duration="@integer/qmui_anim_duration"
android:fromXDelta="0%p"
android:toXDelta="100%p"/>
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Tencent is pleased to support the open source community by making QMUI_Android available.
Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://opensource.org/licenses/MIT
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.
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="@integer/qmui_anim_duration"
android:fromAlpha="1.0"
android:toAlpha="1.0"
android:interpolator="@android:interpolator/decelerate_quad" />
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Tencent is pleased to support the open source community by making QMUI_Android available.
Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://opensource.org/licenses/MIT
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.
-->
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="0"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="0"
android:toYDelta="0"/>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Tencent is pleased to support the open source community by making QMUI_Android available.
Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://opensource.org/licenses/MIT
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.
-->
<!-- some machines will flash black if the duration == 0 or fromXDelta > 0%p -->
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1"
android:fromXDelta="0%p"
android:fromYDelta="0"
android:toXDelta="100%p"
android:toYDelta="0"/>
<?xml version="1.0" encoding="utf-8"?>
<!--
Tencent is pleased to support the open source community by making QMUI_Android available.
Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://opensource.org/licenses/MIT
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.
-->
<!-- when previous activity has a child window, backing to previous activity will run the child
window enter animation, but so far I have no way to reset the enter animation. -->
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@integer/qmui_anim_duration"
android:fromXDelta="0%p"
android:fromYDelta="0"
android:toXDelta="0%p"
android:toYDelta="0"/>
<?xml version="1.0" encoding="utf-8"?>
<!--
Tencent is pleased to support the open source community by making QMUI_Android available.
Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://opensource.org/licenses/MIT
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.
-->
<resources>
<declare-styleable name="SwipeBackLayout">
<attr name="edge_flag">
<enum name="left" value="0" />
<enum name="right" value="1" />
<enum name="bottom" value="2" />
<enum name="all" value="3" />
</attr>
<attr name="shadow_left" format="reference"/>
<attr name="shadow_right" format="reference"/>
<attr name="shadow_bottom" format="reference"/>
</declare-styleable>
<attr name="SwipeBackLayoutStyle" format="reference"/>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Tencent is pleased to support the open source community by making QMUI_Android available.
Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://opensource.org/licenses/MIT
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.
-->
<resources>
<item name="qmui_arch_swipe_layout_in_back" type="id"/>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
Tencent is pleased to support the open source community by making QMUI_Android available.
Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://opensource.org/licenses/MIT
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.
-->
<resources>
<!-- activity或fragment切换的动画时间 -->
<integer name="qmui_anim_duration">300</integer>
</resources>
\ No newline at end of file
<resources>
<style name="SwipeBackLayout">
<item name="shadow_left">@drawable/shadow_left</item>
<item name="shadow_right">@drawable/shadow_right</item>
<item name="shadow_bottom">@drawable/shadow_bottom</item>
</style>
</resources>
......@@ -2,13 +2,11 @@ package com.gingersoft.gsa.cloud.ui.dialog;
import android.app.Dialog;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.Log;
import android.util.SparseArray;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
......@@ -17,39 +15,25 @@ import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import com.gingersoft.gsa.cloud.database.bean.Food;
import com.gingersoft.gsa.cloud.ui.R;
import com.jess.arms.base.BaseHolder;
import com.jess.arms.base.DefaultAdapter;
import com.jess.arms.utils.ArmsUtils;
import com.qmuiteam.qmui.QMUILog;
import com.qmuiteam.qmui.util.QMUIDisplayHelper;
import com.qmuiteam.qmui.util.QMUILangHelper;
import com.qmuiteam.qmui.util.QMUIResHelper;
import com.qmuiteam.qmui.widget.QMUITopBar;
import com.qmuiteam.qmui.widget.dialog.QMUIBottomSheet;
import com.qmuiteam.qmui.widget.dialog.QMUIBottomSheetItemView;
import com.qmuiteam.qmui.widget.grouplist.QMUIGroupListView;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import butterknife.BindView;
/**
* 作者:ELEGANT_BIN
......
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#BF1C42</color>
<color name="colorPrimaryDark">#BF1C42</color>
<color name="colorAccent">#FF4747</color>
......@@ -9,7 +8,10 @@
<color name="mainSelected">#90a4ae</color>
<!--App主色调-->
<color name="theme_color">#BF1C42</color>
<!-- <color name="theme_color">#BF1C42</color>-->
<color name="theme_color">#398BED</color>
<color name="normal_color">#333333</color>
<color name="theme_white_color">#FFFFFFFF</color>
<color name="theme_333_color">#333</color>
<color name="theme_grey_color">#747879</color> <!--灰色tag、字体 -->
......@@ -399,5 +401,10 @@
<color name="blue_grey_800">#37474f</color>
<color name="blue_grey_900">#263238</color>
<color name="color_f4">#F4F4F4</color>
<color name="color_ccc">#CCC</color>
<color name="line_color">@color/color_ccc</color>
<color name="scroll_bar_color">#CACACA</color>
<color name="main_home_function_head_bg">@color/color_f4</color>
</resources>
......@@ -2,18 +2,40 @@
<style name="AppTheme" parent="QMUI.Compat.NoActionBar">
<!-- 配置Android提供的theme -->
<item name="android:textAppearanceListItemSmall">@style/QDTextAppearanceListItemSmall</item>
<item name="android:textAppearanceListItem">@style/QDtextAppearanceListItem</item>
<item name="android:listPreferredItemHeight">?attr/qmui_list_item_height_higher</item>
<item name="android:listPreferredItemHeightSmall">?attr/qmui_list_item_height</item>
<!-- <item name="android:textAppearanceListItemSmall">@style/QDTextAppearanceListItemSmall</item>-->
<!-- <item name="android:textAppearanceListItem">@style/QDtextAppearanceListItem</item>-->
<!-- <item name="android:listPreferredItemHeight">?attr/qmui_list_item_height_higher</item>-->
<!-- <item name="android:listPreferredItemHeightSmall">?attr/qmui_list_item_height</item>-->
<!-- 配置qmui提供的theme -->
<item name="qmui_config_color_blue">@color/app_color_blue</item>
<item name="qmui_round_btn_bg_color">@color/ui_s_btn_blue_bg</item>
<item name="qmui_round_btn_border_color">@color/ui_s_btn_blue_border</item>
<item name="qmui_round_btn_text_color">@color/ui_s_btn_blue_text</item>
<item name="qmui_content_spacing_horizontal">20dp</item>
<item name="qmui_content_padding_horizontal">@dimen/qmui_content_spacing_horizontal</item>
<item name="qmui_config_color_blue">@color/theme_color</item>
<item name="qmui_config_color_gray_6">@color/normal_color</item>
<!-- <item name="qmui_round_btn_bg_color">@color/ui_s_btn_blue_bg</item>-->
<!-- <item name="qmui_round_btn_border_color">@color/ui_s_btn_blue_border</item>-->
<!-- <item name="qmui_round_btn_text_color">@color/ui_s_btn_blue_text</item>-->
<!-- <item name="qmui_content_spacing_horizontal">20dp</item>-->
<!-- <item name="qmui_content_padding_horizontal">@dimen/qmui_content_spacing_horizontal</item>-->
<!--***************************** qmui topbar ***************************** -->
<item name="qmui_topbar_height">@dimen/head_height</item>
<!-- skin support-->
<item name="qmui_skin_support_topbar_separator_color">?attr/qmui_skin_support_color_separator</item>
<item name="qmui_skin_support_topbar_bg">@color/qmui_config_color_white</item>
<item name="qmui_skin_support_topbar_title_color">@color/normal_color</item>
<item name="qmui_skin_support_topbar_subtitle_color">?attr/qmui_config_color_gray_3</item>
<item name="qmui_skin_support_topbar_text_btn_color_state_list">@color/qmui_config_color_gray_1</item>
<item name="qmui_skin_support_topbar_image_tint_color">@color/qmui_config_color_gray_1</item>
<!-- skin support-->
<!--*************************** qmui tabSegment *************************** -->
<!-- skin support-->
<item name="qmui_skin_support_tab_bg">@color/qmui_config_color_white</item>
<item name="qmui_skin_support_tab_separator_color">?attr/qmui_skin_support_color_separator</item>
<item name="qmui_skin_support_tab_normal_color">@color/normal_color</item>
<item name="qmui_skin_support_tab_selected_color">@color/theme_color</item>
<item name="qmui_skin_support_tab_sign_count_view_text_color">@color/qmui_config_color_white</item>
<item name="qmui_skin_support_tab_sign_count_view_bg_color">?attr/qmui_config_color_red</item>
<!-- skin support-->
<item name="QMUITopBarStyle">@style/QDTopBar</item>
......@@ -35,9 +57,8 @@
<item name="colorPrimary">@color/theme_color</item>
<item name="colorPrimaryDark">@color/theme_color</item>
<item name="colorAccent">@color/theme_color</item>
<!--<item name="android:alertDialogTheme">@style/Theme.AppCompat.Light.Dialog.Alert.Self</item>-->
<item name="android:windowAnimationStyle">@style/ui_activityAnimation
</item><!-- 设置activity切换动画 -->
<!-- <item name="android:alertDialogTheme">@style/Theme.AppCompat.Light.Dialog.Alert.Self</item>-->
<item name="android:windowAnimationStyle">@style/ui_activityAnimation</item><!-- 设置activity切换动画 -->
</style>
......@@ -70,15 +91,13 @@
<style name="QDtextAppearanceListItem">
<item name="android:textColor">?attr/qmui_config_color_black</item>
<item name="android:textSize">18sp</item>
<item name="android:background">?attr/qmui_s_list_item_bg_with_border_bottom_inset_left
</item>
<!-- <item name="android:background">?attr/qmui_s_list_item_bg_with_border_bottom_inset_left</item>-->
</style>
<style name="QDTextAppearanceListItemSmall">
<item name="android:textColor">?attr/qmui_config_color_gray_4</item>
<item name="android:textSize">16sp</item>
<item name="android:background">?attr/qmui_s_list_item_bg_with_border_bottom_inset_left
</item>
<!-- <item name="android:background">?attr/qmui_s_list_item_bg_with_border_bottom_inset_left</item>-->
</style>
<style name="QDCommonTitle">
......@@ -100,7 +119,7 @@
</style>
<style name="QDTopBar" parent="QMUI.TopBar">
<item name="qmui_topbar_bg_color">?attr/app_primary_color</item>
<!-- <item name="qmui_topbar_bg_color">?attr/app_primary_color</item>-->
<item name="qmui_topbar_title_color">@color/qmui_config_color_white</item>
<item name="qmui_topbar_subtitle_color">@color/qmui_config_color_white</item>
<item name="qmui_topbar_text_btn_color_state_list">@color/ui_s_topbar_btn_color</item>
......@@ -113,7 +132,7 @@
<item name="android:layout_width">wrap_content</item>
<item name="android:paddingLeft">?attr/qmui_content_spacing_horizontal</item>
<item name="android:paddingRight">?attr/qmui_content_spacing_horizontal</item>
<item name="qmui_borderColor">?attr/qmui_round_btn_border_color</item>
<!-- <item name="qmui_borderColor">?attr/qmui_round_btn_border_color</item>-->
<item name="qmui_backgroundColor">@color/ui_s_app_color_blue_3</item>
<item name="android:textColor">@color/ui_s_app_color_blue_2</item>
<item name="android:textSize">14sp</item>
......
......@@ -26,6 +26,7 @@ android {
includeCompileClasspath true
}
}
multiDexEnabled true
}
resourcePrefix "table"
......
package debug;
import android.app.Application;
import com.billy.cc.core.component.CC;
import com.jess.arms.base.BaseApplication;
/**
* @author billy.qi
* @since 17/11/20 20:02
*/
public class MyApp extends Application {
public class MyApp extends BaseApplication {
@Override
public void onCreate() {
super.onCreate();
......
......@@ -33,7 +33,6 @@ import com.gingersoft.gsa.cloud.table.mvp.contract.TableContract;
import com.gingersoft.gsa.cloud.table.mvp.presenter.TablePresenter;
import com.qmuiteam.qmui.layout.QMUIButton;
import com.qmuiteam.qmui.widget.QMUITopBar;
import com.qmuiteam.qmui.widget.popup.QMUIListPopup;
import com.qmuiteam.qmui.widget.popup.QMUIPopup;
import java.util.ArrayList;
......
package debug;
import android.app.Application;
import com.billy.cc.core.component.CC;
import com.jess.arms.base.BaseApplication;
/**
* @author billy.qi
* @since 17/11/20 20:02
*/
public class MyApp extends Application {
public class MyApp extends BaseApplication {
@Override
public void onCreate() {
super.onCreate();
......
package com.gingersoft.gsa.cloud.user.login.mvp.server;
import com.gingersoft.gsa.cloud.base.Api;
import com.gingersoft.gsa.cloud.user.login.mvp.bean.LoginBean;
import com.gingersoft.gsa.cloud.user.login.mvp.bean.TestLoginBean;
import io.reactivex.Observable;
import me.jessyan.retrofiturlmanager.RetrofitUrlManager;
import okhttp3.RequestBody;
import retrofit2.http.Body;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;
/**
......
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="user_login_title_color">@color/theme_white_color</color>
<color name="user_login_title_color">@color/theme_333_color</color>
<color name="user_login_edit_color">@color/theme_hint_color</color>
</resources>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment