diff --git a/.gitignore b/.gitignore index 39fb081..2a42e3e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,20 @@ *.iml .gradle /local.properties -/.idea/workspace.xml +/.idea/caches /.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +/.idea/ +/.idea/misc.xml .DS_Store /build /captures .externalNativeBuild +.cxx +*.apk +*.ap_ +*.dex +*.class diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..0d15693 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,134 @@ + + + + + + + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
+
+
\ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 504a670..08809d1 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,11 +1,13 @@ + diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 095909e..6d07175 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -1,6 +1,9 @@ \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 9ac5bbb..360a949 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -2,47 +2,51 @@ - + diff --git a/.idea/modules.xml b/.idea/modules.xml index 05348d0..0f2e166 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,13 +2,14 @@ - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7..35eb1dd 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/README.md b/README.md index 433a6b1..9358faf 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,14 @@ # AndroidModuleDemo -基于MVP搭建的组件化开发框架
+基于MVP搭建的组件化开发框架 ,[详细介绍](https://www.jianshu.com/p/00746e6fb48a)
# 效果图
-## 主要用于学习android组件化的学习, +## 主要用于学习android组件化框架 ## 封装了工作中常用的一些控件,基类等,可以做到快速开发 +
电商 商品详情
+
+ +~ diff --git a/app/build.gradle b/app/build.gradle index 7ed3cdf..357bfc5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,64 +1,142 @@ apply plugin: 'com.android.application' +/** + * 打包时间 + */ +static String releaseTime() { + return "\"" + new Date().format("yyyy-MM-dd HH:mm") + "\"" +} + +/** + * 根据build时间自动生成versionCode + */ +static def createVersionCode() { + def year = new Date().format("yy") + def month = new Date().format("MM") + def other = new Date().format("ddHHmm") + //年份-1 月份+12 + year = year.toInteger() - 1 + month = month.toInteger() + 12 + def code = year.toString() + month.toString() + other + return code.toInteger(); +} + android { compileSdkVersion rootProject.ext.versions.compileSdkVersion buildToolsVersion rootProject.ext.versions.buildToolsVersion defaultConfig { - applicationId rootProject.ext.versions.applicationId minSdkVersion rootProject.ext.versions.minSdkVersion targetSdkVersion rootProject.ext.versions.targetSdkVersion - versionCode rootProject.ext.versions.versionCode - versionName rootProject.ext.versions.versionName - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - //MultiDex分包方法 - multiDexEnabled true - - //Arouter路由配置 - javaCompileOptions { - annotationProcessorOptions { - arguments = [moduleName: project.getName()] - includeCompileClasspath = true + + signingConfigs { + config { + keyAlias 'amd' + keyPassword '123456' + storeFile file('../key/amd.jsk') + storePassword '123456' } } - } - signingConfigs { - config { - keyAlias 'amd' - keyPassword '123456' - storeFile file('../key/amd.jsk') - storePassword '123456' + defaultConfig { + minSdkVersion rootProject.ext.versions.minSdkVersion + targetSdkVersion rootProject.ext.versions.targetSdkVersion + versionCode createVersionCode() + multiDexEnabled true + signingConfig signingConfigs.config + + ndk { + abiFilters "armeabi-v7a" + } + + javaCompileOptions { + annotationProcessorOptions { + arguments = [AROUTER_MODULE_NAME: project.getName()] + includeCompileClasspath = true + } + } } + } + buildTypes { - debug { - signingConfig signingConfigs.config - } release { - signingConfig signingConfigs.config + lintOptions { + checkReleaseBuilds false + abortOnError false + } + //不使用混淆 minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } -} + compileOptions { + targetCompatibility rootProject.ext.versions.javaSDKVersion + sourceCompatibility rootProject.ext.versions.javaSDKVersion + } + + dexOptions { + javaMaxHeapSize "5g" + } + repositories { + flatDir { + dirs project(':common_base').file('libs') + } + } + //多维度标签 + flavorDimensions "default" + //多渠道配置 + productFlavors { + //开发 + DEV { + dimension "default" + versionName rootProject.ext.versions.versionNameDEV + applicationId rootProject.ext.versions.applicationIdDEV + resValue "string", "app_name", "AMD_DEV" + buildConfigField("String", "RELEASE_TIME", releaseTime()) + manifestPlaceholders = [ + //7.0文件权限 + FILE_PROVIDER: applicationId, + ] + } + + //生产 + PRO { + dimension "default" + versionName rootProject.ext.versions.versionName + applicationId rootProject.ext.versions.applicationId + resValue "string", "app_name", "AMD" + buildConfigField("String", "RELEASE_TIME", releaseTime()) + manifestPlaceholders = [ + //7.0文件权限 + FILE_PROVIDER: applicationId, + ] + } + } + android.applicationVariants.all { variant -> + variant.outputs.all { output -> + outputFileName = "AMD_v${variant.versionName}_${variant.productFlavors[0].name}_${variant.buildType.name}.apk" + } + } -configurations.all { - resolutionStrategy.force 'com.android.support:support-annotations:27.1.1' } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - annotationProcessor rootProject.ext.dependencies["butterknife_compiler"] + annotationProcessor rootProject.ext.dependencies["butterknifeCompiler"] //公用依赖包 implementation project(':common_base') if (!Boolean.valueOf(rootProject.ext.isModule)) { + //main模块 implementation project(':module_main') + //商城模块 implementation project(':module_market') - implementation project(':module_wan_android') + //用户模块 implementation project(':module_user') + //玩Android模块 + implementation project(':module_wan_android') } } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d468f7e..55ada32 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,6 +10,16 @@ android:supportsRtl="true" android:theme="@style/AdmTheme"> + + + + + + + + + + test page + + + + +获取分辨率 +
+ + \ No newline at end of file diff --git a/app/src/main/java/com/wss/amd/app/AppApplication.java b/app/src/main/java/com/wss/amd/app/AppApplication.java index e1951e4..6b49668 100644 --- a/app/src/main/java/com/wss/amd/app/AppApplication.java +++ b/app/src/main/java/com/wss/amd/app/AppApplication.java @@ -1,12 +1,19 @@ package com.wss.amd.app; +import com.wss.amd.profile.ProfileFactory; import com.wss.common.base.BaseApplication; +import com.wss.common.profile.ProfileManager; /** - * Describe: + * Describe: Application * Created by 吴天强 on 2018/10/15. */ - public class AppApplication extends BaseApplication { + @Override + public void onCreate() { + super.onCreate(); + ProfileManager.inst.factory(new ProfileFactory()); + + } } diff --git a/app/src/main/java/com/wss/amd/main/LoadingActivity.java b/app/src/main/java/com/wss/amd/main/LoadingActivity.java new file mode 100644 index 0000000..06e3aea --- /dev/null +++ b/app/src/main/java/com/wss/amd/main/LoadingActivity.java @@ -0,0 +1,41 @@ +package com.wss.amd.main; + +import android.os.Bundle; +import android.os.Handler; +import android.view.WindowManager; +import android.widget.TextView; + +import com.wss.amd.R; +import com.wss.common.base.BaseFullScreenActivity; +import com.wss.common.base.mvp.BasePresenter; +import com.wss.common.manage.ActivityToActivity; +import com.wss.common.utils.Utils; +import com.wss.module.main.ui.main.MainActivity; + +import androidx.annotation.Nullable; + +/** + * Describe:应用启动页 + * Created by 吴天强 on 2018/10/16. + */ +public class LoadingActivity extends BaseFullScreenActivity { + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_loading); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + new Handler().postDelayed(() -> { + ActivityToActivity.toActivity(this, MainActivity.class); + }, 1200); + + TextView tvVersion = findViewById(R.id.tv_version); + tvVersion.setText(String.format("V%s(%s)", Utils.getVersionName(), Utils.getVersionCode())); + } + + @Override + protected BasePresenter createPresenter() { + return null; + } + +} diff --git a/app/src/main/java/com/wss/amd/note/NoteTest.java b/app/src/main/java/com/wss/amd/note/NoteTest.java new file mode 100644 index 0000000..3916479 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/NoteTest.java @@ -0,0 +1,371 @@ +package com.wss.amd.note; + +import com.wss.amd.note.designpattern.adapter.classs.Dc5V; +import com.wss.amd.note.designpattern.adapter.classs.Dc5VAdapter; +import com.wss.amd.note.designpattern.adapter.obj.SixiDumplings; +import com.wss.amd.note.designpattern.adapter.obj.SteamedBunsAdapter; +import com.wss.amd.note.designpattern.bridge.Circle; +import com.wss.amd.note.designpattern.bridge.Rectangle; +import com.wss.amd.note.designpattern.bridge.Shape; +import com.wss.amd.note.designpattern.bridge.pen.GreenPen; +import com.wss.amd.note.designpattern.bridge.pen.RedPen; +import com.wss.amd.note.designpattern.builder.TestDialog; +import com.wss.amd.note.designpattern.combination.Employee; +import com.wss.amd.note.designpattern.command.WaiterInvoker; +import com.wss.amd.note.designpattern.command.command.NoodleCommand; +import com.wss.amd.note.designpattern.command.command.RiceCommand; +import com.wss.amd.note.designpattern.command.command.StirFryCommand; +import com.wss.amd.note.designpattern.decorator.Egg; +import com.wss.amd.note.designpattern.decorator.GreenPepperShreddedMeat; +import com.wss.amd.note.designpattern.decorator.PotatoesBurnFireSirloin; +import com.wss.amd.note.designpattern.decorator.Vegetables; +import com.wss.amd.note.designpattern.decorator.base.Food; +import com.wss.amd.note.designpattern.decorator.base.Noodle; +import com.wss.amd.note.designpattern.decorator.base.Rice; +import com.wss.amd.note.designpattern.facade.FoodMaker; +import com.wss.amd.note.designpattern.fracory.abstractfactory.AssembleComputer; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.IComputerFactory; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.computer.HaweiComputerFactoryFactory; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.computer.IntelComputerFactoryFactory; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.computer.MacComputerFactoryFactory; +import com.wss.amd.note.designpattern.fracory.normalfactory.ConfigFactory; +import com.wss.amd.note.designpattern.fracory.simplefactory.SimpleFactory; +import com.wss.amd.note.designpattern.fracory.simplefactory.config.IConfig; +import com.wss.amd.note.designpattern.interpreter.GameEnvironment; +import com.wss.amd.note.designpattern.interpreter.GameUser; +import com.wss.amd.note.designpattern.iterator.Iterator; +import com.wss.amd.note.designpattern.iterator.UserAggregate; +import com.wss.amd.note.designpattern.mediator.Colleague; +import com.wss.amd.note.designpattern.mediator.ConcreteColleague1; +import com.wss.amd.note.designpattern.mediator.ConcreteColleague2; +import com.wss.amd.note.designpattern.mediator.ConcreteMediator; +import com.wss.amd.note.designpattern.mediator.Mediator; +import com.wss.amd.note.designpattern.memorandum.Caretaker; +import com.wss.amd.note.designpattern.memorandum.Originator; +import com.wss.amd.note.designpattern.observer.BinaryObserver; +import com.wss.amd.note.designpattern.observer.HexaObserver; +import com.wss.amd.note.designpattern.observer.Subject; +import com.wss.amd.note.designpattern.proxy.User; +import com.wss.amd.note.designpattern.proxy.UserService; +import com.wss.amd.note.designpattern.proxy.UserServiceProxy; +import com.wss.amd.note.designpattern.responsibility.LocationRuleHandler; +import com.wss.amd.note.designpattern.responsibility.NewUserRuleHandler; +import com.wss.amd.note.designpattern.responsibility.ParticipantsRuleHandler; +import com.wss.amd.note.designpattern.responsibility.People; +import com.wss.amd.note.designpattern.state.InvisibleState; +import com.wss.amd.note.designpattern.state.OnLineState; +import com.wss.amd.note.designpattern.state.QQUser; +import com.wss.amd.note.designpattern.strategy.NoodleStrategy; +import com.wss.amd.note.designpattern.strategy.NoonEatWhat; +import com.wss.amd.note.designpattern.strategy.RiceStrategy; +import com.wss.amd.note.designpattern.template.AbsTemplateMethod; +import com.wss.amd.note.designpattern.template.TemplateMethod; +import com.wss.amd.note.designpattern.visitor.SetMaterial; +import com.wss.amd.note.designpattern.visitor.company.ArtCompany; +import com.wss.amd.note.designpattern.visitor.company.MintCompany; +import com.wss.amd.note.designpattern.visitor.material.Copper; +import com.wss.amd.note.designpattern.visitor.material.Paper; +import com.wss.common.base.BaseApplication; + +import org.junit.Test; + +/** + * Describe:测试类 + * Created by 吴天强 on 2022/1/17. + */ +public class NoteTest { + + @Test + public void testSimpleFactory() { + + //创建开发环境 + IConfig devConfig = SimpleFactory.createConfig(1); + + //创建生产环境 + IConfig proConfig = SimpleFactory.createConfig(0); + + } + + @Test + public void testConfigFactory() { + //普通工厂 + ConfigFactory configFactory = new ConfigFactory(); + IConfig config = configFactory.createConfig(); + String serviceUrl = config.getServiceUrl(); + } + + @Test + public void testAbstractFactory() { + //抽象工厂 + IComputerFactory factory; + + //创建华为工厂、组装华为电脑 + factory = new HaweiComputerFactoryFactory(); + AssembleComputer huaweiComputer = new AssembleComputer(factory.createCPU(), factory.createHardDisk() + , factory.createMainBoard()); + + //创建Intel工厂、组装Intel电脑 + factory = new IntelComputerFactoryFactory(); + AssembleComputer intelComputer = new AssembleComputer(factory.createCPU(), factory.createHardDisk() + , factory.createMainBoard()); + + //创建苹果工厂、组装苹果电脑 + factory = new MacComputerFactoryFactory(); + AssembleComputer macComputer = new AssembleComputer(factory.createCPU(), factory.createHardDisk() + , factory.createMainBoard()); + + } + + @Test + public void testBuilderDialog() { + //建造者 + new TestDialog.Builder(BaseApplication.i()) + .setContent("对话框内容") + .setCanCancel(false) + .build() + .show(); + } + + @Test + public void testUserProxy() { + //代理模式 + UserService service = new UserServiceProxy(); + User admin = service.creteAdmin(); + User user = service.createUser(); + } + + @Test + public void testObjAdapter() { + //测试 对象适配器 + SixiDumplings sixiDumplings = new SixiDumplings(); + SteamedBunsAdapter bunsAdapter = new SteamedBunsAdapter(sixiDumplings); + bunsAdapter.bunsFilling(); + bunsAdapter.steam(); + } + + @Test + public void testClassAdapter() { + //测试类适配器 + Dc5V dc5V = new Dc5VAdapter(); + int i = dc5V.dc5v(); + } + + @Test + public void testBridge() { + //桥梁模式 + + //红色的圆圈 + Shape circle = new Circle(10, new RedPen()); + circle.draw(); + + //绿色的矩形 + Shape rectangle = new Rectangle(10, 10, new GreenPen()); + rectangle.draw(); + } + + @Test + public void testFoodMaker() { + //门面模式 + FoodMaker foodMaker = new FoodMaker(); + foodMaker.makeBreakfast(); + foodMaker.makeLunch(); + foodMaker.makeDinner(); + } + + + @Test + public void testDecorator() { + //餐馆来了一位小哥, 他对老板说 + //老板,来米饭 + Food rice = new Rice(); + System.out.println(rice.getName() + ",价格:" + rice.getPrice() + "元"); + //加一分土豆烧牛腩 + rice = new PotatoesBurnFireSirloin(rice); + System.out.println(rice.getName() + ",价格:" + rice.getPrice() + "元"); + //再加个鸡蛋 + rice = new Egg(rice); + System.out.println(rice.getName() + ",价格:" + rice.getPrice() + "元"); + System.out.println(); + + //餐馆又来了一位大哥,他饭量比较好,需要双份的土豆牛腩和双份的青椒肉丝以及青菜、一个鸡蛋 + //老板,来双份面条 + Food noodle = new Noodle(); + System.out.println(noodle.getName() + ",价格:" + noodle.getPrice() + "元"); + //加双份土豆牛腩 + noodle = new PotatoesBurnFireSirloin(new PotatoesBurnFireSirloin(noodle)); + System.out.println(noodle.getName() + ",价格:" + noodle.getPrice() + "元"); + //再加双份的青椒肉丝 + noodle = new GreenPepperShreddedMeat(new GreenPepperShreddedMeat(noodle)); + System.out.println(noodle.getName() + ",价格:" + noodle.getPrice() + "元"); + //再来青菜 + noodle = new Vegetables(noodle); + System.out.println(noodle.getName() + ",价格:" + noodle.getPrice() + "元"); + //再来一个鸡蛋 + noodle = new Egg(noodle); + System.out.println(noodle.getName() + ",价格:" + noodle.getPrice() + "元"); + + } + + @Test + public void testCombination() { + + Employee employee = new Employee("张三", "信息部"); + employee.add(new Employee("李四", "信息部")); + employee.add(new Employee("王五", "信息部")); + + System.out.println(employee.toString()); + } + + @Test + public void testStrategy() { + //10个人去吃米饭 + NoonEatWhat noonEatWhat = new NoonEatWhat(new RiceStrategy()); + noonEatWhat.executeEat(10); + + //5个人去吃面条 + NoonEatWhat noonEatWhat1 = new NoonEatWhat(new NoodleStrategy()); + noonEatWhat1.executeEat(5); + } + + + @Test + public void testObserver() { + + //定义主题(被观察者) + Subject subject = new Subject(); + + //定义两个观察者 + new BinaryObserver(subject); + new HexaObserver(subject); + + //模拟数据变更,被观察者有了变化 + subject.setState(22); + } + + + @Test + public void testResponsibility() { + + People people = new People(); + people.setNewUser(true); + people.setLocation("上海"); + people.setParticipants(222); + + NewUserRuleHandler newUserRuleHandler = new NewUserRuleHandler(); + LocationRuleHandler locationRuleHandler = new LocationRuleHandler(); + ParticipantsRuleHandler participantsRuleHandler = new ParticipantsRuleHandler(); + + locationRuleHandler.setSuccessor(newUserRuleHandler); + participantsRuleHandler.setSuccessor(locationRuleHandler); + newUserRuleHandler.apply(people); + } + + @Test + public void testAbsTemplateMethod() { + AbsTemplateMethod templateMethod = new TemplateMethod(); + templateMethod.templateMethod(); + } + + @Test + public void testState() { + QQUser qqUser = new QQUser("人生如梦"); + + //隐身 + InvisibleState invisibleState = new InvisibleState(); + invisibleState.doAction(qqUser); + System.out.println(qqUser.getName() + "当前状态:" + qqUser.getState().toString()); + + //上线 + OnLineState onLineState = new OnLineState(); + onLineState.doAction(qqUser); + System.out.println(qqUser.getName() + "当前状态:" + qqUser.getState().toString()); + } + + @Test + public void testIterator() { + UserAggregate aggregate = new UserAggregate<>(); + aggregate.add(new User("张三")); + aggregate.add(new User("李四")); + aggregate.add(new User("王五")); + + Iterator iterator = aggregate.iterator(); + System.out.println("First:" + iterator.first()); + System.out.println("Has next:" + iterator.hasNext()); + System.out.println("Next:" + iterator.next()); + System.out.println("Next:" + iterator.next()); + System.out.println("Has next:" + iterator.hasNext()); + + } + + @Test + public void testCommand() { + //饭店对外生成了一个服务员,同时也生成了米饭、面条、炒菜三个菜单 + WaiterInvoker waiterInvoker = new WaiterInvoker(new RiceCommand(), new NoodleCommand(), new StirFryCommand()); + //饭店开张,来了一位顾客,选择了米饭 + waiterInvoker.chooseRice(); + //又继续点了一份面条 + waiterInvoker.chooseNoodle(); + //最后又加了一份炒菜 + waiterInvoker.chooseStirFry(); + } + + @Test + public void testMemorandum() { + Originator originator = new Originator(); + Caretaker caretaker = new Caretaker(); + originator.setState("create"); + System.out.println("当前状态:" + originator.getState()); + //保存当前状态到备忘录 + caretaker.setMemento(originator.createMemento()); + originator.setState("working"); + System.out.println("当前状态:" + originator.getState()); + originator.restoreMemento(caretaker.getMemento()); + System.out.println("当前状态:" + originator.getState()); + } + + @Test + public void testVisitor() { + + //定义材料集 + SetMaterial setMaterial = new SetMaterial(); + //添加纸 + setMaterial.add(new Paper()); + //添加铜 + setMaterial.add(new Copper()); + + //艺术公司制作工艺品 + String artSet = setMaterial.accept(new ArtCompany()); + System.out.println("艺术公司成果:" + artSet); + //造币公司制作钞票 + String mintSet = setMaterial.accept(new MintCompany()); + System.out.println("造币公司成果:" + mintSet); + + } + + @Test + public void testMediator() { + Mediator mediator = new ConcreteMediator(); + Colleague concreteColleague1 = new ConcreteColleague1(); + Colleague concreteColleague2 = new ConcreteColleague2(); + mediator.register(concreteColleague1); + mediator.register(concreteColleague2); + concreteColleague1.send(); + concreteColleague2.send(); + } + + @Test + public void testInterpreter() { + //假设:阵营是齐国、吴国且等级大于50的玩家只能参加普通副本《捉泥鳅》, + //其他的则可以参加高级副本《鹊桥仙》 + //定义用户环境 + GameEnvironment gameEnvironment = new GameEnvironment(); + //第一位 来自齐国的66级的李逍遥 + gameEnvironment.operation(new GameUser("李逍遥", 66, "齐国")); + //第二位 来自楚国的51级的张小凡 + gameEnvironment.operation(new GameUser("张小凡", 51, "楚国")); + //第三位 来自燕国的11级的高渐离 + gameEnvironment.operation(new GameUser("高渐离", 11, "燕国")); + + } + +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/adapter/classs/Ac220V.java b/app/src/main/java/com/wss/amd/note/designpattern/adapter/classs/Ac220V.java new file mode 100644 index 0000000..207499d --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/adapter/classs/Ac220V.java @@ -0,0 +1,13 @@ +package com.wss.amd.note.designpattern.adapter.classs; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +public class Ac220V { + + //获取220v电压 + public int outPut220() { + return 220; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/adapter/classs/Dc5V.java b/app/src/main/java/com/wss/amd/note/designpattern/adapter/classs/Dc5V.java new file mode 100644 index 0000000..65ebce5 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/adapter/classs/Dc5V.java @@ -0,0 +1,10 @@ +package com.wss.amd.note.designpattern.adapter.classs; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +public interface Dc5V { + + int dc5v(); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/adapter/classs/Dc5VAdapter.java b/app/src/main/java/com/wss/amd/note/designpattern/adapter/classs/Dc5VAdapter.java new file mode 100644 index 0000000..819a71c --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/adapter/classs/Dc5VAdapter.java @@ -0,0 +1,13 @@ +package com.wss.amd.note.designpattern.adapter.classs; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +public class Dc5VAdapter extends Ac220V implements Dc5V { + @Override + public int dc5v() { + int ac220v = outPut220(); + return ac220v / 44; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/adapter/normal/AppHttpRequestListener.java b/app/src/main/java/com/wss/amd/note/designpattern/adapter/normal/AppHttpRequestListener.java new file mode 100644 index 0000000..75d1943 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/adapter/normal/AppHttpRequestListener.java @@ -0,0 +1,32 @@ +package com.wss.amd.note.designpattern.adapter.normal; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +public class AppHttpRequestListener implements HttpRequestListener { + @Override + public void onStart() { + + } + + @Override + public void onProgress(int progress, int count) { + + } + + @Override + public void onSuccess() { + + } + + @Override + public void onError() { + + } + + @Override + public void onComplete() { + + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/adapter/normal/HttpRequestListener.java b/app/src/main/java/com/wss/amd/note/designpattern/adapter/normal/HttpRequestListener.java new file mode 100644 index 0000000..92138ab --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/adapter/normal/HttpRequestListener.java @@ -0,0 +1,18 @@ +package com.wss.amd.note.designpattern.adapter.normal; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +public interface HttpRequestListener { + + void onStart(); + + void onProgress(int progress, int count); + + void onSuccess(); + + void onError(); + + void onComplete(); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/adapter/normal/XxAppHttpRequestListener.java b/app/src/main/java/com/wss/amd/note/designpattern/adapter/normal/XxAppHttpRequestListener.java new file mode 100644 index 0000000..ade3dc8 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/adapter/normal/XxAppHttpRequestListener.java @@ -0,0 +1,18 @@ +package com.wss.amd.note.designpattern.adapter.normal; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +public class XxAppHttpRequestListener extends AppHttpRequestListener { + + @Override + public void onSuccess() { + //doSomething + } + + @Override + public void onError() { + //doSomething + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/adapter/obj/Buns.java b/app/src/main/java/com/wss/amd/note/designpattern/adapter/obj/Buns.java new file mode 100644 index 0000000..92172af --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/adapter/obj/Buns.java @@ -0,0 +1,12 @@ +package com.wss.amd.note.designpattern.adapter.obj; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +public interface Buns { + + void bunsFilling(); + + void steam(); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/adapter/obj/Dumplings.java b/app/src/main/java/com/wss/amd/note/designpattern/adapter/obj/Dumplings.java new file mode 100644 index 0000000..38fe600 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/adapter/obj/Dumplings.java @@ -0,0 +1,12 @@ +package com.wss.amd.note.designpattern.adapter.obj; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +public interface Dumplings { + + void dumplingsFilling(); + + void steam(); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/adapter/obj/SixiDumplings.java b/app/src/main/java/com/wss/amd/note/designpattern/adapter/obj/SixiDumplings.java new file mode 100644 index 0000000..5c5a1be --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/adapter/obj/SixiDumplings.java @@ -0,0 +1,17 @@ +package com.wss.amd.note.designpattern.adapter.obj; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +public class SixiDumplings implements Dumplings { + @Override + public void dumplingsFilling() { + System.out.println("四喜水饺馅儿"); + } + + @Override + public void steam() { + System.out.println("上锅蒸"); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/adapter/obj/SteamedBunsAdapter.java b/app/src/main/java/com/wss/amd/note/designpattern/adapter/obj/SteamedBunsAdapter.java new file mode 100644 index 0000000..cefb32d --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/adapter/obj/SteamedBunsAdapter.java @@ -0,0 +1,25 @@ +package com.wss.amd.note.designpattern.adapter.obj; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +public class SteamedBunsAdapter implements Buns { + + private Dumplings dumplings; + + public SteamedBunsAdapter(Dumplings dumplings) { + this.dumplings = dumplings; + } + + @Override + public void bunsFilling() { + //包子的内部实现其实是饺子馅儿 + dumplings.dumplingsFilling(); + } + + @Override + public void steam() { + dumplings.steam(); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/bridge/Circle.java b/app/src/main/java/com/wss/amd/note/designpattern/bridge/Circle.java new file mode 100644 index 0000000..a817f50 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/bridge/Circle.java @@ -0,0 +1,19 @@ +package com.wss.amd.note.designpattern.bridge; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +public class Circle extends Shape { + private int radius; + + public Circle(int radius, DrawApi drawApi) { + super(drawApi); + this.radius = radius; + } + + @Override + public void draw() { + drawApi.draw(radius, 0, 0); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/bridge/DrawApi.java b/app/src/main/java/com/wss/amd/note/designpattern/bridge/DrawApi.java new file mode 100644 index 0000000..95040ff --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/bridge/DrawApi.java @@ -0,0 +1,10 @@ +package com.wss.amd.note.designpattern.bridge; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +public interface DrawApi { + + void draw(int radius, int x, int y); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/bridge/Rectangle.java b/app/src/main/java/com/wss/amd/note/designpattern/bridge/Rectangle.java new file mode 100644 index 0000000..1a4b576 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/bridge/Rectangle.java @@ -0,0 +1,20 @@ +package com.wss.amd.note.designpattern.bridge; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +public class Rectangle extends Shape { + private int x, y; + + public Rectangle(int x, int y, DrawApi drawApi) { + super(drawApi); + this.x = x; + this.y = y; + } + + @Override + public void draw() { + drawApi.draw(0, x, y); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/bridge/Shape.java b/app/src/main/java/com/wss/amd/note/designpattern/bridge/Shape.java new file mode 100644 index 0000000..894c5d0 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/bridge/Shape.java @@ -0,0 +1,16 @@ +package com.wss.amd.note.designpattern.bridge; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +public abstract class Shape { + + protected DrawApi drawApi; + + public Shape(DrawApi drawApi) { + this.drawApi = drawApi; + } + + public abstract void draw(); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/bridge/pen/GreenPen.java b/app/src/main/java/com/wss/amd/note/designpattern/bridge/pen/GreenPen.java new file mode 100644 index 0000000..d28b9d5 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/bridge/pen/GreenPen.java @@ -0,0 +1,14 @@ +package com.wss.amd.note.designpattern.bridge.pen; + +import com.wss.amd.note.designpattern.bridge.DrawApi; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +public class GreenPen implements DrawApi { + @Override + public void draw(int radius, int x, int y) { + System.out.println("使用绿笔画图,radius:" + radius + ",x:" + x + ",y:" + y); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/bridge/pen/RedPen.java b/app/src/main/java/com/wss/amd/note/designpattern/bridge/pen/RedPen.java new file mode 100644 index 0000000..a2cabbb --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/bridge/pen/RedPen.java @@ -0,0 +1,14 @@ +package com.wss.amd.note.designpattern.bridge.pen; + +import com.wss.amd.note.designpattern.bridge.DrawApi; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +public class RedPen implements DrawApi { + @Override + public void draw(int radius, int x, int y) { + System.out.println("使用红笔画图,radius:" + radius + ",x:" + x + ",y:" + y); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/builder/TestDialog.java b/app/src/main/java/com/wss/amd/note/designpattern/builder/TestDialog.java new file mode 100644 index 0000000..103a92d --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/builder/TestDialog.java @@ -0,0 +1,64 @@ +package com.wss.amd.note.designpattern.builder; + +import android.app.Dialog; +import android.content.Context; +import android.view.Gravity; +import android.view.View; +import android.view.Window; +import android.widget.TextView; + +import com.wss.amd.R; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +public class TestDialog { + + private Builder builder; + + private TestDialog(Builder builder) { + this.builder = builder; + } + + + public void show() { + View dialogView = View.inflate(builder.context, R.layout.dialog_app, null); + ((TextView) dialogView.findViewById(R.id.tv_content)).setText(builder.content); + Dialog dialog = new Dialog(builder.context, R.style.DialogStyle); + dialog.setContentView(dialogView); + Window window = dialog.getWindow(); + if (window != null) { + window.getAttributes().gravity = Gravity.CENTER; + } + dialog.setCancelable(builder.canCancel); + dialog.show(); + } + + public static class Builder { + + private Context context; + private String content; + private boolean canCancel; + + public Builder(Context context) { + this.context = context; + } + + public Builder setContent(String content) { + this.content = content; + return this; + } + + public Builder setCanCancel(boolean canCancel) { + this.canCancel = canCancel; + return this; + } + + + public TestDialog build() { + return new TestDialog(this); + } + + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/combination/Employee.java b/app/src/main/java/com/wss/amd/note/designpattern/combination/Employee.java new file mode 100644 index 0000000..6e15c78 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/combination/Employee.java @@ -0,0 +1,41 @@ +package com.wss.amd.note.designpattern.combination; + +import java.util.ArrayList; +import java.util.List; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public class Employee { + private String name; + private String dept; + private List subordinates = new ArrayList<>(); + + public Employee(String name, String dept) { + this.name = name; + this.dept = dept; + } + + + public void add(Employee e) { + subordinates.add(e); + } + + public void remove(Employee e) { + subordinates.remove(e); + } + + public List getSubordinates() { + return subordinates; + } + + @Override + public String toString() { + return "Employee{" + + "name='" + name + '\'' + + ", dept='" + dept + '\'' + + ", subordinates=" + subordinates + + '}'; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/command/WaiterInvoker.java b/app/src/main/java/com/wss/amd/note/designpattern/command/WaiterInvoker.java new file mode 100644 index 0000000..cba241d --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/command/WaiterInvoker.java @@ -0,0 +1,35 @@ +package com.wss.amd.note.designpattern.command; + +import com.wss.amd.note.designpattern.command.command.AbsCommand; + +/** + * Describe:具体调度者 + * Created by 吴天强 on 2022/1/19. + */ +public class WaiterInvoker { + private AbsCommand riceCommand; + private AbsCommand noodleCommand; + private AbsCommand stirFryCommand; + + public WaiterInvoker(AbsCommand riceCommand, AbsCommand noodleCommand, AbsCommand stirFryCommand) { + this.riceCommand = riceCommand; + this.noodleCommand = noodleCommand; + this.stirFryCommand = stirFryCommand; + } + + + public void chooseRice() { + riceCommand.execute(); + } + + public void chooseNoodle() { + noodleCommand.execute(); + } + + public void chooseStirFry() { + stirFryCommand.execute(); + } + + +} + diff --git a/app/src/main/java/com/wss/amd/note/designpattern/command/command/AbsCommand.java b/app/src/main/java/com/wss/amd/note/designpattern/command/command/AbsCommand.java new file mode 100644 index 0000000..474024b --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/command/command/AbsCommand.java @@ -0,0 +1,14 @@ +package com.wss.amd.note.designpattern.command.command; + +import com.wss.amd.note.designpattern.command.receiver.CookReceiver; + +/** + * Describe: + * Created by 吴天强 on 2022/1/19. + */ +public abstract class AbsCommand { + + protected CookReceiver receiver; + + public abstract void execute(); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/command/command/NoodleCommand.java b/app/src/main/java/com/wss/amd/note/designpattern/command/command/NoodleCommand.java new file mode 100644 index 0000000..3b0103f --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/command/command/NoodleCommand.java @@ -0,0 +1,18 @@ +package com.wss.amd.note.designpattern.command.command; + +import com.wss.amd.note.designpattern.command.receiver.NoodleCookeReceiver; + +/** + * Describe:面条命令 + * Created by 吴天强 on 2022/1/19. + */ +public class NoodleCommand extends AbsCommand { + public NoodleCommand() { + this.receiver = new NoodleCookeReceiver(); + } + + @Override + public void execute() { + receiver.cooking(); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/command/command/RiceCommand.java b/app/src/main/java/com/wss/amd/note/designpattern/command/command/RiceCommand.java new file mode 100644 index 0000000..2aae7e2 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/command/command/RiceCommand.java @@ -0,0 +1,19 @@ +package com.wss.amd.note.designpattern.command.command; + +import com.wss.amd.note.designpattern.command.receiver.RiceCookReceiver; + +/** + * Describe:做米饭具体命令 + * Created by 吴天强 on 2022/1/19. + */ +public class RiceCommand extends AbsCommand { + + public RiceCommand() { + this.receiver = new RiceCookReceiver(); + } + + @Override + public void execute() { + receiver.cooking(); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/command/command/StirFryCommand.java b/app/src/main/java/com/wss/amd/note/designpattern/command/command/StirFryCommand.java new file mode 100644 index 0000000..f57904a --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/command/command/StirFryCommand.java @@ -0,0 +1,18 @@ +package com.wss.amd.note.designpattern.command.command; + +import com.wss.amd.note.designpattern.command.receiver.StirFryReceiver; + +/** + * Describe:炒菜命令 + * Created by 吴天强 on 2022/1/19. + */ +public class StirFryCommand extends AbsCommand { + public StirFryCommand() { + this.receiver = new StirFryReceiver(); + } + + @Override + public void execute() { + receiver.cooking(); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/command/receiver/CookReceiver.java b/app/src/main/java/com/wss/amd/note/designpattern/command/receiver/CookReceiver.java new file mode 100644 index 0000000..605dbf1 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/command/receiver/CookReceiver.java @@ -0,0 +1,10 @@ +package com.wss.amd.note.designpattern.command.receiver; + +/** + * Describe: + * Created by 吴天强 on 2022/1/19. + */ +public interface CookReceiver { + + void cooking(); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/command/receiver/NoodleCookeReceiver.java b/app/src/main/java/com/wss/amd/note/designpattern/command/receiver/NoodleCookeReceiver.java new file mode 100644 index 0000000..bc9bfa0 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/command/receiver/NoodleCookeReceiver.java @@ -0,0 +1,12 @@ +package com.wss.amd.note.designpattern.command.receiver; + +/** + * Describe: + * Created by 吴天强 on 2022/1/19. + */ +public class NoodleCookeReceiver implements CookReceiver { + @Override + public void cooking() { + System.out.println("面条厨子开始做面条了~~~"); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/command/receiver/RiceCookReceiver.java b/app/src/main/java/com/wss/amd/note/designpattern/command/receiver/RiceCookReceiver.java new file mode 100644 index 0000000..026fd5d --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/command/receiver/RiceCookReceiver.java @@ -0,0 +1,14 @@ +package com.wss.amd.note.designpattern.command.receiver; + +/** + * Describe:米饭厨子 + * Created by 吴天强 on 2022/1/19. + */ +public class RiceCookReceiver implements CookReceiver { + + + @Override + public void cooking() { + System.out.println("米饭厨子开始做米饭~"); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/command/receiver/StirFryReceiver.java b/app/src/main/java/com/wss/amd/note/designpattern/command/receiver/StirFryReceiver.java new file mode 100644 index 0000000..415be9b --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/command/receiver/StirFryReceiver.java @@ -0,0 +1,12 @@ +package com.wss.amd.note.designpattern.command.receiver; + +/** + * Describe: + * Created by 吴天强 on 2022/1/19. + */ +public class StirFryReceiver implements CookReceiver { + @Override + public void cooking() { + System.out.println("炒菜厨子开始炒菜了~"); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/decorator/Condiment.java b/app/src/main/java/com/wss/amd/note/designpattern/decorator/Condiment.java new file mode 100644 index 0000000..12a5762 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/decorator/Condiment.java @@ -0,0 +1,10 @@ +package com.wss.amd.note.designpattern.decorator; + +import com.wss.amd.note.designpattern.decorator.base.Food; + +/** + * Describe:定义调料,也就是装饰者的基类,此类必须继承自Food + * Created by 吴天强 on 2022/1/18. + */ +public abstract class Condiment extends Food { +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/decorator/Egg.java b/app/src/main/java/com/wss/amd/note/designpattern/decorator/Egg.java new file mode 100644 index 0000000..49eee56 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/decorator/Egg.java @@ -0,0 +1,28 @@ +package com.wss.amd.note.designpattern.decorator; + +import com.wss.amd.note.designpattern.decorator.base.Food; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public class Egg extends Condiment { + private Food food; + + //这里很关键,需要传入具体的食物(大米、面条),当然也可以传入已经调好的(装饰过)食物 + public Egg(Food food) { + this.food = food; + } + + @Override + public String getName() { + //加个鸡蛋装饰 + return food.getName() + ",加个鸡蛋"; + } + + @Override + public double getPrice() { + //价格装饰 + return food.getPrice() + 2; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/decorator/GreenPepperShreddedMeat.java b/app/src/main/java/com/wss/amd/note/designpattern/decorator/GreenPepperShreddedMeat.java new file mode 100644 index 0000000..401dcb1 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/decorator/GreenPepperShreddedMeat.java @@ -0,0 +1,29 @@ +package com.wss.amd.note.designpattern.decorator; + +import com.wss.amd.note.designpattern.decorator.base.Food; + +/** + * Describe:青椒肉丝浇头 + * Created by 吴天强 on 2022/1/18. + */ +public class GreenPepperShreddedMeat extends Condiment { + + private Food food; + + //这里很关键,需要传入具体的食物(大米、面条),当然也可以传入已经调好的(装饰过)食物 + public GreenPepperShreddedMeat(Food food) { + this.food = food; + } + + @Override + public String getName() { + //进行青椒肉丝的装饰 + return food.getName() + ",加青椒肉丝"; + } + + @Override + public double getPrice() { + //进行价格装饰 + return food.getPrice() + 4; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/decorator/PotatoesBurnFireSirloin.java b/app/src/main/java/com/wss/amd/note/designpattern/decorator/PotatoesBurnFireSirloin.java new file mode 100644 index 0000000..f0298e3 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/decorator/PotatoesBurnFireSirloin.java @@ -0,0 +1,29 @@ +package com.wss.amd.note.designpattern.decorator; + +import com.wss.amd.note.designpattern.decorator.base.Food; + +/** + * Describe:土豆烧牛腩浇头 + * Created by 吴天强 on 2022/1/18. + */ +public class PotatoesBurnFireSirloin extends Condiment { + + private Food food; + + //这里很关键,需要传入具体的食物(大米、面条),当然也可以传入已经调好的(装饰过)食物 + public PotatoesBurnFireSirloin(Food food) { + this.food = food; + } + + @Override + public String getName() { + //进行土豆烧牛腩的装饰 + return food.getName() + ",加土豆烧牛腩"; + } + + @Override + public double getPrice() { + //进行价格装饰 + return food.getPrice() + 6; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/decorator/Vegetables.java b/app/src/main/java/com/wss/amd/note/designpattern/decorator/Vegetables.java new file mode 100644 index 0000000..273bf85 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/decorator/Vegetables.java @@ -0,0 +1,29 @@ +package com.wss.amd.note.designpattern.decorator; + +import com.wss.amd.note.designpattern.decorator.base.Food; + +/** + * Describe:加青菜 + * Created by 吴天强 on 2022/1/18. + */ +public class Vegetables extends Condiment { + + private Food food; + + //这里很关键,需要传入具体的食物(大米、面条),当然也可以传入已经调好的(装饰过)食物 + public Vegetables(Food food) { + this.food = food; + } + + @Override + public String getName() { + //进行素菜装饰 + return food.getName() + ",加一份青菜"; + } + + @Override + public double getPrice() { + //进行价格装饰 + return food.getPrice() + 1; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/decorator/base/Food.java b/app/src/main/java/com/wss/amd/note/designpattern/decorator/base/Food.java new file mode 100644 index 0000000..95c5eb1 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/decorator/base/Food.java @@ -0,0 +1,12 @@ +package com.wss.amd.note.designpattern.decorator.base; + +/** + * Describe:定义食物抽象基类 + * Created by 吴天强 on 2022/1/18. + */ +public abstract class Food { + + public abstract String getName(); + + public abstract double getPrice(); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/decorator/base/Noodle.java b/app/src/main/java/com/wss/amd/note/designpattern/decorator/base/Noodle.java new file mode 100644 index 0000000..b455c17 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/decorator/base/Noodle.java @@ -0,0 +1,17 @@ +package com.wss.amd.note.designpattern.decorator.base; + +/** + * Describe:定义普通面条 + * Created by 吴天强 on 2022/1/18. + */ +public class Noodle extends Food { + @Override + public String getName() { + return "清汤面"; + } + + @Override + public double getPrice() { + return 5; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/decorator/base/Rice.java b/app/src/main/java/com/wss/amd/note/designpattern/decorator/base/Rice.java new file mode 100644 index 0000000..d60cb03 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/decorator/base/Rice.java @@ -0,0 +1,17 @@ +package com.wss.amd.note.designpattern.decorator.base; + +/** + * Describe:定义普通米饭 + * Created by 吴天强 on 2022/1/18. + */ +public class Rice extends Food { + @Override + public String getName() { + return "白米饭"; + } + + @Override + public double getPrice() { + return 6; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/facade/BreakfastFood.java b/app/src/main/java/com/wss/amd/note/designpattern/facade/BreakfastFood.java new file mode 100644 index 0000000..9734ae8 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/facade/BreakfastFood.java @@ -0,0 +1,12 @@ +package com.wss.amd.note.designpattern.facade; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public class BreakfastFood implements Food { + @Override + public void make() { + System.out.println("开始制作早餐啦~~~"); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/facade/DinnerFood.java b/app/src/main/java/com/wss/amd/note/designpattern/facade/DinnerFood.java new file mode 100644 index 0000000..3e518e4 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/facade/DinnerFood.java @@ -0,0 +1,12 @@ +package com.wss.amd.note.designpattern.facade; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public class DinnerFood implements Food { + @Override + public void make() { + System.out.println("开始制作晚餐啦~~~"); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/facade/Food.java b/app/src/main/java/com/wss/amd/note/designpattern/facade/Food.java new file mode 100644 index 0000000..197e4e9 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/facade/Food.java @@ -0,0 +1,10 @@ +package com.wss.amd.note.designpattern.facade; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public interface Food { + + void make(); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/facade/FoodMaker.java b/app/src/main/java/com/wss/amd/note/designpattern/facade/FoodMaker.java new file mode 100644 index 0000000..322faef --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/facade/FoodMaker.java @@ -0,0 +1,31 @@ +package com.wss.amd.note.designpattern.facade; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public class FoodMaker { + + private BreakfastFood breakfastFood; + private LunchFood lunchFood; + private DinnerFood dinnerFood; + + public FoodMaker() { + breakfastFood = new BreakfastFood(); + lunchFood = new LunchFood(); + dinnerFood = new DinnerFood(); + } + //下面定义一堆方法,具体应该调用什么方法,有这个门面来决定 + + public void makeBreakfast() { + breakfastFood.make(); + } + + public void makeLunch() { + lunchFood.make(); + } + + public void makeDinner() { + dinnerFood.make(); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/facade/LunchFood.java b/app/src/main/java/com/wss/amd/note/designpattern/facade/LunchFood.java new file mode 100644 index 0000000..920218d --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/facade/LunchFood.java @@ -0,0 +1,12 @@ +package com.wss.amd.note.designpattern.facade; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public class LunchFood implements Food { + @Override + public void make() { + System.out.println("开始制作午餐啦~~~"); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/flyweight/Flyweight.java b/app/src/main/java/com/wss/amd/note/designpattern/flyweight/Flyweight.java new file mode 100644 index 0000000..063ce96 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/flyweight/Flyweight.java @@ -0,0 +1,21 @@ +package com.wss.amd.note.designpattern.flyweight; + +import java.util.WeakHashMap; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public class Flyweight { + + private WeakHashMap weakHashMap = new WeakHashMap<>(); + + public User getUser(int index) { + User user = weakHashMap.get(index); + if (user == null) { + user = new User(); + weakHashMap.put(index, user); + } + return user; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/flyweight/User.java b/app/src/main/java/com/wss/amd/note/designpattern/flyweight/User.java new file mode 100644 index 0000000..0c011ea --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/flyweight/User.java @@ -0,0 +1,9 @@ +package com.wss.amd.note.designpattern.flyweight; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public class User { + +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/AssembleComputer.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/AssembleComputer.java new file mode 100644 index 0000000..2ae7460 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/AssembleComputer.java @@ -0,0 +1,23 @@ +package com.wss.amd.note.designpattern.fracory.abstractfactory; + +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.ICPU; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.IHardDisk; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.IMainBoard; + +/** + * Describe:组装电脑 + * Created by 吴天强 on 2022/1/14. + */ +public class AssembleComputer { + + private ICPU cpu; + private IHardDisk hardDisk; + private IMainBoard mainBoard; + + public AssembleComputer(ICPU cpu, IHardDisk hardDisk, IMainBoard mainBoard) { + this.cpu = cpu; + this.hardDisk = hardDisk; + this.mainBoard = mainBoard; + } +} + diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/ICPU.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/ICPU.java new file mode 100644 index 0000000..48fb8d6 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/ICPU.java @@ -0,0 +1,8 @@ +package com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces; + +/** + * Describe:CPU 接口 + * Created by 吴天强 on 2022/1/14. + */ +public interface ICPU { +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/IComputerFactory.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/IComputerFactory.java new file mode 100644 index 0000000..c45fb55 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/IComputerFactory.java @@ -0,0 +1,14 @@ +package com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces; + +/** + * Describe:电脑接口 + * Created by 吴天强 on 2022/1/14. + */ +public interface IComputerFactory { + + ICPU createCPU(); + + IHardDisk createHardDisk(); + + IMainBoard createMainBoard(); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/IHardDisk.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/IHardDisk.java new file mode 100644 index 0000000..147cbda --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/IHardDisk.java @@ -0,0 +1,8 @@ +package com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces; + +/** + * Describe:硬盘接口 + * Created by 吴天强 on 2022/1/14. + */ +public interface IHardDisk { +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/IMainBoard.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/IMainBoard.java new file mode 100644 index 0000000..d87784a --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/IMainBoard.java @@ -0,0 +1,8 @@ +package com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces; + +/** + * Describe:主板接口 + * Created by 吴天强 on 2022/1/14. + */ +public interface IMainBoard { +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/computer/HaweiComputerFactoryFactory.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/computer/HaweiComputerFactoryFactory.java new file mode 100644 index 0000000..02dd705 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/computer/HaweiComputerFactoryFactory.java @@ -0,0 +1,31 @@ +package com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.computer; + +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.ICPU; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.IComputerFactory; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.IHardDisk; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.IMainBoard; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.cpu.AmdCPU; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.harddisk.ToshibaHardDisk; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.mainboard.AsusMainBoard; + +/** + * Describe:华为电脑工厂 + * Created by 吴天强 on 2022/1/14. + */ +public class HaweiComputerFactoryFactory implements IComputerFactory { + + @Override + public ICPU createCPU() { + return new AmdCPU(); + } + + @Override + public IHardDisk createHardDisk() { + return new ToshibaHardDisk(); + } + + @Override + public IMainBoard createMainBoard() { + return new AsusMainBoard(); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/computer/IntelComputerFactoryFactory.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/computer/IntelComputerFactoryFactory.java new file mode 100644 index 0000000..40b0d2e --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/computer/IntelComputerFactoryFactory.java @@ -0,0 +1,31 @@ +package com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.computer; + +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.ICPU; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.IComputerFactory; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.IHardDisk; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.IMainBoard; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.cpu.IntelCPU; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.harddisk.HpHardDisk; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.mainboard.MsiMainBoard; + +/** + * Describe:英特尔电脑工厂 + * Created by 吴天强 on 2022/1/14. + */ +public class IntelComputerFactoryFactory implements IComputerFactory { + + @Override + public ICPU createCPU() { + return new IntelCPU(); + } + + @Override + public IHardDisk createHardDisk() { + return new HpHardDisk(); + } + + @Override + public IMainBoard createMainBoard() { + return new MsiMainBoard(); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/computer/MacComputerFactoryFactory.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/computer/MacComputerFactoryFactory.java new file mode 100644 index 0000000..06de11a --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/computer/MacComputerFactoryFactory.java @@ -0,0 +1,29 @@ +package com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.computer; + +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.ICPU; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.IComputerFactory; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.IHardDisk; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.IMainBoard; +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.cpu.AmdCPU; + +/** + * Describe:MAC电脑工厂 + * Created by 吴天强 on 2022/1/14. + */ +public class MacComputerFactoryFactory implements IComputerFactory { + + @Override + public ICPU createCPU() { + return new AmdCPU(); + } + + @Override + public IHardDisk createHardDisk() { + return null; + } + + @Override + public IMainBoard createMainBoard() { + return null; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/cpu/AmdCPU.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/cpu/AmdCPU.java new file mode 100644 index 0000000..0e45fc1 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/cpu/AmdCPU.java @@ -0,0 +1,10 @@ +package com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.cpu; + +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.ICPU; + +/** + * Describe:AMD CPU + * Created by 吴天强 on 2022/1/14. + */ +public class AmdCPU implements ICPU { +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/cpu/IntelCPU.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/cpu/IntelCPU.java new file mode 100644 index 0000000..bd3b656 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/cpu/IntelCPU.java @@ -0,0 +1,10 @@ +package com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.cpu; + +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.ICPU; + +/** + * Describe:Intel CPU + * Created by 吴天强 on 2022/1/14. + */ +public class IntelCPU implements ICPU { +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/harddisk/HpHardDisk.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/harddisk/HpHardDisk.java new file mode 100644 index 0000000..3c147ca --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/harddisk/HpHardDisk.java @@ -0,0 +1,10 @@ +package com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.harddisk; + +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.IHardDisk; + +/** + * Describe:惠普硬盘 + * Created by 吴天强 on 2022/1/14. + */ +public class HpHardDisk implements IHardDisk { +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/harddisk/ToshibaHardDisk.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/harddisk/ToshibaHardDisk.java new file mode 100644 index 0000000..a4848b6 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/harddisk/ToshibaHardDisk.java @@ -0,0 +1,10 @@ +package com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.harddisk; + +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.IHardDisk; + +/** + * Describe:东芝硬盘 + * Created by 吴天强 on 2022/1/14. + */ +public class ToshibaHardDisk implements IHardDisk { +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/mainboard/AsusMainBoard.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/mainboard/AsusMainBoard.java new file mode 100644 index 0000000..6b65dab --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/mainboard/AsusMainBoard.java @@ -0,0 +1,10 @@ +package com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.mainboard; + +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.IMainBoard; + +/** + * Describe:华硕主板 + * Created by 吴天强 on 2022/1/14. + */ +public class AsusMainBoard implements IMainBoard { +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/mainboard/MsiMainBoard.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/mainboard/MsiMainBoard.java new file mode 100644 index 0000000..0903947 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/abstractfactory/interfaces/impl/mainboard/MsiMainBoard.java @@ -0,0 +1,10 @@ +package com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.impl.mainboard; + +import com.wss.amd.note.designpattern.fracory.abstractfactory.interfaces.IMainBoard; + +/** + * Describe:微星主板 + * Created by 吴天强 on 2022/1/14. + */ +public class MsiMainBoard implements IMainBoard { +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/normalfactory/ConfigFactory.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/normalfactory/ConfigFactory.java new file mode 100644 index 0000000..56042e3 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/normalfactory/ConfigFactory.java @@ -0,0 +1,21 @@ +package com.wss.amd.note.designpattern.fracory.normalfactory; + +import com.wss.amd.BuildConfig; +import com.wss.amd.note.designpattern.fracory.simplefactory.config.DevConfig; +import com.wss.amd.note.designpattern.fracory.simplefactory.config.IConfig; +import com.wss.amd.note.designpattern.fracory.simplefactory.config.ProConfig; + +/** + * Describe:创建环境工厂 + * Created by 吴天强 on 2022/1/14. + */ +public class ConfigFactory implements IConfigFactory { + + @Override + public IConfig createConfig() { + if (!BuildConfig.DEBUG) { + return new ProConfig(); + } + return new DevConfig(); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/normalfactory/IConfigFactory.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/normalfactory/IConfigFactory.java new file mode 100644 index 0000000..b46393a --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/normalfactory/IConfigFactory.java @@ -0,0 +1,12 @@ +package com.wss.amd.note.designpattern.fracory.normalfactory; + + +import com.wss.amd.note.designpattern.fracory.simplefactory.config.IConfig; + +/** + * Describe:定义创建环境工厂接口 + * Created by 吴天强 on 2022/1/14. + */ +public interface IConfigFactory { + IConfig createConfig(); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/simplefactory/SimpleFactory.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/simplefactory/SimpleFactory.java new file mode 100644 index 0000000..10a040e --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/simplefactory/SimpleFactory.java @@ -0,0 +1,30 @@ +package com.wss.amd.note.designpattern.fracory.simplefactory; + +import com.wss.amd.note.designpattern.fracory.simplefactory.config.DevConfig; +import com.wss.amd.note.designpattern.fracory.simplefactory.config.IConfig; +import com.wss.amd.note.designpattern.fracory.simplefactory.config.ProConfig; + +/** + * Describe:创建环境配置文件工厂 + * Created by 吴天强 on 2022/1/14. + */ +public class SimpleFactory { + + + /** + * 创建配置文件 + * + * @param type 环境类型 + * @return 已创建环境 + */ + public static IConfig createConfig(int type) { + switch (type) { + case 0: + return new ProConfig(); + case 1: + return new DevConfig(); + default: + } + return null; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/simplefactory/config/DevConfig.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/simplefactory/config/DevConfig.java new file mode 100644 index 0000000..44fa8e0 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/simplefactory/config/DevConfig.java @@ -0,0 +1,13 @@ +package com.wss.amd.note.designpattern.fracory.simplefactory.config; + +/** + * Describe:开发环境 + * Created by 吴天强 on 2022/1/14. + */ +public class DevConfig implements IConfig { + + @Override + public String getServiceUrl() { + return "http://192.168.0.1"; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/simplefactory/config/IConfig.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/simplefactory/config/IConfig.java new file mode 100644 index 0000000..948d25d --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/simplefactory/config/IConfig.java @@ -0,0 +1,10 @@ +package com.wss.amd.note.designpattern.fracory.simplefactory.config; + +/** + * Describe:定义环境配置相关方法 + * Created by 吴天强 on 2022/1/14. + */ +public interface IConfig { + + String getServiceUrl(); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/fracory/simplefactory/config/ProConfig.java b/app/src/main/java/com/wss/amd/note/designpattern/fracory/simplefactory/config/ProConfig.java new file mode 100644 index 0000000..a947a52 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/fracory/simplefactory/config/ProConfig.java @@ -0,0 +1,13 @@ +package com.wss.amd.note.designpattern.fracory.simplefactory.config; + +/** + * Describe:生产环境 + * Created by 吴天强 on 2022/1/14. + */ +public class ProConfig implements IConfig { + + @Override + public String getServiceUrl() { + return "http://pro.wss.com"; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/interpreter/AbstractExpression.java b/app/src/main/java/com/wss/amd/note/designpattern/interpreter/AbstractExpression.java new file mode 100644 index 0000000..b760dff --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/interpreter/AbstractExpression.java @@ -0,0 +1,9 @@ +package com.wss.amd.note.designpattern.interpreter; + +/** + * Describe: + * Created by 吴天强 on 2022/1/19. + */ +public interface AbstractExpression { + boolean interpret(GameUser gameUser); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/interpreter/CampTerminalExpression.java b/app/src/main/java/com/wss/amd/note/designpattern/interpreter/CampTerminalExpression.java new file mode 100644 index 0000000..f16a0fe --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/interpreter/CampTerminalExpression.java @@ -0,0 +1,26 @@ +package com.wss.amd.note.designpattern.interpreter; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Describe: + * Created by 吴天强 on 2022/1/19. + */ +public class CampTerminalExpression implements AbstractExpression { + + private List list = new ArrayList<>(); + + public CampTerminalExpression(String[] resource) { + this.list.addAll(Arrays.asList(resource)); + } + + @Override + public boolean interpret(@NotNull GameUser info) { + //对终结符表达式的处理 + return !list.contains(info.getCamp()); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/wss/amd/note/designpattern/interpreter/GameEnvironment.java b/app/src/main/java/com/wss/amd/note/designpattern/interpreter/GameEnvironment.java new file mode 100644 index 0000000..23d8908 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/interpreter/GameEnvironment.java @@ -0,0 +1,26 @@ +package com.wss.amd.note.designpattern.interpreter; + +/** + * Describe: + * Created by 吴天强 on 2022/1/19. + */ +public class GameEnvironment { + private AbstractExpression exp; + + + public GameEnvironment() { + //数据初始化 + exp = new NonTerminalExpression(new CampTerminalExpression(new String[]{"齐国", "吴国"}), + new GradeTerminalExpression(50)); + } + + public void operation(GameUser user) { + //调用相关表达式类的解释方法 + boolean interpret = exp.interpret(user); + if (interpret) { + System.out.println("恭喜来自" + user.getCamp() + "的" + user.getName() + ",您可以参加高级副本《鹊桥仙》"); + } else { + System.out.println("恭喜来自" + user.getCamp() + "的" + user.getName() + ",您可以参加普通副本《捉泥鳅》"); + } + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/interpreter/GameUser.java b/app/src/main/java/com/wss/amd/note/designpattern/interpreter/GameUser.java new file mode 100644 index 0000000..a590a52 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/interpreter/GameUser.java @@ -0,0 +1,24 @@ +package com.wss.amd.note.designpattern.interpreter; + +import lombok.Getter; +import lombok.Setter; + +/** + * Describe: 游戏角色 + * Created by 吴天强 on 2022/1/19. + */ +@Getter +@Setter +public class GameUser { + private String name; + private String grader; + private int grade; + private String camp; + private boolean participated; + + public GameUser(String name, int grade, String camp) { + this.name = name; + this.grade = grade; + this.camp = camp; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/interpreter/GradeTerminalExpression.java b/app/src/main/java/com/wss/amd/note/designpattern/interpreter/GradeTerminalExpression.java new file mode 100644 index 0000000..070bb38 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/interpreter/GradeTerminalExpression.java @@ -0,0 +1,22 @@ +package com.wss.amd.note.designpattern.interpreter; + +import org.jetbrains.annotations.NotNull; + +/** + * Describe: + * Created by 吴天强 on 2022/1/19. + */ +public class GradeTerminalExpression implements AbstractExpression { + + private int grade; + + public GradeTerminalExpression(int grade) { + this.grade = grade; + } + + @Override + public boolean interpret(@NotNull GameUser info) { + //对终结符表达式的处理 + return info.getGrade() < grade; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/wss/amd/note/designpattern/interpreter/NonTerminalExpression.java b/app/src/main/java/com/wss/amd/note/designpattern/interpreter/NonTerminalExpression.java new file mode 100644 index 0000000..2707162 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/interpreter/NonTerminalExpression.java @@ -0,0 +1,22 @@ +package com.wss.amd.note.designpattern.interpreter; + +/** + * Describe:非终结表达式 + * Created by 吴天强 on 2022/1/19. + */ +public class NonTerminalExpression implements AbstractExpression { + private AbstractExpression expression1; + private AbstractExpression expression2; + + public NonTerminalExpression(AbstractExpression expression1, AbstractExpression expression2) { + this.expression1 = expression1; + this.expression2 = expression2; + } + + @Override + public boolean interpret(GameUser info) { + //非对终结符表达式的处理 + return expression1.interpret(info) && expression2.interpret(info); + } +} + diff --git a/app/src/main/java/com/wss/amd/note/designpattern/iterator/Aggregate.java b/app/src/main/java/com/wss/amd/note/designpattern/iterator/Aggregate.java new file mode 100644 index 0000000..08c2560 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/iterator/Aggregate.java @@ -0,0 +1,12 @@ +package com.wss.amd.note.designpattern.iterator; + +/** + * Describe:聚合接口 + * Created by 吴天强 on 2022/1/19. + */ +public interface Aggregate { + + void add(E object); + + void remove(E object); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/iterator/Iterator.java b/app/src/main/java/com/wss/amd/note/designpattern/iterator/Iterator.java new file mode 100644 index 0000000..9066dd4 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/iterator/Iterator.java @@ -0,0 +1,14 @@ +package com.wss.amd.note.designpattern.iterator; + +/** + * Describe:迭代器接口 + * Created by 吴天强 on 2022/1/19. + */ +public interface Iterator { + + E first(); + + E next(); + + boolean hasNext(); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/iterator/UserAggregate.java b/app/src/main/java/com/wss/amd/note/designpattern/iterator/UserAggregate.java new file mode 100644 index 0000000..3a54589 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/iterator/UserAggregate.java @@ -0,0 +1,27 @@ +package com.wss.amd.note.designpattern.iterator; + +import java.util.ArrayList; +import java.util.List; + +/** + * Describe: + * Created by 吴天强 on 2022/1/19. + */ +public class UserAggregate implements Aggregate { + private List list = new ArrayList<>(); + + @Override + public void add(E object) { + list.add(object); + } + + @Override + public void remove(E object) { + list.remove(object); + } + + public Iterator iterator() { + return new UserIterator(list); + } + +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/iterator/UserIterator.java b/app/src/main/java/com/wss/amd/note/designpattern/iterator/UserIterator.java new file mode 100644 index 0000000..d8263bc --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/iterator/UserIterator.java @@ -0,0 +1,36 @@ +package com.wss.amd.note.designpattern.iterator; + +import java.util.List; + +/** + * Describe: + * Created by 吴天强 on 2022/1/19. + */ +public class UserIterator implements Iterator { + private List list = null; + private int index = -1; + + public UserIterator(List list) { + this.list = list; + } + + @Override + public E first() { + index = 0; + return list.get(index); + } + + @Override + public E next() { + E obj = null; + if (this.hasNext()) { + obj = list.get(++index); + } + return obj; + } + + @Override + public boolean hasNext() { + return index < list.size() - 1; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/mediator/Colleague.java b/app/src/main/java/com/wss/amd/note/designpattern/mediator/Colleague.java new file mode 100644 index 0000000..96578cd --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/mediator/Colleague.java @@ -0,0 +1,17 @@ +package com.wss.amd.note.designpattern.mediator; + +/** + * Describe: + * Created by 吴天强 on 2022/1/19. + */ +public abstract class Colleague { + protected Mediator mediator; + + public void setMedium(Mediator mediator) { + this.mediator = mediator; + } + + public abstract void receive(); + + public abstract void send(); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/mediator/ConcreteColleague1.java b/app/src/main/java/com/wss/amd/note/designpattern/mediator/ConcreteColleague1.java new file mode 100644 index 0000000..3c656ef --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/mediator/ConcreteColleague1.java @@ -0,0 +1,18 @@ +package com.wss.amd.note.designpattern.mediator; + +/** + * Describe: + * Created by 吴天强 on 2022/1/19. + */ +public class ConcreteColleague1 extends Colleague { + @Override + public void receive() { + System.out.println("具体同事类1收到请求。"); + } + + @Override + public void send() { + System.out.println("具体同事类1发出请求。"); + mediator.relay(this); //请中介者转发 + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/mediator/ConcreteColleague2.java b/app/src/main/java/com/wss/amd/note/designpattern/mediator/ConcreteColleague2.java new file mode 100644 index 0000000..e3a42c4 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/mediator/ConcreteColleague2.java @@ -0,0 +1,19 @@ +package com.wss.amd.note.designpattern.mediator; + +/** + * Describe: + * Created by 吴天强 on 2022/1/19. + */ +public class ConcreteColleague2 extends Colleague { + + @Override + public void receive() { + System.out.println("具体同事类2收到请求。"); + } + + @Override + public void send() { + System.out.println("具体同事类2发出请求。"); + mediator.relay(this); //请中介者转发 + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/mediator/ConcreteMediator.java b/app/src/main/java/com/wss/amd/note/designpattern/mediator/ConcreteMediator.java new file mode 100644 index 0000000..27416bc --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/mediator/ConcreteMediator.java @@ -0,0 +1,29 @@ +package com.wss.amd.note.designpattern.mediator; + +import java.util.ArrayList; +import java.util.List; + +/** + * Describe: + * Created by 吴天强 on 2022/1/19. + */ +public class ConcreteMediator implements Mediator { + private List colleagues = new ArrayList<>(); + + @Override + public void register(Colleague colleague) { + if (!colleagues.contains(colleague)) { + colleagues.add(colleague); + colleague.setMedium(this); + } + } + + @Override + public void relay(Colleague cl) { + for (Colleague ob : colleagues) { + if (!ob.equals(cl)) { + ob.receive(); + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/wss/amd/note/designpattern/mediator/Mediator.java b/app/src/main/java/com/wss/amd/note/designpattern/mediator/Mediator.java new file mode 100644 index 0000000..a68f7ca --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/mediator/Mediator.java @@ -0,0 +1,11 @@ +package com.wss.amd.note.designpattern.mediator; + +/** + * Describe: + * Created by 吴天强 on 2022/1/19. + */ +public interface Mediator { + void register(Colleague colleague); + + void relay(Colleague cl); //转发 +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/memorandum/Caretaker.java b/app/src/main/java/com/wss/amd/note/designpattern/memorandum/Caretaker.java new file mode 100644 index 0000000..58d3cf2 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/memorandum/Caretaker.java @@ -0,0 +1,18 @@ +package com.wss.amd.note.designpattern.memorandum; + +/** + * Describe:管理者 + * Created by 吴天强 on 2022/1/19. + */ +public class Caretaker { + + private Memento memento; + + public Memento getMemento() { + return memento; + } + + public void setMemento(Memento memento) { + this.memento = memento; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/memorandum/Memento.java b/app/src/main/java/com/wss/amd/note/designpattern/memorandum/Memento.java new file mode 100644 index 0000000..dae773d --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/memorandum/Memento.java @@ -0,0 +1,23 @@ +package com.wss.amd.note.designpattern.memorandum; + +/** + * Describe:备忘录 + * Created by 吴天强 on 2022/1/19. + */ +public class Memento { + + private String state; + + public Memento(String state) { + this.state = state; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } +} + diff --git a/app/src/main/java/com/wss/amd/note/designpattern/memorandum/Originator.java b/app/src/main/java/com/wss/amd/note/designpattern/memorandum/Originator.java new file mode 100644 index 0000000..55d35b7 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/memorandum/Originator.java @@ -0,0 +1,27 @@ +package com.wss.amd.note.designpattern.memorandum; + +import org.jetbrains.annotations.NotNull; + +/** + * Describe:发起人 + * Created by 吴天强 on 2022/1/19. + */ +public class Originator { + private String state; + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public Memento createMemento() { + return new Memento(this.getState()); + } + + public void restoreMemento(@NotNull Memento m) { + this.setState(m.getState()); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/observer/BinaryObserver.java b/app/src/main/java/com/wss/amd/note/designpattern/observer/BinaryObserver.java new file mode 100644 index 0000000..56c948f --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/observer/BinaryObserver.java @@ -0,0 +1,19 @@ +package com.wss.amd.note.designpattern.observer; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public class BinaryObserver extends Observer { + public BinaryObserver(Subject subject) { + this.subject = subject; + // 通常在构造方法中将 this 发布出去的操作一定要小心 + this.subject.attach(this); + } + + @Override + public void update() { + String result = Integer.toBinaryString(subject.getState()); + System.out.println("订阅的数据发生变化,新的数据处理为二进制值为:" + result); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/observer/HexaObserver.java b/app/src/main/java/com/wss/amd/note/designpattern/observer/HexaObserver.java new file mode 100644 index 0000000..efae8dc --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/observer/HexaObserver.java @@ -0,0 +1,18 @@ +package com.wss.amd.note.designpattern.observer; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public class HexaObserver extends Observer { + public HexaObserver(Subject subject) { + this.subject = subject; + this.subject.attach(this); + } + + @Override + public void update() { + String result = Integer.toHexString(subject.getState()); + System.out.println("订阅的数据发生变化,新的数据处理为十六进制值为:" + result); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/observer/Observer.java b/app/src/main/java/com/wss/amd/note/designpattern/observer/Observer.java new file mode 100644 index 0000000..f865bda --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/observer/Observer.java @@ -0,0 +1,12 @@ +package com.wss.amd.note.designpattern.observer; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public abstract class Observer { + + protected Subject subject; + + public abstract void update(); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/observer/Subject.java b/app/src/main/java/com/wss/amd/note/designpattern/observer/Subject.java new file mode 100644 index 0000000..a979207 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/observer/Subject.java @@ -0,0 +1,37 @@ +package com.wss.amd.note.designpattern.observer; + +import java.util.ArrayList; +import java.util.List; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public class Subject { + private List observerList = new ArrayList<>(); + + private int state; + + public void attach(Observer observer) { + observerList.add(observer); + } + + public int getState() { + return state; + } + + public void setState(int state) { + this.state = state; + //数据已变更,通知更新 + notifyAllObservers(); + } + + + private void notifyAllObservers() { + for (Observer observer : observerList) { + observer.update(); + } + } +} + + diff --git a/app/src/main/java/com/wss/amd/note/designpattern/proxy/User.java b/app/src/main/java/com/wss/amd/note/designpattern/proxy/User.java new file mode 100644 index 0000000..65fc591 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/proxy/User.java @@ -0,0 +1,32 @@ +package com.wss.amd.note.designpattern.proxy; + +import lombok.Getter; +import lombok.Setter; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +@Getter +@Setter +public class User { + + private String name; + private String password; + private int age; + private String dec; + + public User(String name) { + this.name = name; + } + + public User() { + } + + @Override + public String toString() { + return "User{" + + "name='" + name + '\'' + + '}'; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/proxy/UserService.java b/app/src/main/java/com/wss/amd/note/designpattern/proxy/UserService.java new file mode 100644 index 0000000..34d8ba0 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/proxy/UserService.java @@ -0,0 +1,13 @@ +package com.wss.amd.note.designpattern.proxy; + +/** + * Describe: + * Created by 吴天强 on 2022/1/17. + */ +public interface UserService { + + User creteAdmin(); + + User createUser(); + +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/proxy/UserServiceImpl.java b/app/src/main/java/com/wss/amd/note/designpattern/proxy/UserServiceImpl.java new file mode 100644 index 0000000..15ec082 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/proxy/UserServiceImpl.java @@ -0,0 +1,24 @@ +package com.wss.amd.note.designpattern.proxy; + +/** + * Describe:创建用户实现 + * Created by 吴天强 on 2022/1/17. + */ +public class UserServiceImpl implements UserService { + @Override + public User creteAdmin() { + User user = new User(); + user.setName("admin"); + user.setPassword("000000"); + return user; + } + + @Override + public User createUser() { + User user = new User(); + user.setName("Tom"); + user.setPassword("000000"); + user.setAge(18); + return user; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/proxy/UserServiceProxy.java b/app/src/main/java/com/wss/amd/note/designpattern/proxy/UserServiceProxy.java new file mode 100644 index 0000000..099cd8f --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/proxy/UserServiceProxy.java @@ -0,0 +1,26 @@ +package com.wss.amd.note.designpattern.proxy; + +/** + * Describe:代理类 + * Created by 吴天强 on 2022/1/17. + */ +public class UserServiceProxy implements UserService { + + private UserService userService = new UserServiceImpl(); + + @Override + public User creteAdmin() { + System.out.println("代理类开始创建管理员"); + User user = userService.creteAdmin(); + user.setDec("由代理类创建的管理员"); + return user; + } + + @Override + public User createUser() { + System.out.println("代理类开始创建用户"); + User user = userService.creteAdmin(); + user.setDec("由代理类创建的用户"); + return user; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/responsibility/LocationRuleHandler.java b/app/src/main/java/com/wss/amd/note/designpattern/responsibility/LocationRuleHandler.java new file mode 100644 index 0000000..5f61eec --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/responsibility/LocationRuleHandler.java @@ -0,0 +1,22 @@ +package com.wss.amd.note.designpattern.responsibility; + +import org.jetbrains.annotations.NotNull; + +/** + * Describe:地理位置规则 + * Created by 吴天强 on 2022/1/18. + */ +public class LocationRuleHandler extends RuleHandler { + private static final String LOCATION = "上海"; + + @Override + public void apply(@NotNull People people) { + if (LOCATION.equalsIgnoreCase(people.getLocation())) { + if (this.getSuccessor() != null) { + this.getSuccessor().apply(people); + } + } else { + throw new RuntimeException("该活动仅限上海地区参与"); + } + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/responsibility/NewUserRuleHandler.java b/app/src/main/java/com/wss/amd/note/designpattern/responsibility/NewUserRuleHandler.java new file mode 100644 index 0000000..c14cf88 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/responsibility/NewUserRuleHandler.java @@ -0,0 +1,22 @@ +package com.wss.amd.note.designpattern.responsibility; + +import org.jetbrains.annotations.NotNull; + +/** + * Describe:新用户规则 + * Created by 吴天强 on 2022/1/18. + */ +public class NewUserRuleHandler extends RuleHandler { + + + @Override + public void apply(@NotNull People people) { + if (people.isNewUser()) { + if (this.getSuccessor() != null) { + this.getSuccessor().apply(people); + } + } else { + throw new RuntimeException("该活动仅限新用户参与"); + } + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/responsibility/ParticipantsRuleHandler.java b/app/src/main/java/com/wss/amd/note/designpattern/responsibility/ParticipantsRuleHandler.java new file mode 100644 index 0000000..c73e2db --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/responsibility/ParticipantsRuleHandler.java @@ -0,0 +1,22 @@ +package com.wss.amd.note.designpattern.responsibility; + +import org.jetbrains.annotations.NotNull; + +/** + * Describe:参与人数规则 + * Created by 吴天强 on 2022/1/18. + */ +public class ParticipantsRuleHandler extends RuleHandler { + private static final int MAX_PARTICIPANTS = 10; + + @Override + public void apply(@NotNull People people) { + if (people.getParticipants() <= MAX_PARTICIPANTS) { + if (this.getSuccessor() != null) { + this.getSuccessor().apply(people); + } + } else { + throw new RuntimeException("该活动单次仅限" + MAX_PARTICIPANTS + "人参数"); + } + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/responsibility/People.java b/app/src/main/java/com/wss/amd/note/designpattern/responsibility/People.java new file mode 100644 index 0000000..9c98bd4 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/responsibility/People.java @@ -0,0 +1,16 @@ +package com.wss.amd.note.designpattern.responsibility; + +import lombok.Getter; +import lombok.Setter; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +@Getter +@Setter +public class People { + private boolean newUser; + private String location; + private int participants; +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/responsibility/RuleHandler.java b/app/src/main/java/com/wss/amd/note/designpattern/responsibility/RuleHandler.java new file mode 100644 index 0000000..7f0f532 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/responsibility/RuleHandler.java @@ -0,0 +1,22 @@ +package com.wss.amd.note.designpattern.responsibility; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public abstract class RuleHandler { + + private RuleHandler successor; + + + public RuleHandler getSuccessor() { + return successor; + } + + public void setSuccessor(RuleHandler successor) { + this.successor = successor; + } + + + public abstract void apply(People people); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/singleton/FullMan.java b/app/src/main/java/com/wss/amd/note/designpattern/singleton/FullMan.java new file mode 100644 index 0000000..05c4281 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/singleton/FullMan.java @@ -0,0 +1,26 @@ +package com.wss.amd.note.designpattern.singleton; + +/** + * Describe:单例模式 - 饱汉模式 + * Created by 吴天强 on 2022/1/14. + */ +public class FullMan { + private FullMan() { + } + + // 和饿汉模式相比,这边不需要先实例化出来,注意这里的 volatile,它是必须的 + private static volatile FullMan instance = null; + + public static FullMan getInstance() { + if (instance == null) { + // 加锁 + synchronized (FullMan.class) { + // 这一次判断也是必须的,不然会有并发问题 + if (instance == null) { + instance = new FullMan(); + } + } + } + return instance; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/wss/amd/note/designpattern/singleton/HungryMan.java b/app/src/main/java/com/wss/amd/note/designpattern/singleton/HungryMan.java new file mode 100644 index 0000000..fe49309 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/singleton/HungryMan.java @@ -0,0 +1,17 @@ +package com.wss.amd.note.designpattern.singleton; + +/** + * Describe:单例模式 - 饿汉模式 + * Created by 吴天强 on 2022/1/14. + */ +public class HungryMan { + private HungryMan() { + } + + // 创建私有静态实例,意味着这个类第一次使用的时候就会进行创建 + private static HungryMan instance = new HungryMan(); + + public static HungryMan getInstance() { + return instance; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/singleton/NestedClass.java b/app/src/main/java/com/wss/amd/note/designpattern/singleton/NestedClass.java new file mode 100644 index 0000000..4ebb988 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/singleton/NestedClass.java @@ -0,0 +1,19 @@ +package com.wss.amd.note.designpattern.singleton; + +/** + * Describe:单例模式 - 嵌套类 + * Created by 吴天强 on 2022/1/14. + */ +public class NestedClass { + private NestedClass() { + } + + //主要是使用了 嵌套类可以访问外部类的静态属性和静态方法 的特性 + private static class Holder { + private static NestedClass instance = new NestedClass(); + } + + public static NestedClass getInstance() { + return Holder.instance; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/state/InvisibleState.java b/app/src/main/java/com/wss/amd/note/designpattern/state/InvisibleState.java new file mode 100644 index 0000000..3f07bdd --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/state/InvisibleState.java @@ -0,0 +1,24 @@ +package com.wss.amd.note.designpattern.state; + +import org.jetbrains.annotations.NotNull; + +import androidx.annotation.NonNull; + +/** + * Describe:隐身 + * Created by 吴天强 on 2022/1/18. + */ +public class InvisibleState implements State { + @Override + public void doAction(@NotNull QQUser qqUser) { + System.out.println("此时QQ用户隐身啦~"); + qqUser.setState(this); + + } + + @NonNull + @Override + public String toString() { + return "InvisibleState"; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/state/OnLineState.java b/app/src/main/java/com/wss/amd/note/designpattern/state/OnLineState.java new file mode 100644 index 0000000..8ddf781 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/state/OnLineState.java @@ -0,0 +1,23 @@ +package com.wss.amd.note.designpattern.state; + +import org.jetbrains.annotations.NotNull; + +import androidx.annotation.NonNull; + +/** + * Describe:上线 + * Created by 吴天强 on 2022/1/18. + */ +public class OnLineState implements State { + @Override + public void doAction(@NotNull QQUser qqUser) { + System.out.println("此时QQ用户在线了~"); + qqUser.setState(this); + } + + @NonNull + @Override + public String toString() { + return "OnLineState"; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/state/QQUser.java b/app/src/main/java/com/wss/amd/note/designpattern/state/QQUser.java new file mode 100644 index 0000000..5451132 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/state/QQUser.java @@ -0,0 +1,19 @@ +package com.wss.amd.note.designpattern.state; + +import lombok.Getter; +import lombok.Setter; + +/** + * Describe:QQ用户 + * Created by 吴天强 on 2022/1/18. + */ +@Getter +@Setter +public class QQUser { + private State state; + private String name; + + public QQUser(String name) { + this.name = name; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/state/State.java b/app/src/main/java/com/wss/amd/note/designpattern/state/State.java new file mode 100644 index 0000000..e767bbd --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/state/State.java @@ -0,0 +1,10 @@ +package com.wss.amd.note.designpattern.state; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public interface State { + + void doAction(QQUser QQUser); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/strategy/NoodleStrategy.java b/app/src/main/java/com/wss/amd/note/designpattern/strategy/NoodleStrategy.java new file mode 100644 index 0000000..d7d5cd6 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/strategy/NoodleStrategy.java @@ -0,0 +1,12 @@ +package com.wss.amd.note.designpattern.strategy; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public class NoodleStrategy implements Strategy { + @Override + public void eat(int count) { + System.out.println("今天" + count + "人吃面条吧!!!"); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/strategy/NoonEatWhat.java b/app/src/main/java/com/wss/amd/note/designpattern/strategy/NoonEatWhat.java new file mode 100644 index 0000000..74515cb --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/strategy/NoonEatWhat.java @@ -0,0 +1,18 @@ +package com.wss.amd.note.designpattern.strategy; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public class NoonEatWhat { + + private Strategy strategy; + + public NoonEatWhat(Strategy strategy) { + this.strategy = strategy; + } + + public void executeEat(int cont) { + strategy.eat(cont); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/strategy/RiceStrategy.java b/app/src/main/java/com/wss/amd/note/designpattern/strategy/RiceStrategy.java new file mode 100644 index 0000000..07b529e --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/strategy/RiceStrategy.java @@ -0,0 +1,12 @@ +package com.wss.amd.note.designpattern.strategy; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public class RiceStrategy implements Strategy { + @Override + public void eat(int count) { + System.out.println("今天" + count + "人吃米饭呀~~"); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/strategy/Strategy.java b/app/src/main/java/com/wss/amd/note/designpattern/strategy/Strategy.java new file mode 100644 index 0000000..b9adcbc --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/strategy/Strategy.java @@ -0,0 +1,10 @@ +package com.wss.amd.note.designpattern.strategy; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public interface Strategy { + + void eat(int count); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/template/AbsTemplateMethod.java b/app/src/main/java/com/wss/amd/note/designpattern/template/AbsTemplateMethod.java new file mode 100644 index 0000000..fc15bd1 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/template/AbsTemplateMethod.java @@ -0,0 +1,26 @@ +package com.wss.amd.note.designpattern.template; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public abstract class AbsTemplateMethod { + + + public void templateMethod() { + init(); + ready(); + end(); + } + + protected void init() { + System.out.println("基类已经实现init"); + } + + protected abstract void ready(); + + protected void end() { + } + + +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/template/TemplateMethod.java b/app/src/main/java/com/wss/amd/note/designpattern/template/TemplateMethod.java new file mode 100644 index 0000000..5f0c6a5 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/template/TemplateMethod.java @@ -0,0 +1,18 @@ +package com.wss.amd.note.designpattern.template; + +/** + * Describe: + * Created by 吴天强 on 2022/1/18. + */ +public class TemplateMethod extends AbsTemplateMethod { + @Override + protected void ready() { + System.out.println("子类必须实现的抽象方法"); + } + + @Override + protected void end() { + super.end(); + System.out.println("子类可覆写的父类已经实现的方法"); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/visitor/SetMaterial.java b/app/src/main/java/com/wss/amd/note/designpattern/visitor/SetMaterial.java new file mode 100644 index 0000000..6ffd3c9 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/visitor/SetMaterial.java @@ -0,0 +1,33 @@ +package com.wss.amd.note.designpattern.visitor; + +import com.wss.amd.note.designpattern.visitor.company.Company; +import com.wss.amd.note.designpattern.visitor.material.Material; + +import java.util.ArrayList; +import java.util.List; + +/** + * Describe:对象结构角色:材料集 + * Created by 吴天强 on 2022/1/19. + */ +public class SetMaterial { + + private List list = new ArrayList<>(); + + + public String accept(Company visitor) { + StringBuilder sb = new StringBuilder(); + for (Material m : list) { + sb.append(m.accept(visitor)).append(","); + } + return sb.toString(); + } + + public void add(Material element) { + list.add(element); + } + + public void remove(Material element) { + list.remove(element); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/visitor/company/ArtCompany.java b/app/src/main/java/com/wss/amd/note/designpattern/visitor/company/ArtCompany.java new file mode 100644 index 0000000..5ce4e31 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/visitor/company/ArtCompany.java @@ -0,0 +1,20 @@ +package com.wss.amd.note.designpattern.visitor.company; + +import com.wss.amd.note.designpattern.visitor.material.Copper; +import com.wss.amd.note.designpattern.visitor.material.Paper; + +/** + * Describe:具体访问者:艺术公司 + * Created by 吴天强 on 2022/1/19. + */ +public class ArtCompany implements Company { + @Override + public String create(Copper copper) { + return "讲学图"; + } + + @Override + public String create(Paper paper) { + return "朱熹铜像"; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/visitor/company/Company.java b/app/src/main/java/com/wss/amd/note/designpattern/visitor/company/Company.java new file mode 100644 index 0000000..c6891ec --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/visitor/company/Company.java @@ -0,0 +1,16 @@ +package com.wss.amd.note.designpattern.visitor.company; + +import com.wss.amd.note.designpattern.visitor.material.Copper; +import com.wss.amd.note.designpattern.visitor.material.Paper; + +/** + * Describe:定义公司接口,分别可以制造纸制品 和铜制品 + * Created by 吴天强 on 2022/1/19. + */ +public interface Company { + + String create(Copper copper); + + String create(Paper paper); + +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/visitor/company/MintCompany.java b/app/src/main/java/com/wss/amd/note/designpattern/visitor/company/MintCompany.java new file mode 100644 index 0000000..856c9ac --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/visitor/company/MintCompany.java @@ -0,0 +1,20 @@ +package com.wss.amd.note.designpattern.visitor.company; + +import com.wss.amd.note.designpattern.visitor.material.Copper; +import com.wss.amd.note.designpattern.visitor.material.Paper; + +/** + * Describe:具体访问者:造币公司 + * Created by 吴天强 on 2022/1/19. + */ +public class MintCompany implements Company { + @Override + public String create(Copper copper) { + return "纸币"; + } + + @Override + public String create(Paper paper) { + return "铜币"; + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/visitor/material/Copper.java b/app/src/main/java/com/wss/amd/note/designpattern/visitor/material/Copper.java new file mode 100644 index 0000000..94b2851 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/visitor/material/Copper.java @@ -0,0 +1,16 @@ +package com.wss.amd.note.designpattern.visitor.material; + +import com.wss.amd.note.designpattern.visitor.company.Company; + +import org.jetbrains.annotations.NotNull; + +/** + * Describe:具体元素:铜 + * Created by 吴天强 on 2022/1/19. + */ +public class Copper implements Material { + @Override + public String accept(@NotNull Company visitor) { + return visitor.create(this); + } +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/visitor/material/Material.java b/app/src/main/java/com/wss/amd/note/designpattern/visitor/material/Material.java new file mode 100644 index 0000000..d5e8025 --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/visitor/material/Material.java @@ -0,0 +1,12 @@ +package com.wss.amd.note.designpattern.visitor.material; + +import com.wss.amd.note.designpattern.visitor.company.Company; + +/** + * Describe: + * Created by 吴天强 on 2022/1/19. + */ +public interface Material { + + String accept(Company visitor); +} diff --git a/app/src/main/java/com/wss/amd/note/designpattern/visitor/material/Paper.java b/app/src/main/java/com/wss/amd/note/designpattern/visitor/material/Paper.java new file mode 100644 index 0000000..86fb84a --- /dev/null +++ b/app/src/main/java/com/wss/amd/note/designpattern/visitor/material/Paper.java @@ -0,0 +1,16 @@ +package com.wss.amd.note.designpattern.visitor.material; + +import com.wss.amd.note.designpattern.visitor.company.Company; + +import org.jetbrains.annotations.NotNull; + +/** + * Describe:具体元素:纸 + * Created by 吴天强 on 2022/1/19. + */ +public class Paper implements Material { + @Override + public String accept(@NotNull Company visitor) { + return visitor.create(this); + } +} diff --git a/app/src/main/java/com/wss/amd/profile/DevProfile.java b/app/src/main/java/com/wss/amd/profile/DevProfile.java new file mode 100644 index 0000000..52a2ebf --- /dev/null +++ b/app/src/main/java/com/wss/amd/profile/DevProfile.java @@ -0,0 +1,31 @@ +package com.wss.amd.profile; + + +import com.wss.common.profile.IProfile; + +/** + * Describe:开发环境配置 + * Created by 吴天强 on 2020/4/13. + */ +public class DevProfile implements IProfile { + + /** + * Api服务器地址 + */ + private static final String SERVICE_BAR_URL = "https://www.wanandroid.com"; + + @Override + public String getServiceBase() { + return SERVICE_BAR_URL; + } + + @Override + public boolean isSecret() { + return false; + } + + @Override + public String getAesSecretKey() { + return "t96IBJiOSURJZOzdjQ36pw=="; + } +} diff --git a/app/src/main/java/com/wss/amd/profile/ProProfile.java b/app/src/main/java/com/wss/amd/profile/ProProfile.java new file mode 100644 index 0000000..71ac39e --- /dev/null +++ b/app/src/main/java/com/wss/amd/profile/ProProfile.java @@ -0,0 +1,31 @@ +package com.wss.amd.profile; + + +import com.wss.common.profile.IProfile; + +/** + * Describe:生产环境配置 + * Created by 吴天强 on 2021/11/15. + */ +public class ProProfile implements IProfile { + + /** + * Api服务器地址 + */ + private static final String SERVICE_BAR_URL = "https://www.wanandroid.com"; + + @Override + public String getServiceBase() { + return SERVICE_BAR_URL; + } + + @Override + public boolean isSecret() { + return true; + } + + @Override + public String getAesSecretKey() { + return "t96IBJiOSURJZOzdjQ36pw=="; + } +} diff --git a/app/src/main/java/com/wss/amd/profile/ProfileFactory.java b/app/src/main/java/com/wss/amd/profile/ProfileFactory.java new file mode 100644 index 0000000..6f9f9fb --- /dev/null +++ b/app/src/main/java/com/wss/amd/profile/ProfileFactory.java @@ -0,0 +1,32 @@ +package com.wss.amd.profile; + + +import com.wss.amd.BuildConfig; +import com.wss.common.profile.IProfile; +import com.wss.common.profile.IProfileFactory; + +/** + * Describe:创建环境工厂 + * Created by 吴天强 on 2020/4/13. + */ +public class ProfileFactory implements IProfileFactory { + /** + * 开发环境 + */ + private static final String DEV = "DEV"; + /** + * 生产环境 + */ + private static final String PRO = "PRO"; + + @Override + public IProfile createProfile() { + switch (BuildConfig.FLAVOR) { + case PRO: + return new ProProfile(); + case DEV: + default: + return new DevProfile(); + } + } +} diff --git a/app/src/main/res/layout/activity_loading.xml b/app/src/main/res/layout/activity_loading.xml new file mode 100644 index 0000000..0b6d228 --- /dev/null +++ b/app/src/main/res/layout/activity_loading.xml @@ -0,0 +1,30 @@ + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6862253..989abce 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,3 @@ - AMD + diff --git a/build.gradle b/build.gradle index 87207ac..b95a8be 100644 --- a/build.gradle +++ b/build.gradle @@ -1,29 +1,39 @@ apply from: "config.gradle" buildscript { - repositories { - google() - jcenter() - mavenCentral() + maven { url 'https://maven.aliyun.com/repository/google' } + maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' } + maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' } +// google() +// jcenter( } dependencies { - classpath "com.android.tools.build:gradle:3.0.1" - //黄油刀 - classpath "com.jakewharton:butterknife-gradle-plugin:8.4.0" + classpath 'com.android.tools.build:gradle:3.6.2' + classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.1' //数据库GreenDAO classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' + //听云 } +} - allprojects { - repositories { - google() - jcenter() - maven { url 'https://jitpack.io' } - } +allprojects { + repositories { + maven { url "https://dl.bintray.com/tencentqcloudterminal/maven" } + maven { url 'https://maven.aliyun.com/repository/google' } + maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' } + maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' } + maven { url 'https://jitpack.io' } + maven { url "http://mvn.gt.igexin.com/nexus/content/repositories/releases/" } + maven { url 'https://gitee.com/liuchaoya/libcommon/raw/master/repository/' } +// google() +// jcenter() } } + task clean(type: Delete) { delete rootProject.buildDir } + + diff --git a/common_base/build.gradle b/common_base/build.gradle index 23dac5f..a364a2f 100644 --- a/common_base/build.gradle +++ b/common_base/build.gradle @@ -35,54 +35,61 @@ android { dexOptions { javaMaxHeapSize "4g" } + compileOptions { + targetCompatibility rootProject.ext.versions.javaSDKVersion + sourceCompatibility rootProject.ext.versions.javaSDKVersion + } } dependencies { // 在项目中的libs中的所有的.jar结尾的文件,都是依赖 - compile fileTree(include: ['*.jar'], dir: 'libs') - //把implementation 用api代替,它是对外部公开的, 所有其他的module就不需要添加该依赖 - api rootProject.ext.dependencies["appcompat_v7"] - api rootProject.ext.dependencies["constraint_layout"] - api rootProject.ext.dependencies["cardview-v7"] - api rootProject.ext.dependencies["recyclerview-v7"] - api rootProject.ext.dependencies["support-v4"] - api rootProject.ext.dependencies["design"] - api rootProject.ext.dependencies["support_annotations"] - //MultiDex分包方法 + api fileTree(include: ['*.jar'], dir: 'libs') + //android基础库 + api rootProject.ext.dependencies["appcompat"] + api rootProject.ext.dependencies["recyclerview"] + api rootProject.ext.dependencies["cardview"] + api rootProject.ext.dependencies["annotation"] + api rootProject.ext.dependencies["material"] api rootProject.ext.dependencies["multidex"] - //黄油刀 - annotationProcessor rootProject.ext.dependencies["butterknife_compiler"] + api rootProject.ext.dependencies["junit"] + api rootProject.ext.dependencies["swiperefreshlayout"] + api rootProject.ext.dependencies["localbroadcastmanager"] + //Lombok + api rootProject.ext.dependencies["lombok"] + api rootProject.ext.dependencies["javaxAnnotation"] + //阿里ARouter + api rootProject.ext.dependencies["arouter"] + annotationProcessor rootProject.ext.dependencies["arouterCompiler"] + //Butterknife api rootProject.ext.dependencies["butterknife"] - //Arouter路由 - annotationProcessor rootProject.ext.dependencies["arouter_compiler"] - api rootProject.ext.dependencies["arouter_api"] - api rootProject.ext.dependencies["arouter_annotation"] - //eventbus 发布/订阅事件总线 - api rootProject.ext.dependencies["eventbus"] - //网络 - api rootProject.ext.dependencies["novate"] - //日志 + annotationProcessor rootProject.ext.dependencies["butterknifeCompiler"] + //EventBus + api rootProject.ext.dependencies["eventBus"] + //Logger api rootProject.ext.dependencies["logger"] - //fastJson - api rootProject.ext.dependencies["fastjson"] //沉浸栏 api rootProject.ext.dependencies["immersionbar"] - //banner + //Bnnaer api rootProject.ext.dependencies["banner"] -// //图片加载 -// api rootProject.ext.dependencies["picasso"] - //图片加载 + //Glude api rootProject.ext.dependencies["glide"] - //lombok - api rootProject.ext.dependencies["lombok"] - api rootProject.ext.dependencies["lombokJavax"] - //时间 日期 地址 条件选中器 + //弹窗选择器 api rootProject.ext.dependencies["pickerView"] - //万能Adapter + //危险权限申请 + api rootProject.ext.dependencies["xxpermissions"] + //网络 + api rootProject.ext.dependencies["rxHttp"] + api rootProject.ext.dependencies["rxLife"] + api rootProject.ext.dependencies["rxAndroid"] + annotationProcessor rootProject.ext.dependencies["rxCompiler"] + //万能适配器 api rootProject.ext.dependencies["superAdapter"] + //图片预览 + api rootProject.ext.dependencies["scaleImageView"] + //二维码扫描 + api rootProject.ext.dependencies["zxing"] + //刷新库 + api rootProject.ext.dependencies["refreshLayout"] //GreenDao api rootProject.ext.dependencies["greenDao"] - //scaleImageView - api rootProject.ext.dependencies["scaleImageView"] - annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0' } diff --git a/common_base/doc.txt b/common_base/doc.txt index ee0c71a..17a85e5 100644 --- a/common_base/doc.txt +++ b/common_base/doc.txt @@ -1,3 +1,8 @@ 说明:该module为所有业务Module必须依赖的lib - 其中包含了第三方库的加载、网络请求初始化、日志、公共资源文件、公共方法的抽取等。 \ No newline at end of file + 其中包含了第三方库的加载、网络请求初始化、日志、公共资源文件、公共方法的抽取等。 + + +Jar包说明 + +bcprov-1.3.3.jar Aes加密接用到该包 \ No newline at end of file diff --git a/common_base/libs/bcprov-1.3.3.jar b/common_base/libs/bcprov-1.3.3.jar new file mode 100644 index 0000000..4554ce5 Binary files /dev/null and b/common_base/libs/bcprov-1.3.3.jar differ diff --git a/common_base/src/main/AndroidManifest.xml b/common_base/src/main/AndroidManifest.xml index a4ea8b7..146ce8a 100644 --- a/common_base/src/main/AndroidManifest.xml +++ b/common_base/src/main/AndroidManifest.xml @@ -9,14 +9,17 @@ + + - + + diff --git a/common_base/src/main/assets/iconfont/iconfont.ttf b/common_base/src/main/assets/iconfont/iconfont.ttf new file mode 100644 index 0000000..e24ea22 Binary files /dev/null and b/common_base/src/main/assets/iconfont/iconfont.ttf differ diff --git a/common_base/src/main/java/com/wss/common/activity/WebViewActivity.java b/common_base/src/main/java/com/wss/common/activity/WebViewActivity.java deleted file mode 100644 index 5d252fb..0000000 --- a/common_base/src/main/java/com/wss/common/activity/WebViewActivity.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.wss.common.activity; - -import android.content.Context; -import android.content.Intent; -import android.net.http.SslError; -import android.view.KeyEvent; -import android.webkit.SslErrorHandler; -import android.webkit.WebView; -import android.webkit.WebViewClient; - -import com.wss.common.base.ActionBarActivity; -import com.wss.common.base.R; -import com.wss.common.base.R2; -import com.wss.common.base.mvp.BasePresenter; -import com.wss.common.widget.ProgressWebView; - -import butterknife.BindView; - -/** - * Describe:WevView Activity - * Created by 吴天强 on 2018/10/19. - */ - -public class WebViewActivity extends ActionBarActivity { - - @BindView(R2.id.pw_view) - ProgressWebView webView; - - - public static void actionStart(Context context, String url) { - Intent intent = new Intent(context, WebViewActivity.class); - intent.putExtra("URL", url); - context.startActivity(intent); - } - - @Override - protected BasePresenter createPresenter() { - return null; - } - - @Override - protected int getLayoutId() { - return R.layout.activity_webview; - } - - @Override - protected void initView() { - webView.loadUrl(getIntent().getStringExtra("URL")); - webView.setWebViewClient(new MyWebClient()); - } - - - private class MyWebClient extends WebViewClient { - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - webView.loadUrl(url); - return true; - } - - @Override - public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { - handler.proceed(); // 接受所有网站的证书 - } - - @Override - public void onPageFinished(WebView view, String url) { - super.onPageFinished(view, url); - setTitleText(view.getTitle()); - } - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_BACK) { - showFinish(); - return true; - } else { - return super.onKeyDown(keyCode, event); - } - } - - - private void showFinish() { - if (webView.canGoBack()) { - webView.goBack(); - } else { - finish(); - } - } - -} diff --git a/common_base/src/main/java/com/wss/common/adapter/BannerImgAdapter.java b/common_base/src/main/java/com/wss/common/adapter/BannerImgAdapter.java index 8ab2b19..1a0a6bc 100644 --- a/common_base/src/main/java/com/wss/common/adapter/BannerImgAdapter.java +++ b/common_base/src/main/java/com/wss/common/adapter/BannerImgAdapter.java @@ -7,6 +7,7 @@ import com.bigkoo.convenientbanner.holder.CBViewHolderCreator; import com.bigkoo.convenientbanner.holder.Holder; import com.wss.common.base.R; +import com.wss.common.bean.Banner; import com.wss.common.utils.ImageUtils; /** @@ -14,20 +15,30 @@ * Created by 吴天强 on 2018/11/1. */ public class BannerImgAdapter implements CBViewHolderCreator { + /** + * 是否加载圆角的 + */ + private boolean circle = false; + + public BannerImgAdapter() { + } + + public BannerImgAdapter(boolean circle) { + this.circle = circle; + } @Override public Holder createHolder(View itemView) { - - return new Holder(itemView) { + return new Holder(itemView) { LinearLayout layout; ImageView imageView; @Override protected void initView(View itemView) { layout = itemView.findViewById(R.id.ll_img_parent); - if (getImageView() != null) { + imageView = getImageView(); + if (imageView != null) { layout.removeAllViews(); - imageView = getImageView(); layout.addView(imageView); } else { imageView = itemView.findViewById(R.id.image); @@ -35,8 +46,12 @@ protected void initView(View itemView) { } @Override - public void updateUI(String data) { - ImageUtils.loadImage(imageView, data); + public void updateUI(Banner data) { + if (circle) { + ImageUtils.loadImageCircleBead(imageView, data.getImageUrl(), 4); + } else { + ImageUtils.loadImage(imageView, data.getImageUrl()); + } } }; } @@ -48,6 +63,8 @@ public int getLayoutId() { /** * 可以传入自定义的ImageView + * + * @return ImageView */ public ImageView getImageView() { return null; diff --git a/common_base/src/main/java/com/wss/common/adapter/FragmentPagerAdapter.java b/common_base/src/main/java/com/wss/common/adapter/FragmentPagerAdapter.java index 499cb62..3c5af2d 100644 --- a/common_base/src/main/java/com/wss/common/adapter/FragmentPagerAdapter.java +++ b/common_base/src/main/java/com/wss/common/adapter/FragmentPagerAdapter.java @@ -1,35 +1,46 @@ package com.wss.common.adapter; -import android.support.annotation.NonNull; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentStatePagerAdapter; -import android.view.ViewGroup; +import android.util.Log; import com.wss.common.base.BaseFragment; import com.wss.common.bean.HorizontalTabTitle; +import org.jetbrains.annotations.NotNull; + import java.util.List; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentStatePagerAdapter; + + /** * Describe:滑动Fragment适配器 - * 如果滑动Fragment是同一个 使用双参构造方法 则覆写 getTabFragment 返回Fragment - * 如果滑动Fragment是不同的Fragment 使用第三参个构造方法 传入对应的Fragment + * 如果滑动Fragment是同一个 使用双参构造方法 覆写 getTabFragment 返回Fragment + * 如果滑动Fragment是不同的Fragment 使用第三参构造方法 传入对应的Fragment集合 *

* Created by 吴天强 on 2018/10/22. */ - public class FragmentPagerAdapter extends FragmentStatePagerAdapter { private List titles; private List fragments; /** * 使用该构造方法 必须重写 getTabFragment 返回对应的Fragment + * + * @param fm FragmentManager + * @param titles Tab */ public FragmentPagerAdapter(FragmentManager fm, List titles) { this(fm, titles, null); } + /** + * @param fm FragmentManager + * @param titles Tab + * @param fragments 滑动的Fragment集合 + */ public FragmentPagerAdapter(FragmentManager fm, List titles, List fragments) { super(fm); this.titles = titles; @@ -43,18 +54,20 @@ public int getCount() { } + @NotNull @Override public Fragment getItem(int position) { - BaseFragment fragment; + Log.e("调用了Fragment", "postion:" + position); + BaseFragment fragment = null; if (fragments == null || fragments.isEmpty()) { fragment = getTabFragment(); } else { fragment = fragments.get(position); } if (fragment == null) { - throw new NullPointerException("Fragment is null,please give me a fragment!"); + throw new NullPointerException("Switch Fragment can not be empty!"); } - fragment.setFragmentData(titles.get(position)); + fragment.setTabTitle(titles.get(position)); return fragment; } @@ -63,10 +76,6 @@ public int getItemPosition(@NonNull Object object) { return POSITION_NONE; } - @Override - public void startUpdate(ViewGroup container) { - super.startUpdate(container); - } @Override public CharSequence getPageTitle(int position) { @@ -75,8 +84,11 @@ public CharSequence getPageTitle(int position) { /** * 使用两参构造方法 必须重写 该方法 返回对应的Fragment + * + * @return BaseFragment */ public BaseFragment getTabFragment() { return null; } + } diff --git a/common_base/src/main/java/com/wss/common/base/ActionBarActivity.java b/common_base/src/main/java/com/wss/common/base/ActionBarActivity.java deleted file mode 100644 index 1c291db..0000000 --- a/common_base/src/main/java/com/wss/common/base/ActionBarActivity.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.wss.common.base; - -import android.os.Bundle; -import android.support.annotation.Nullable; - -import com.wss.common.base.mvp.BasePresenter; -import com.wss.common.widget.ActionBar; - -/** - * Describe:所有带actionBar的Activity基类 - * Created by 吴天强 on 2018/10/18. - */ - -public abstract class ActionBarActivity

extends BaseMvpActivity

{ - - // @BindView(R2.id.actionbar) - protected ActionBar actionBar; - - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - actionBar = findViewById(R.id.actionbar); - } - - protected void setTitleText(String title) { - if (actionBar != null) { - actionBar.setCenterText(title); - } - } - - protected void setTitleText(int title) { - if (actionBar != null) { - actionBar.setCenterText(getString(title)); - } - } - - @Override - protected boolean isActionBar() { - return true; - } -} diff --git a/common_base/src/main/java/com/wss/common/base/BaseActionBarActivity.java b/common_base/src/main/java/com/wss/common/base/BaseActionBarActivity.java new file mode 100644 index 0000000..5f2e01f --- /dev/null +++ b/common_base/src/main/java/com/wss/common/base/BaseActionBarActivity.java @@ -0,0 +1,240 @@ +package com.wss.common.base; + +import android.os.Bundle; +import android.view.View; + +import com.wss.common.base.mvp.BasePresenter; +import com.wss.common.widget.ActionBar; + +import androidx.annotation.Nullable; +import butterknife.BindView; + +/** + * Describe:所有带actionBar的Activity基类 + * Created by 吴天强 on 2018/10/18. + */ +public abstract class BaseActionBarActivity

extends BaseMvpActivity

{ + + @BindView(R2.id.actionbar) + ActionBar actionBar; + + @BindView(R2.id.action_bar_line) + View actionBarLine; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + actionBar.setVisibility(View.VISIBLE); + //沉浸式状态栏 + setImmersionBarColor(R.color.white); + } + + + /** + * 设置左边文字 + * + * @param text 文字 + */ + protected void setLeftText(String text) { + setLeftText(text, null); + } + + /** + * @param text 文字 + * @param listener 事件监听 + */ + protected void setLeftText(String text, View.OnClickListener listener) { + setLeftText(text, R.color.color_333333, listener); + } + + /** + * 设置左边文字 + * + * @param text 文字 + * @param textColor 文字颜色 + * @param listener 事件监听 + */ + protected void setLeftText(String text, int textColor, View.OnClickListener listener) { + if (actionBar != null) { + if (textColor != 0) { + actionBar.setLeftTextColor(getResources().getColor(textColor)); + } + actionBar.setLeftText(text, listener); + } + } + + /** + * 设置左边icon + * + * @param drawable icon resId + * @param listener 事件监听 + */ + protected void setLeftIcon(int drawable, View.OnClickListener listener) { + if (actionBar != null) { + actionBar.setLeftIcon(drawable, listener); + } + } + + /** + * 设置左边icon + * + * @param listener 事件监听 + */ + protected void setLeftIcon(View.OnClickListener listener) { + setLeftIcon(R.drawable.ic_back_black, listener); + } + + /** + * 设置左边View + * + * @param view view + */ + protected void setLeftView(View view) { + if (actionBar != null) { + actionBar.setLeftView(view); + } + } + + /** + * 设置中间文字 + * + * @param text text + */ + protected void setCenterText(int text) { + setCenterText(getString(text)); + } + + /** + * 设置中间文字 + * + * @param text text + */ + protected void setCenterText(String text) { + setCenterText(text, R.color.color_333333); + } + + /** + * 设置中间文字 + * + * @param text text + * @param textColor 文字颜色 + */ + protected void setCenterText(String text, int textColor) { + setCenterText(text, textColor, null); + } + + /** + * 设置中间文字 + * + * @param text text + * @param textColor 文字颜色 + * @param listener 事件监听 + */ + protected void setCenterText(String text, int textColor, View.OnClickListener listener) { + if (actionBar != null) { + if (textColor != 0) { + actionBar.setCenterTextColor(textColor); + } + //加粗 + actionBar.setCenterTextBold(true); + actionBar.setCenterText(text, listener); + } + } + + /** + * 设置中间View + * + * @param view view + */ + protected void setCenterView(View view) { + if (actionBar != null) { + actionBar.setCenterView(view); + } + } + + /** + * 设置右边文字 + * + * @param resId 文字 + * @param listener 事件监听 + */ + protected void setRightText(int resId, View.OnClickListener listener) { + setRightText(getString(resId), listener); + } + + /** + * 设置右边文字 + * + * @param text 文字 + * @param listener 事件监听 + */ + protected void setRightText(String text, View.OnClickListener listener) { + setRightText(text, R.color.color_333333, listener); + } + + /** + * 设置右边文字 + * + * @param text 文字 + * @param textColor 文字颜色 + * @param listener 事件监听 + */ + protected void setRightText(String text, int textColor, View.OnClickListener listener) { + if (actionBar != null) { + if (textColor != 0) { + actionBar.setRightTextColor(textColor); + } + actionBar.setRightText(text, listener); + } + } + + /** + * 设置右边icon + * + * @param drawable 图片 + * @param listener 事件监听 + */ + protected void setRightIcon(int drawable, View.OnClickListener listener) { + if (actionBar != null) { + actionBar.setRightIcon(drawable, listener); + } + } + + /** + * 设置右边View + * + * @param view view + */ + protected void setRightView(View view) { + if (actionBar != null) { + actionBar.setRightView(view); + } + } + + /** + * 返回顶部TitleBar + * + * @return ActionBar + */ + protected ActionBar getTitleBar() { + return actionBar; + } + + /** + * 设置ActionBar下面的横线 + * + * @param show 是否显示 + */ + protected void showActionBarLine(boolean show) { + actionBarLine.setVisibility(show ? View.VISIBLE : View.GONE); + } + + /** + * 设置左边返回图标是否显示 + * + * @param show 是否显示 + */ + public void showBackImg(boolean show) { + actionBar.showBackImg(show); + } +} diff --git a/common_base/src/main/java/com/wss/common/base/BaseActivity.java b/common_base/src/main/java/com/wss/common/base/BaseActivity.java index ae77bd4..6a3a911 100644 --- a/common_base/src/main/java/com/wss/common/base/BaseActivity.java +++ b/common_base/src/main/java/com/wss/common/base/BaseActivity.java @@ -1,30 +1,24 @@ package com.wss.common.base; import android.content.Context; -import android.content.Intent; -import android.net.Uri; import android.os.Bundle; -import android.provider.Settings; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.app.FragmentActivity; import android.view.View; import android.view.ViewGroup; import android.view.ViewStub; import android.view.WindowManager; import android.widget.TextView; -import com.gyf.barlibrary.ImmersionBar; -import com.orhanobut.logger.Logger; +import com.gyf.immersionbar.BarHide; +import com.gyf.immersionbar.ImmersionBar; +import com.scwang.smartrefresh.layout.SmartRefreshLayout; import com.wss.common.bean.Event; import com.wss.common.utils.EventBusUtils; -import com.wss.common.widget.dialog.LoadingDialog; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; -import java.util.Arrays; - +import androidx.annotation.Nullable; +import androidx.fragment.app.FragmentActivity; import butterknife.ButterKnife; import butterknife.Unbinder; @@ -32,53 +26,72 @@ * Describe:所有Activity的基类 * Created by 吴天强 on 2018/10/15. */ - public abstract class BaseActivity extends FragmentActivity { - private Unbinder unbinder; private ViewStub emptyView; - protected Context mContext; - protected ImmersionBar mImmersionBar; - protected LoadingDialog loadingDialog; - + protected Context context; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mContext = this; + //加入Activity管理器 + BaseApplication.i().getActivityManage().addActivity(this); + context = this; getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); - if (isActionBar()) { + if (!isFullScreenLayout()) { setContentView(R.layout.activity_base); ((ViewGroup) findViewById(R.id.fl_content)).addView(getLayoutInflater().inflate(getLayoutId(), null)); - } else { - setContentView(getLayoutId()); + unbinder = ButterKnife.bind(this); } - //初始化ButterKnife - unbinder = ButterKnife.bind(this); - - //沉浸式状态栏 - initImmersionBar(R.color.blue); - - //加入Activity管理器 - BaseApplication.getApplication().getActivityManage().addActivity(this); - if (regEvent()) { + if (registerEventBus()) { EventBusUtils.register(this); } - loadingDialog = new LoadingDialog(mContext); + } + /** + * 设置沉浸栏颜色 + * + * @param statusBarColor 颜色 + */ + protected void setImmersionBarColor(int statusBarColor) { + setImmersionBarColor(statusBarColor, false); + } + + /** + * 设置沉浸栏颜色 + * + * @param statusBarColor 沉浸栏颜色 + */ + protected void setImmersionBarColor(int statusBarColor, boolean fitsSystemWindows) { + setImmersionBarColor(statusBarColor, R.color.black, fitsSystemWindows); } /** - * 沉浸栏颜色 + * 设置沉浸栏颜色 + * + * @param statusBarColor 沉浸栏颜色 + * @param navigationBarColor 沉浸栏图标颜色 */ - protected void initImmersionBar(int color) { - mImmersionBar = ImmersionBar.with(this); - if (color != 0) { - mImmersionBar.statusBarColor(color); - } - mImmersionBar.init(); + protected void setImmersionBarColor(int statusBarColor, int navigationBarColor, boolean fitsSystemWindows) { + ImmersionBar.with(this) + .statusBarColor(statusBarColor) + .navigationBarColor(navigationBarColor) + .fitsSystemWindows(fitsSystemWindows) + .autoDarkModeEnable(true) + .statusBarDarkFont(true) + .init(); + } + + /** + * 隐藏状态栏、导航栏 + */ + protected void setImmersionBarHide() { + ImmersionBar.with(this) + .fitsSystemWindows(false) + .hideBar(BarHide.FLAG_HIDE_BAR) + .init(); } @Override @@ -87,15 +100,11 @@ protected void onDestroy() { if (unbinder != null) { unbinder.unbind(); } - if (regEvent()) { + if (registerEventBus()) { EventBusUtils.unregister(this); } - //必须调用该方法,防止内存泄漏 - if (mImmersionBar != null) { - mImmersionBar.destroy(); - } //将Activity从管理器移除 - BaseApplication.getApplication().getActivityManage().removeActivity(this); + BaseApplication.i().getActivityManage().removeActivity(this); } @Override @@ -104,39 +113,65 @@ public void onAttachedToWindow() { initView(); } - //***************************************空页面方法************************************* - protected void showEmptyView(String text) { - showEmptyOrErrorView(text, R.drawable.bg_no_data); - } + //***************************************空页面方法 start************************************* + /** + * 数据为空页面 + */ protected void showEmptyView() { showEmptyView(getString(R.string.no_data)); } - protected void showErrorView(String text) { - showEmptyOrErrorView(text, R.drawable.bg_no_net); + /** + * 数据为空页面 + * + * @param text 显示文案 + */ + protected void showEmptyView(String text) { + showEmptyOrErrorView(text, R.drawable.bg_no_data, false); } + + /** + * 请求数据报错页面 + */ protected void showErrorView() { - showErrorView(getString(R.string.error_data)); + showErrorView(getString(R.string.network_error_server_error)); + } + + /** + * 请求数据报错页面 + * + * @param text 显示文案 + */ + protected void showErrorView(String text) { + showEmptyOrErrorView(text, R.drawable.bg_no_net , true); } - public void showEmptyOrErrorView(String text, int img) { - emptyView = findViewById(R.id.vs_empty); - if (emptyView != null) { - emptyView.setVisibility(View.VISIBLE); - findViewById(R.id.iv_empty).setBackgroundResource(img); - ((TextView) findViewById(R.id.tv_empty)).setText(text); - findViewById(R.id.ll_empty).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - onPageClick(); - } - }); + /** + * 请求数据报错或者为空页面 + * + * @param text 提示文案 + * @param iconResId 显示的icon + */ + public void showEmptyOrErrorView(String text, int iconResId, boolean showRefreshButton) { + if (emptyView == null) { + emptyView = findViewById(R.id.vs_empty); + } + emptyView.setVisibility(View.VISIBLE); + findViewById(R.id.iv_empty).setBackgroundResource(iconResId); + ((TextView) findViewById(R.id.tv_empty)).setText(text); + if (showRefreshButton) { + View refreshButton = findViewById(R.id.tv_try_again); + refreshButton.setVisibility(View.VISIBLE); + refreshButton.setOnClickListener(v -> onRefreshRetry()); } } + /** + * 隐藏空页面 + */ protected void hideEmptyView() { if (emptyView != null) { emptyView.setVisibility(View.GONE); @@ -144,69 +179,64 @@ protected void hideEmptyView() { } /** - * 空页面被点击 + * 刷新重试 */ - protected void onPageClick() { - + protected void onRefreshRetry() { } - //***************************************空页面方法********************************* - - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - Logger.e("permissions:" + Arrays.toString(permissions) + " grantResults:" + Arrays.toString(grantResults)); - - //如果有未授权权限则跳转设置页面 - if (!requestPermissionsResult(grantResults)) { - Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.setData(Uri.parse("package:" + getPackageName())); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - } - - - } + //***************************************空页面方法 end********************************* /** - * 判断授权结果 + * 停止刷新和加载更多 + * + * @param layout 刷新layout */ - private boolean requestPermissionsResult(int[] grantResults) { - for (int code : grantResults) { - if (code == -1) { - return false; - } + protected void stopRefresh(SmartRefreshLayout layout) { + if (layout == null) { + return; } - return true; + layout.finishLoadMore(); + layout.finishRefresh(); } - /** - * 子类接受事件 重写该方法 + * 是否布局伸入状态栏类型Activity + * + * @return boolean */ - @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventBus(Event event) { + protected boolean isFullScreenLayout() { + return false; } /** - * 是否需要ActionBar - * TODO 暂时用此方法 后续优化 + * 需要接收事件 重写该方法 并返回true + * + * @return boolean */ - protected boolean isActionBar() { + protected boolean registerEventBus() { return false; } /** - * 需要接收事件 重写该方法 并返回true + * 子类接受事件 重写该方法 + * + * @param event 事件 */ - protected boolean regEvent() { - return false; + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEventBus(Event event) { } + /** + * 返回页面layout + * + * @return layout + */ protected abstract int getLayoutId(); + /** + * 初始化View + */ protected abstract void initView(); } diff --git a/common_base/src/main/java/com/wss/common/base/BaseApplication.java b/common_base/src/main/java/com/wss/common/base/BaseApplication.java index c6992a3..2e64d20 100644 --- a/common_base/src/main/java/com/wss/common/base/BaseApplication.java +++ b/common_base/src/main/java/com/wss/common/base/BaseApplication.java @@ -2,7 +2,7 @@ import android.app.Application; import android.content.Context; -import android.support.multidex.MultiDex; +import android.widget.Toast; import com.alibaba.android.arouter.launcher.ARouter; import com.orhanobut.logger.AndroidLogAdapter; @@ -10,26 +10,67 @@ import com.orhanobut.logger.LogcatLogStrategy; import com.orhanobut.logger.Logger; import com.orhanobut.logger.PrettyFormatStrategy; +import com.scwang.smartrefresh.layout.SmartRefreshLayout; +import com.scwang.smartrefresh.layout.footer.ClassicsFooter; +import com.scwang.smartrefresh.layout.header.ClassicsHeader; +import com.wss.common.bean.User; +import com.wss.common.constants.Constants; +import com.wss.common.constants.Dic; import com.wss.common.manage.ActivityManage; -import com.wss.common.manage.CrashHandlerManage; +import com.wss.common.utils.CacheUtils; +import com.wss.common.utils.ToastUtils; +import com.wss.common.utils.ValidUtils; +import com.wss.common.utils.toast.ToastInterceptor; +import com.wss.common.utils.toast.style.ToastBlackStyle; + +import org.jetbrains.annotations.Contract; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.X509TrustManager; + +import androidx.multidex.MultiDex; +import io.reactivex.disposables.Disposable; +import io.reactivex.plugins.RxJavaPlugins; +import okhttp3.ConnectionSpec; +import okhttp3.OkHttpClient; +import rxhttp.HttpSender; +import rxhttp.wrapper.ssl.SSLSocketFactoryImpl; +import rxhttp.wrapper.ssl.X509TrustManagerImpl; /** * Describe:基础Application所有需要模块化开发的module都需要继承自BaseApplication * Created by 吴天强 on 2018/10/12. */ public class BaseApplication extends Application { - - //全局唯一的context + /** + * 全局上下文 + */ private static BaseApplication application; - - //Activity管理器 + /** + * Activity管理器 + */ private ActivityManage activityManage; + /** + * 保存所有网络请求 + */ + private Map netDisposable; + + /** + * 登录用户 + */ + private User user; + @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); application = this; - //MultiDex分包方法 必须最先初始化 + //MultiDex分包方法 初始化 MultiDex.install(this); } @@ -37,37 +78,98 @@ protected void attachBaseContext(Context base) { public void onCreate() { super.onCreate(); activityManage = new ActivityManage(); - initARouter(); + //初始化日志框架 initLogger(); - initCrashManage(); + //初始化ARouter + initARouter(); + //初始化Toast + initToast(); + //初始化网络框架 + initRXHttp(); + //刷新框架 + initRefreshLayout(); } /** - * 初始化崩溃管理器 + * 初始化刷新框架 */ - private void initCrashManage() { - if (!BuildConfig.DEBUG) { - CrashHandlerManage.getInstance() - .init(getApplicationContext()); - } + private void initRefreshLayout() { + //设置全局的Header构建器 + SmartRefreshLayout.setDefaultRefreshHeaderCreator((context, layout) -> { + //指定为经典Footer,默认是 BezierRadarHeader + return new ClassicsHeader(context); + }); + //设置全局的Footer构建器 + SmartRefreshLayout.setDefaultRefreshFooterCreator((context, layout) -> { + //指定为经典Footer,默认是 BallPulseFooter + return new ClassicsFooter(context).setDrawableSize(20); + }); } + /** + * B + * 初始化Toast + */ + private void initToast() { + ToastUtils.setToastInterceptor(new ToastInterceptor() { + @Override + public boolean intercept(Toast toast, CharSequence text) { + boolean intercept = super.intercept(toast, text); + if (intercept) { + Logger.e("空 Toast"); + } else { + Logger.d(text.toString()); + } + return intercept; + } + }); + // 初始化吐司工具类 + ToastUtils.init(this, new ToastBlackStyle(this)); + } + + /** + * 初始化网络请求 + */ + private void initRXHttp() { + X509TrustManager trustManager = new X509TrustManagerImpl(); + SSLSocketFactory sslSocketFactory = new SSLSocketFactoryImpl(trustManager); + HttpSender.setDebug(BuildConfig.DEBUG); + HttpSender.init(new OkHttpClient.Builder() + .connectTimeout(Constants.Net.TIME_OUT, TimeUnit.SECONDS) + .readTimeout(Constants.Net.TIME_OUT, TimeUnit.SECONDS) + .writeTimeout(Constants.Net.TIME_OUT, TimeUnit.SECONDS) + .connectionSpecs(Arrays.asList(ConnectionSpec.COMPATIBLE_TLS, ConnectionSpec.CLEARTEXT)) + //添加信任证书 + .sslSocketFactory(sslSocketFactory, trustManager) + //忽略Host验证 + .hostnameVerifier(((hostname, session) -> true)) + .build()); + RxJavaPlugins.setErrorHandler(throwable -> { + //Rx全局异常处理 + }); + } /** * 初始化日志打印框架 */ private void initLogger() { FormatStrategy formatStrategy = PrettyFormatStrategy.newBuilder() - .showThreadInfo(false) //(可选)是否显示线程信息。 默认值为true - .methodCount(2) //(可选)要显示的方法行数。 默认2 - .methodOffset(7) //(可选)设置调用堆栈的函数偏移值,0的话则从打印该Log的函数开始输出堆栈信息,默认是0 - .logStrategy(new LogcatLogStrategy()) //(可选)更改要打印的日志策略。 默认LogCat - .tag("AMD") //(可选)每个日志的全局标记。 默认PRETTY_LOGGER + //(可选)是否显示线程信息。 默认值为true + .showThreadInfo(false) + //(可选)要显示的方法行数。 默认2 + .methodCount(0) + //(可选)设置调用堆栈的函数偏移值,0的话则从打印该Log的函数开始输出堆栈信息,默认是0 + .methodOffset(7) + //(可选)更改要打印的日志策略。 默认LogCat + .logStrategy(new LogcatLogStrategy()) + //(可选)每个日志的全局标记。 默认PRETTY_LOGGER + .tag("APP_LOG") .build(); + Logger.addLogAdapter(new AndroidLogAdapter(formatStrategy) { @Override public boolean isLoggable(int priority, String tag) { - //DEBUG模式下不打印LOG + //非DEBUG模式下不打印LOG return BuildConfig.DEBUG; } }); @@ -78,10 +180,12 @@ public boolean isLoggable(int priority, String tag) { */ private void initARouter() { if (BuildConfig.DEBUG) { - ARouter.openLog(); // 打印日志 - ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险) + // 打印日志 + ARouter.openLog(); + // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险) + ARouter.openDebug(); } - ARouter.init(application);// 尽可能早,推荐在Application中初始化 + ARouter.init(application); } /** @@ -98,7 +202,8 @@ public void onTerminate() { * * @return BaseApplication */ - public static BaseApplication getApplication() { + @Contract(pure = true) + public static BaseApplication i() { return application; } @@ -113,7 +218,9 @@ public void exitApp() { } /** - * 返回Activity管理器 + * 获取Activity管理器 + * + * @return ActivityManage */ public ActivityManage getActivityManage() { if (activityManage == null) { @@ -122,5 +229,90 @@ public ActivityManage getActivityManage() { return activityManage; } + /** + * 获取存放的请求对象 + * + * @return Map + */ + public Map getNetDisposables() { + if (netDisposable == null) { + return new HashMap<>(16); + } + return netDisposable; + } + + /** + * 退出登录清除换群 + */ + public void loginOutClean() { + + } + + /** + * 添加请求对象 + * + * @param requestId 请求ID + * @param disposable 对象 + */ + public void addNetDisposable(String requestId, Disposable disposable) { + if (netDisposable == null) { + netDisposable = new HashMap<>(16); + } + netDisposable.put(requestId, disposable); + } + + /** + * 根据请求ID移除该对象 + * + * @param requestId 请求ID + */ + public void removeNetDisposable(String requestId) { + netDisposable.remove(requestId); + } + + /** + * 保存用户信息 + * + * @param user 登录用户 + */ + public void setUser(User user) { + CacheUtils.get(this).put(Dic.LOGIN_USER_INFO, user); + this.user = user; + } + + /** + * 获取用户信息 + * + * @return User + */ + public User getUser() { + if (!ValidUtils.isValid(user) || !ValidUtils.isValid(user.getId())) { + //如果保存的user为空,则去本地缓存中取 + user = (User) CacheUtils.get(this).getAsObject(Dic.LOGIN_USER_INFO); + } + if (!ValidUtils.isValid(user)) { + //防止异常情况下getUser对象为null问题 + user = new User(); + } + return user; + } + /** + * 是否登录 + * + * @return boolean + */ + public boolean isLogged() { + User user = getUser(); + return ValidUtils.isValid(user) && ValidUtils.isValid(user.getId()); + } + + + public String getDeviceId() { + return ""; + } + + public String getLoginToken() { + return ""; + } } \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/base/BaseFragment.java b/common_base/src/main/java/com/wss/common/base/BaseFragment.java index edc3de2..e463b3a 100644 --- a/common_base/src/main/java/com/wss/common/base/BaseFragment.java +++ b/common_base/src/main/java/com/wss/common/base/BaseFragment.java @@ -2,23 +2,24 @@ import android.content.Context; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewStub; import android.widget.TextView; +import com.scwang.smartrefresh.layout.SmartRefreshLayout; import com.wss.common.bean.Event; import com.wss.common.bean.HorizontalTabTitle; -import com.wss.common.widget.dialog.LoadingDialog; +import com.wss.common.utils.ValidUtils; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; import butterknife.ButterKnife; import butterknife.Unbinder; @@ -26,35 +27,36 @@ * Describe:所有Fragment的基类 * Created by 吴天强 on 2018/10/17. */ - public abstract class BaseFragment extends Fragment { + protected Context context; private ViewStub emptyView; private View rootView; private Unbinder unBinder; - protected Context mContext; - protected LoadingDialog loadingDialog; - + private HorizontalTabTitle tabTitle; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mContext = getActivity(); - loadingDialog = new LoadingDialog(mContext); + context = getActivity(); } + @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - rootView = inflater.inflate(R.layout.fragment_base, container, false); + rootView = inflater.inflate(R.layout.layout_base, container, false); ((ViewGroup) rootView.findViewById(R.id.fl_content)).addView(getLayoutInflater().inflate(getLayoutId(), null)); unBinder = ButterKnife.bind(this, rootView); - if (regEvent()) { - EventBus.getDefault().register(this); + if (registerEventBus()) { + if (!EventBus.getDefault().isRegistered(this)) { + EventBus.getDefault().register(this); + } } return rootView; } + @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); initView(); @@ -67,38 +69,73 @@ public void onDestroy() { if (unBinder != null) { unBinder.unbind(); } - if (regEvent()) { + if (registerEventBus()) { EventBus.getDefault().unregister(this); } } - //***************************************空页面方法************************************* + //***************************************空页面方法 start ************************************* + + /** + * 数据为空页面 + */ protected void showEmptyView() { - showEmptyOrErrorView(getString(R.string.no_data), R.drawable.bg_no_data); + showEmptyView(getString(R.string.no_data)); + } + + /** + * 数据为空页面 + * + * @param text 显示文案 + */ + protected void showEmptyView(String text) { + showEmptyOrErrorView(text, R.drawable.bg_no_data, false); } + /** + * 请求数据报错页面 + */ protected void showErrorView() { - showEmptyOrErrorView(getString(R.string.error_data), R.drawable.bg_no_net); + showErrorView(getString(R.string.network_error_server_error)); + } + + /** + * 请求数据报错页面 + * + * @param text 显示文案 + */ + protected void showErrorView(String text) { + showEmptyOrErrorView(text, R.drawable.bg_no_net, true); } - public void showEmptyOrErrorView(String text, int img) { - emptyView = rootView.findViewById(R.id.vs_empty); - if (emptyView != null) { - emptyView.setVisibility(View.VISIBLE); - rootView.findViewById(R.id.iv_empty).setBackgroundResource(img); - ((TextView) rootView.findViewById(R.id.tv_empty)).setText(text); - rootView.findViewById(R.id.ll_empty).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - onPageClick(); - } - }); + /** + * 请求数据报错或者为空页面 + * + * @param text 提示文案 + * @param iconResId 显示的icon + */ + public void showEmptyOrErrorView(String text, int iconResId, boolean showRefreshButton) { + if (emptyView == null) { + emptyView = rootView.findViewById(R.id.vs_empty); + } + emptyView.setVisibility(View.VISIBLE); + rootView.findViewById(R.id.iv_empty).setBackgroundResource(iconResId); + ((TextView) rootView.findViewById(R.id.tv_empty)).setText(text); + View refreshButton = rootView.findViewById(R.id.tv_try_again); + if (showRefreshButton) { + refreshButton.setVisibility(View.VISIBLE); + refreshButton.setOnClickListener(v -> onRefreshRetry()); + } else { + refreshButton.setVisibility(View.GONE); } } + /** + * 隐藏空页面 + */ protected void hideEmptyView() { if (emptyView != null) { emptyView.setVisibility(View.GONE); @@ -106,20 +143,52 @@ protected void hideEmptyView() { } /** - * 空页面被点击 + * 刷新重试 */ - protected void onPageClick() { + protected void onRefreshRetry() { + } + + //***************************************空页面方法 end********************************* + /** + * 停止刷新和加载更多 + * + * @param layout 刷新layout + */ + protected void stopRefresh(SmartRefreshLayout layout) { + if (layout == null) { + return; + } + layout.finishLoadMore(); + layout.finishRefresh(); } - //***************************************空页面方法********************************* + /** + * 返回Fragment的根布局 + * + * @return View + */ + protected View getRootView() { + return rootView; + } /** - * 给Fragment设置数据 + * 给Fragment设置TabTile数据 + * + * @param data tabtitle */ - public void setFragmentData(HorizontalTabTitle data) { + public void setTabTitle(HorizontalTabTitle data) { + this.tabTitle = data; + } + /** + * 返回ViewPager+Fragment滑动 设置给子Fragment的Tab数据 + * + * @return HorizontalTabTitle + */ + public HorizontalTabTitle getTabTitle() { + return ValidUtils.isValid(tabTitle) ? tabTitle : new HorizontalTabTitle(""); } /** @@ -132,13 +201,20 @@ public void onEventBus(Event event) { /** * 需要接收事件 重新该方法 并返回true */ - protected boolean regEvent() { + protected boolean registerEventBus() { return false; } - + /** + * 返回页面layout + * + * @return layout + */ protected abstract int getLayoutId(); + /** + * 初始化View + */ protected abstract void initView(); } diff --git a/common_base/src/main/java/com/wss/common/base/BaseFullScreenActivity.java b/common_base/src/main/java/com/wss/common/base/BaseFullScreenActivity.java new file mode 100644 index 0000000..b6df48f --- /dev/null +++ b/common_base/src/main/java/com/wss/common/base/BaseFullScreenActivity.java @@ -0,0 +1,34 @@ +package com.wss.common.base; + + +import com.gyf.immersionbar.ImmersionBar; +import com.wss.common.base.mvp.BasePresenter; + +/** + * Describe:布局需要伸入状态栏下面的Activity继承该类, + * 并通过setContentView来设置layout,重新注册ButterKnife + * Created by 吴天强 on 2020/4/28. + */ +public abstract class BaseFullScreenActivity

extends BaseMvpActivity

{ + + @Override + protected boolean isFullScreenLayout() { + return true; + } + + @Override + protected int getLayoutId() { + //该方法仅仅是为了实现父类的抽象方法,无任何意义,忽略即可 + return R.layout.layout_nothing; + } + + @Override + protected void initView() { + //布局可伸入状态栏 + ImmersionBar.with(this) + .statusBarColor(R.color.transparent) + .statusBarDarkFont(true) + .fullScreen(true) + .init(); + } +} diff --git a/common_base/src/main/java/com/wss/common/base/HorizontalTabActivity.java b/common_base/src/main/java/com/wss/common/base/BaseHorizontalTabActivity.java similarity index 71% rename from common_base/src/main/java/com/wss/common/base/HorizontalTabActivity.java rename to common_base/src/main/java/com/wss/common/base/BaseHorizontalTabActivity.java index e528b05..a1ab86f 100644 --- a/common_base/src/main/java/com/wss/common/base/HorizontalTabActivity.java +++ b/common_base/src/main/java/com/wss/common/base/BaseHorizontalTabActivity.java @@ -1,7 +1,5 @@ package com.wss.common.base; -import android.support.annotation.CallSuper; -import android.support.v4.view.ViewPager; import com.wss.common.adapter.FragmentPagerAdapter; import com.wss.common.base.mvp.BasePresenter; @@ -10,15 +8,15 @@ import java.util.List; +import androidx.annotation.CallSuper; +import androidx.viewpager.widget.ViewPager; import butterknife.BindView; /** * Describe:带水平选项卡的Activity * Created by 吴天强 on 2018/10/22. */ - -public abstract class HorizontalTabActivity

extends ActionBarActivity

{ - +public abstract class BaseHorizontalTabActivity

extends BaseActionBarActivity

{ @BindView(R2.id.pst_tab) PagerSlidingTabStrip tabStrip; @@ -38,15 +36,24 @@ protected void initView() { viewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager(), getTabTitles()) { @Override public BaseFragment getTabFragment() { - return HorizontalTabActivity.this.getTabFragment(); + return BaseHorizontalTabActivity.this.getTabFragment(); } }); tabStrip.setViewPager(viewPager); } + /** + * 选项卡List + * + * @return List + */ protected abstract List getTabTitles(); + /** + * 滑动Fragment + * + * @return BaseFragment + */ protected abstract BaseFragment getTabFragment(); - } diff --git a/common_base/src/main/java/com/wss/common/base/BaseMvpActivity.java b/common_base/src/main/java/com/wss/common/base/BaseMvpActivity.java index 826b881..df294f2 100644 --- a/common_base/src/main/java/com/wss/common/base/BaseMvpActivity.java +++ b/common_base/src/main/java/com/wss/common/base/BaseMvpActivity.java @@ -2,25 +2,30 @@ import android.content.Context; import android.os.Bundle; -import android.support.annotation.Nullable; +import android.text.TextUtils; import com.wss.common.base.mvp.BasePresenter; import com.wss.common.base.mvp.IBaseView; +import com.wss.common.widget.dialog.LoadingDialog; + +import androidx.annotation.Nullable; +import androidx.lifecycle.LifecycleOwner; /** * Describe:所有需要Mvp开发的Activity的基类 * Created by 吴天强 on 2018/10/15. */ - +@SuppressWarnings("unchecked") public abstract class BaseMvpActivity

extends BaseActivity implements IBaseView { - protected P presenter; - + private P presenter; + private LoadingDialog loadingDialog; - @SuppressWarnings("unchecked") @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + loadingDialog = new LoadingDialog(context); + loadingDialog.setCancelable(loadingCancelable()); //创建present presenter = createPresenter(); if (presenter != null) { @@ -35,16 +40,38 @@ protected void onDestroy() { presenter.detachView(); presenter = null; } + } + /** + * 返回Presenter + * + * @return P + */ + protected P getPresenter() { + return presenter; } - //***************************************IBaseView方法实现************************************* + //***************************************IBaseView方法实现 start************************************* + @Override public void showLoading() { + showLoading(""); + } + + /** + * 显示加载框 + * + * @param msg 加载框文字 + */ + public void showLoading(String msg) { if (loadingDialog != null && !loadingDialog.isShowing()) { + if (!TextUtils.isEmpty(msg)) { + loadingDialog.setTitleText(msg); + } loadingDialog.show(); } + hideEmptyView(); } @Override @@ -54,24 +81,41 @@ public void dismissLoading() { } } + /** + * 加载框是否可以取消 + * + * @return boolean + */ + protected boolean loadingCancelable() { + return true; + } + + @Override public void onEmpty(Object tag) { - + dismissLoading(); } @Override public void onError(Object tag, String errorMsg) { + dismissLoading(); + } + @Override + public LifecycleOwner getLifecycleOwner() { + return this; } @Override public Context getContext() { - return mContext; + return context; } - //***************************************IBaseView方法实现************************************* + //********************************x*******IBaseView方法实现 end************************************* /** * 创建Presenter + * + * @return Presenter */ protected abstract P createPresenter(); } diff --git a/common_base/src/main/java/com/wss/common/base/BaseMvpFragment.java b/common_base/src/main/java/com/wss/common/base/BaseMvpFragment.java index 4d7ff26..dc4ec42 100644 --- a/common_base/src/main/java/com/wss/common/base/BaseMvpFragment.java +++ b/common_base/src/main/java/com/wss/common/base/BaseMvpFragment.java @@ -1,25 +1,30 @@ package com.wss.common.base; + import android.os.Bundle; -import android.support.annotation.Nullable; import com.wss.common.base.mvp.BasePresenter; import com.wss.common.base.mvp.IBaseView; +import com.wss.common.widget.dialog.LoadingDialog; + +import androidx.annotation.Nullable; +import androidx.lifecycle.LifecycleOwner; /** * Describe:所有需要Mvp开发的Fragment的基类 * Created by 吴天强 on 2018/10/17. */ - +@SuppressWarnings("unchecked") public abstract class BaseMvpFragment

extends BaseFragment implements IBaseView { - protected P presenter; - + private P presenter; + private LoadingDialog loadingDialog; - @SuppressWarnings("unchecked") @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + loadingDialog = new LoadingDialog(context); + loadingDialog.setCancelable(loadingCancelable()); //创建present presenter = createPresenter(); if (presenter != null) { @@ -33,16 +38,26 @@ public void onDestroy() { if (presenter != null) { presenter.detachView(); } + } + /** + * 返回presenter + * + * @return P + */ + protected P getPresenter() { + return presenter; } + //***************************************IBaseView方法实现 start ************************************* + - //***************************************IBaseView方法实现************************************* @Override public void showLoading() { if (loadingDialog != null && !loadingDialog.isShowing()) { loadingDialog.show(); } + hideEmptyView(); } @Override @@ -52,19 +67,36 @@ public void dismissLoading() { } } + /** + * 加载框是否可以取消 + * + * @return boolean + */ + protected boolean loadingCancelable() { + return true; + } + @Override public void onEmpty(Object tag) { - + dismissLoading(); } @Override public void onError(Object tag, String errorMsg) { + dismissLoading(); + } + @Override + public LifecycleOwner getLifecycleOwner() { + return this; } - //***************************************IBaseView方法实现************************************* + + //***************************************IBaseView方法实现 end************************************* /** * 创建Presenter + * + * @return Presenter */ protected abstract P createPresenter(); } diff --git a/common_base/src/main/java/com/wss/common/base/BaseRefreshListActivity.java b/common_base/src/main/java/com/wss/common/base/BaseRefreshListActivity.java new file mode 100644 index 0000000..0769b17 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/base/BaseRefreshListActivity.java @@ -0,0 +1,114 @@ +package com.wss.common.base; + +import com.scwang.smartrefresh.layout.SmartRefreshLayout; +import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener; +import com.wss.common.base.mvp.BasePresenter; + +import androidx.annotation.CallSuper; +import androidx.recyclerview.widget.RecyclerView; +import butterknife.BindView; + +/** + * Describe:带下拉刷新 上拉加载更多的Activity + * 内部实现为刷新控件 SmartRefreshLayout + 列表控件 RecyclerView + * Created by 吴天强 on 2018/10/23. + */ +public abstract class BaseRefreshListActivity

extends BaseActionBarActivity

{ + + @BindView(R2.id.ptrl_list) + SmartRefreshLayout refreshLayout; + + @BindView(R2.id.recycle_view) + RecyclerView recyclerView; + + /** + * 适配器 + */ + private RecyclerView.Adapter adapter; + + @Override + protected int getLayoutId() { + return R.layout.layout_refresh; + } + + @CallSuper + @Override + protected void initView() { + adapter = createAdapter(); + refreshLayout.setOnRefreshLoadMoreListener(createRefreshListener()); + recyclerView.setLayoutManager(getLayoutManager()); + recyclerView.setAdapter(adapter); + + } + + @CallSuper + @Override + public void dismissLoading() { + super.dismissLoading(); + stopRefresh(); + } + + + @CallSuper + @Override + public void showLoading() { + super.showLoading(); + hideEmptyView(); + } + + /** + * 停止刷新 + */ + protected void stopRefresh() { + refreshLayout.finishRefresh(); + refreshLayout.finishLoadMore(); + } + + /** + * 获取刷新控件 + * + * @return PullToRefreshLayout + */ + protected SmartRefreshLayout getRefreshLayout() { + return refreshLayout; + } + + /** + * 获取加载数据列表控件 + * + * @return RecyclerView + */ + protected RecyclerView getRecyclerView() { + return recyclerView; + } + + /** + * 返回适配器 + * + * @return RecyclerView.Adapter + */ + protected RecyclerView.Adapter getAdapter() { + return adapter; + } + + /** + * 创建 RecyclerView LayoutManager + * + * @return RecyclerView.LayoutManager + */ + protected abstract RecyclerView.LayoutManager getLayoutManager(); + + /** + * 创建刷新监听器 + * + * @return OnPullRefreshListener + */ + protected abstract OnRefreshLoadMoreListener createRefreshListener(); + + /** + * 创建列表适配器 + * + * @return RecyclerView.Adapter + */ + protected abstract RecyclerView.Adapter createAdapter(); +} diff --git a/common_base/src/main/java/com/wss/common/base/BaseRefreshListFragment.java b/common_base/src/main/java/com/wss/common/base/BaseRefreshListFragment.java new file mode 100644 index 0000000..a7d45c0 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/base/BaseRefreshListFragment.java @@ -0,0 +1,112 @@ +package com.wss.common.base; + + +import com.scwang.smartrefresh.layout.SmartRefreshLayout; +import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener; +import com.wss.common.base.mvp.BasePresenter; + +import androidx.annotation.CallSuper; +import androidx.recyclerview.widget.RecyclerView; +import butterknife.BindView; + +/** + * Describe:带下拉刷新 上拉加载更多的Fragment + * 内部实现为刷新控件 SmartRefreshLayout + 列表控件 RecyclerView + * Created by 吴天强 on 2018/10/23. + */ +public abstract class BaseRefreshListFragment

extends BaseMvpFragment

{ + + @BindView(R2.id.ptrl_list) + SmartRefreshLayout refreshLayout; + + @BindView(R2.id.recycle_view) + RecyclerView recyclerView; + /** + * 适配器 + */ + private RecyclerView.Adapter adapter; + + @Override + protected int getLayoutId() { + return R.layout.layout_refresh; + } + + @CallSuper + @Override + protected void initView() { + adapter = createAdapter(); + refreshLayout.setOnRefreshLoadMoreListener(createRefreshListener()); + recyclerView.setLayoutManager(getLayoutManager()); + recyclerView.setAdapter(adapter); + } + + @CallSuper + @Override + public void dismissLoading() { + super.dismissLoading(); + stopRefresh(); + } + + @CallSuper + @Override + public void showLoading() { + super.showLoading(); + hideEmptyView(); + } + + /** + * 停止刷新 + */ + protected void stopRefresh() { + refreshLayout.finishRefresh(); + refreshLayout.finishLoadMore(); + } + + /** + * 获取刷新控件 + * + * @return PullToRefreshLayout + */ + protected SmartRefreshLayout getRefreshLayout() { + return refreshLayout; + } + + /** + * 获取加载数据列表控件 + * + * @return RecyclerView + */ + protected RecyclerView getRecyclerView() { + return recyclerView; + } + + /** + * 返回适配器 + * + * @return RecyclerView.Adapter + */ + protected RecyclerView.Adapter getAdapter() { + return adapter; + } + + /** + * 创建 RecyclerView LayoutManager + * + * @return RecyclerView.LayoutManager + */ + protected abstract RecyclerView.LayoutManager getLayoutManager(); + + /** + * 创建刷新监听器 + * + * @return OnPullRefreshListener + */ + protected abstract OnRefreshLoadMoreListener createRefreshListener(); + + /** + * 创建列表适配器 + * + * @return RecyclerView.Adapter + */ + protected abstract RecyclerView.Adapter createAdapter(); +} diff --git a/common_base/src/main/java/com/wss/common/base/RefreshListActivity.java b/common_base/src/main/java/com/wss/common/base/RefreshListActivity.java deleted file mode 100644 index eb896d4..0000000 --- a/common_base/src/main/java/com/wss/common/base/RefreshListActivity.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.wss.common.base; - -import android.support.annotation.CallSuper; -import android.support.v7.widget.RecyclerView; - -import com.wss.common.base.mvp.BasePresenter; -import com.wss.common.listener.OnListItemClickListener; -import com.wss.common.widget.pulltorefresh.OnPullRefreshListener; -import com.wss.common.widget.pulltorefresh.PullToRefreshLayout; - -import butterknife.BindView; - -/** - * Describe:带下拉刷新 上拉加载更多的Activity - * 内部实现为刷新控件 PullToRefreshLayout + 列表控件 RecyclerView - * Created by 吴天强 on 2018/10/23. - */ -public abstract class RefreshListActivity

extends ActionBarActivity

implements OnPullRefreshListener, OnListItemClickListener { - - @BindView(R2.id.ptrl_list) - PullToRefreshLayout refreshLayout; - - @BindView(R2.id.recycle_view) - RecyclerView recyclerView; - - protected RecyclerView.Adapter adapter; - - - @Override - protected int getLayoutId() { - return R.layout.layout_refresh; - } - - @CallSuper - @Override - protected void initView() { - refreshLayout.setOnPullRefreshListener(this); - recyclerView.setLayoutManager(getLayoutManager()); - adapter = createAdapter(); - recyclerView.setAdapter(adapter); - } - - @CallSuper - @Override - public void dismissLoading() { - super.dismissLoading(); - stopRefresh(); - } - - - @CallSuper - @Override - public void showLoading() { - super.showLoading(); - hideEmptyView(); - } - - /** - * 停止刷新 - */ - protected void stopRefresh() { - refreshLayout.finishRefresh(); - refreshLayout.finishLoadMore(); - } - - protected PullToRefreshLayout getRefreshLayout() { - return refreshLayout; - } - - protected RecyclerView getRecyclerView() { - return recyclerView; - } - - protected abstract RecyclerView.LayoutManager getLayoutManager(); - - protected abstract RecyclerView.Adapter createAdapter(); -} diff --git a/common_base/src/main/java/com/wss/common/base/RefreshListFragment.java b/common_base/src/main/java/com/wss/common/base/RefreshListFragment.java deleted file mode 100644 index 0193be3..0000000 --- a/common_base/src/main/java/com/wss/common/base/RefreshListFragment.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.wss.common.base; - -import android.support.annotation.CallSuper; -import android.support.v7.widget.RecyclerView; - -import com.wss.common.listener.OnListItemClickListener; -import com.wss.common.base.mvp.BasePresenter; -import com.wss.common.widget.pulltorefresh.OnPullRefreshListener; -import com.wss.common.widget.pulltorefresh.PullToRefreshLayout; - -import butterknife.BindView; - -/** - * Describe:带下拉刷新 上拉加载更多的Fragment - * 内部实现为刷新控件 PullToRefreshLayout + 列表控件 RecyclerView - * Created by 吴天强 on 2018/10/23. - */ -public abstract class RefreshListFragment

extends BaseMvpFragment

implements OnPullRefreshListener, OnListItemClickListener { - - - @BindView(R2.id.ptrl_list) - PullToRefreshLayout refreshLayout; - - @BindView(R2.id.recycle_view) - RecyclerView recyclerView; - - protected RecyclerView.Adapter adapter; - - @Override - protected int getLayoutId() { - return R.layout.layout_refresh; - } - - @CallSuper - @Override - protected void initView() { - adapter = createAdapter(); - refreshLayout.setOnPullRefreshListener(this); - recyclerView.setLayoutManager(getLayoutManager()); - recyclerView.setAdapter(adapter); - } - - @CallSuper - @Override - public void dismissLoading() { - super.dismissLoading(); - stopRefresh(); - } - - @CallSuper - @Override - public void showLoading() { - super.showLoading(); - hideEmptyView(); - } - - /** - * 停止刷新 - */ - protected void stopRefresh() { - refreshLayout.finishRefresh(); - refreshLayout.finishLoadMore(); - - } - - protected RecyclerView getRecyclerView() { - return recyclerView; - } - - protected PullToRefreshLayout getRefreshLayout() { - return refreshLayout; - } - - protected abstract RecyclerView.LayoutManager getLayoutManager(); - - protected abstract RecyclerView.Adapter createAdapter(); -} diff --git a/common_base/src/main/java/com/wss/common/base/adapter/BaseListAdapter.java b/common_base/src/main/java/com/wss/common/base/adapter/BaseListAdapter.java index 9d079af..77cce29 100644 --- a/common_base/src/main/java/com/wss/common/base/adapter/BaseListAdapter.java +++ b/common_base/src/main/java/com/wss/common/base/adapter/BaseListAdapter.java @@ -1,67 +1,71 @@ package com.wss.common.base.adapter; import android.content.Context; -import android.view.View; -import com.wss.common.listener.OnListItemClickListener; +import com.wss.common.base.adapter.listener.OnListItemClickListener; import org.byteam.superadapter.IMulItemViewType; import org.byteam.superadapter.SuperAdapter; import org.byteam.superadapter.SuperViewHolder; +import org.jetbrains.annotations.NotNull; import java.util.List; /** * Describe:万能适配器基类 适用于RecycleView ListView GridView等 - * 注意点:Item的最外层高度不能设置为 match_parent 否则滑动会出现混乱 目前还不知道原因、 + * 注意点:Item的最外层高度不能设置为 match_parent 否则滑动会出现混乱[TODO] * Created by 吴天强 on 2018/10/30. */ - public abstract class BaseListAdapter extends SuperAdapter { /** * Item点击监听 */ - protected OnListItemClickListener listener; + private OnListItemClickListener listener; /** * 常规列表重写该方法 + * + * @param context context + * @param mData 数据源 + * @param layoutResId 布局文件 + * @param listener Item点击回调 */ - public BaseListAdapter(Context context, List items, int layoutResId, OnListItemClickListener listener) { - super(context, items, layoutResId); + public BaseListAdapter(Context context, List mData, int layoutResId, OnListItemClickListener listener) { + super(context, mData, layoutResId); this.listener = listener; } /** * 多布局列表重写该方法 + * + * @param context context + * @param mData 数据源 + * @param multiItemViewType 多布局类型 */ - public BaseListAdapter(Context context, List items, IMulItemViewType multiItemViewType) { - super(context, items, multiItemViewType); + public BaseListAdapter(Context context, List mData, IMulItemViewType multiItemViewType) { + super(context, mData, multiItemViewType); } /** - * 添加点击事件监听 + * Item点击事件 + * + * @param listener listener */ - public void setOnListItemClickListener(OnListItemClickListener listener) { + public void setOnListItemClickListener(OnListItemClickListener listener) { this.listener = listener; } @Override - public void onBind(final SuperViewHolder viewHolder, int viewType, final int layoutPosition, T data) { - viewHolder.itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (listener != null) { - listener.onItemClick((View) viewHolder.itemView.getParent(), layoutPosition); - } + public void onBind(@NotNull final SuperViewHolder viewHolder, int viewType, final int layoutPosition, T data) { + viewHolder.itemView.setOnClickListener(v -> { + if (listener != null) { + listener.onItemClick(data, layoutPosition); } }); onBindData(viewHolder, viewType, layoutPosition, data); } - /** - * 绑定数据 - */ - public abstract void onBindData(SuperViewHolder holder, int viewType, int layoutPosition, T data); + public abstract void onBindData(@NotNull SuperViewHolder holder, int viewType, int layoutPosition, @NotNull T data); } diff --git a/common_base/src/main/java/com/wss/common/base/adapter/listener/OnListItemClickListener.java b/common_base/src/main/java/com/wss/common/base/adapter/listener/OnListItemClickListener.java new file mode 100644 index 0000000..6e5aa16 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/base/adapter/listener/OnListItemClickListener.java @@ -0,0 +1,16 @@ +package com.wss.common.base.adapter.listener; + +/** + * Describe:RecycleView 点击事件监听 + * Created by 吴天强 on 2018/10/18. + */ +public interface OnListItemClickListener { + + /** + * Item点击事件 + * + * @param data Data + * @param position position + */ + void onItemClick(T data, int position); +} diff --git a/common_base/src/main/java/com/wss/common/base/bean/BaseBean.java b/common_base/src/main/java/com/wss/common/base/bean/BaseBean.java index 5336724..2a1f161 100644 --- a/common_base/src/main/java/com/wss/common/base/bean/BaseBean.java +++ b/common_base/src/main/java/com/wss/common/base/bean/BaseBean.java @@ -2,10 +2,11 @@ import java.io.Serializable; + /** * Describe:Bean基类 * Created by 吴天强 on 2018/10/17. */ - public class BaseBean implements Serializable { + } diff --git a/common_base/src/main/java/com/wss/common/base/mvp/BaseModel.java b/common_base/src/main/java/com/wss/common/base/mvp/BaseModel.java new file mode 100644 index 0000000..3ca9b7e --- /dev/null +++ b/common_base/src/main/java/com/wss/common/base/mvp/BaseModel.java @@ -0,0 +1,27 @@ +package com.wss.common.base.mvp; + + +import androidx.lifecycle.LifecycleOwner; + +/** + * Describe:网络请求基类 + * Created by 吴天强 on 2019/7/11. + */ +public class BaseModel { + + private LifecycleOwner lifecycleOwner; + + public BaseModel(LifecycleOwner lifecycleOwner) { + this.lifecycleOwner = lifecycleOwner; + } + + /** + * 返回生命周期所有者 + * + * @return LifecycleOwner + */ + protected LifecycleOwner getLifecycleOwner() { + return lifecycleOwner; + } + +} diff --git a/common_base/src/main/java/com/wss/common/base/mvp/BasePresenter.java b/common_base/src/main/java/com/wss/common/base/mvp/BasePresenter.java index bb3c05d..ed3fccc 100644 --- a/common_base/src/main/java/com/wss/common/base/mvp/BasePresenter.java +++ b/common_base/src/main/java/com/wss/common/base/mvp/BasePresenter.java @@ -7,29 +7,32 @@ import java.lang.reflect.Method; import java.lang.reflect.Proxy; +import androidx.lifecycle.LifecycleOwner; + /** * Describe:Presenter基类 * Created by 吴天强 on 2018/10/17. */ - -public abstract class BasePresenter { +@SuppressWarnings("unchecked") +public abstract class BasePresenter { private V mProxyView; - private M module; + private M model; private WeakReference weakReference; /** * 绑定View + * + * @param view view */ - @SuppressWarnings("unchecked") public void attachView(V view) { weakReference = new WeakReference<>(view); mProxyView = (V) Proxy.newProxyInstance( view.getClass().getClassLoader(), view.getClass().getInterfaces(), new MvpViewHandler(weakReference.get())); - if (this.module == null) { - this.module = createModule(); + if (this.model == null) { + this.model = createModule(); } } @@ -37,41 +40,70 @@ public void attachView(V view) { * 解绑View */ public void detachView() { - this.module = null; - if (isViewAttached()) { + this.model = null; + if (!isViewDetached()) { weakReference.clear(); weakReference = null; } } /** - * 是否与View建立连接 + * 是否与View断开连接 */ - protected boolean isViewAttached() { - return weakReference != null && weakReference.get() != null; + protected boolean isViewDetached() { + return weakReference == null || weakReference.get() == null; } + /** + * 返回View + * + * @return view + */ protected V getView() { return mProxyView; } - protected M getModule() { - return module; + /** + * 返回Model + * + * @return model + */ + protected M getModel() { + return model; } + /** + * 返回Context + * + * @return context + */ protected Context getContext() { return getView().getContext(); } + /** + * 返回持有View的生命周期所有者 + * + * @return LifecycleOwner + */ + protected LifecycleOwner getLifecycleOwner() { + return getView().getLifecycleOwner(); + } + + /** + * 显示加载框 + */ protected void showLoading() { getView().showLoading(); } + /** + * 隐藏加载框 + */ protected void dismissLoading() { getView().dismissLoading(); } - /** * 通过该方法创建Module */ @@ -97,7 +129,7 @@ private class MvpViewHandler implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //如果V层没被销毁, 执行V层的方法. - if (isViewAttached()) { + if (!isViewDetached()) { return method.invoke(mvpView, args); } //P层不需要关注V层的返回值 return null; diff --git a/common_base/src/main/java/com/wss/common/base/mvp/IBaseModel.java b/common_base/src/main/java/com/wss/common/base/mvp/IBaseModel.java deleted file mode 100644 index e1f07d2..0000000 --- a/common_base/src/main/java/com/wss/common/base/mvp/IBaseModel.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.wss.common.base.mvp; - -/** - * Describe:所有Module的基类 - * Created by 吴天强 on 2018/10/17. - */ - -public interface IBaseModel { - -} diff --git a/common_base/src/main/java/com/wss/common/base/mvp/IBaseView.java b/common_base/src/main/java/com/wss/common/base/mvp/IBaseView.java index 31bd479..5b6f526 100644 --- a/common_base/src/main/java/com/wss/common/base/mvp/IBaseView.java +++ b/common_base/src/main/java/com/wss/common/base/mvp/IBaseView.java @@ -2,11 +2,12 @@ import android.content.Context; +import androidx.lifecycle.LifecycleOwner; + /** * Describe:所有View基类 * Created by 吴天强 on 2018/10/17. */ - public interface IBaseView { /** @@ -40,4 +41,12 @@ public interface IBaseView { * @return context */ Context getContext(); + + /** + * 返回页面生命周期 + * + * @return LifecycleOwner + */ + LifecycleOwner getLifecycleOwner(); + } diff --git a/common_base/src/main/java/com/wss/common/bean/AppInfo.java b/common_base/src/main/java/com/wss/common/bean/AppInfo.java deleted file mode 100644 index 37a7941..0000000 --- a/common_base/src/main/java/com/wss/common/bean/AppInfo.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.wss.common.bean; - -import com.wss.common.base.bean.BaseBean; - -import lombok.Getter; -import lombok.Setter; - -/** - * Describe: - * Created by 吴天强 on 2018/11/20. - */ - -@Getter -@Setter -public class AppInfo extends BaseBean { - - private int id; - private int versionCode; - private String versionName; - private String describe; - private String path; - - @Override - public String toString() { - return "AppInfo{" + - "id=" + id + - ", versionCode=" + versionCode + - ", versionName='" + versionName + '\'' + - ", describe='" + describe + '\'' + - ", path='" + path + '\'' + - '}'; - } -} diff --git a/common_base/src/main/java/com/wss/common/bean/Banner.java b/common_base/src/main/java/com/wss/common/bean/Banner.java new file mode 100644 index 0000000..265a5a0 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/bean/Banner.java @@ -0,0 +1,35 @@ +package com.wss.common.bean; + + +import com.wss.common.base.bean.BaseBean; + +import lombok.Getter; +import lombok.Setter; + +/** + * description: 房源首页Banner实体 + * + * @author 杨伟-tony + * create by 2020/5/21 20:40 + */ +@Getter +@Setter +public class Banner extends BaseBean { + /** + * 图片链接 + */ + private String imageUrl; + /** + * 跳转链接 + */ + private String redirectUrl; + + public Banner(String imageUrl) { + this.imageUrl = imageUrl; + } + + public Banner(String imageUrl, String redirectUrl) { + this.imageUrl = imageUrl; + this.redirectUrl = redirectUrl; + } +} diff --git a/common_base/src/main/java/com/wss/common/bean/Event.java b/common_base/src/main/java/com/wss/common/bean/Event.java index 51f1dcc..554e1cb 100644 --- a/common_base/src/main/java/com/wss/common/bean/Event.java +++ b/common_base/src/main/java/com/wss/common/bean/Event.java @@ -1,22 +1,28 @@ package com.wss.common.bean; + +import com.wss.common.base.bean.BaseBean; + import lombok.Getter; import lombok.Setter; - /** * Describe:EventBus事件类 * Created by 吴天强 on 2018/10/22. */ - @Getter @Setter -public class Event { +public class Event extends BaseBean { + /** + * 事件 + */ private String action; + /** + * 事件附带数据 + */ private T data; - public Event(String action) { this.action = action; } @@ -26,5 +32,4 @@ public Event(String action, T data) { this.data = data; } - } diff --git a/common_base/src/main/java/com/wss/common/bean/HorizontalTabTitle.java b/common_base/src/main/java/com/wss/common/bean/HorizontalTabTitle.java index a002a91..2892986 100644 --- a/common_base/src/main/java/com/wss/common/bean/HorizontalTabTitle.java +++ b/common_base/src/main/java/com/wss/common/bean/HorizontalTabTitle.java @@ -1,18 +1,25 @@ package com.wss.common.bean; + import com.wss.common.base.bean.BaseBean; import lombok.Getter; import lombok.Setter; /** - * Describe:水平选项卡Title + * Describe:水平选项卡标题 * Created by 吴天强 on 2018/10/22. */ @Getter @Setter public class HorizontalTabTitle extends BaseBean { + /** + * 显示标题文字 + */ private String title; + /** + * 标题其他附带数据 + */ private T data; public HorizontalTabTitle(String title) { @@ -22,6 +29,7 @@ public HorizontalTabTitle(String title) { public HorizontalTabTitle(String title, T data) { this.title = title; this.data = data; + } } diff --git a/common_base/src/main/java/com/wss/common/bean/SelectorData.java b/common_base/src/main/java/com/wss/common/bean/SelectorData.java new file mode 100644 index 0000000..85ec54c --- /dev/null +++ b/common_base/src/main/java/com/wss/common/bean/SelectorData.java @@ -0,0 +1,29 @@ +package com.wss.common.bean; + +import com.contrarywind.interfaces.IPickerViewData; +import com.wss.common.base.bean.BaseBean; +import com.wss.common.utils.ValidUtils; + +import lombok.Getter; +import lombok.Setter; + +/** + * Describe:弹窗选择器数据Bean + * Created by 吴天强 on 2020/4/21. + */ +@Getter +@Setter +public class SelectorData extends BaseBean implements IPickerViewData { + private String name; + private T data; + + public SelectorData(String name, T data) { + this.name = name; + this.data = data; + } + + @Override + public String getPickerViewText() { + return ValidUtils.isValid(name) ? name : ""; + } +} diff --git a/common_base/src/main/java/com/wss/common/bean/Template.java b/common_base/src/main/java/com/wss/common/bean/Template.java index 28eaad8..ecfaff6 100644 --- a/common_base/src/main/java/com/wss/common/bean/Template.java +++ b/common_base/src/main/java/com/wss/common/bean/Template.java @@ -1,7 +1,7 @@ package com.wss.common.bean; -import com.wss.common.base.BaseActivity; import com.wss.common.base.bean.BaseBean; +import com.wss.common.constants.Constants; import java.util.Map; @@ -20,27 +20,36 @@ public class Template extends BaseBean { private int res; private String describe; private Class clazz; - private String url;//模块外跳转链接 - private int type;//0.本模块内Activity跳转 1.业务模块跳转 2.应用外跳转[WebView] - private Map params;//其他附加参数 - - public Template(String title, int res, String url, int type, String describe) { + /** + * 模块外跳转链接 + */ + private String url; + /** + * 页面跳转类型 + */ + private int type; + /** + * 其他附加参数 + */ + private Map params; + + public Template(String title, String url, int type, String describe) { this.title = title; - this.res = res; this.url = url; this.type = type; this.describe = describe; } - public Template(String title, int res, Class clazz) { - this(title, res, clazz, ""); + public Template(String title, Class clazz, String describe) { + this.title = title; + this.clazz = clazz; + this.type = Constants.TemplateType.ACTIVITY; + this.describe = describe; } - public Template(String title, int res, Class clazz, String describe) { + public Template(String title, int res, Class clazz) { this.title = title; this.res = res; this.clazz = clazz; - this.describe = describe; } - } diff --git a/common_base/src/main/java/com/wss/common/bean/User.java b/common_base/src/main/java/com/wss/common/bean/User.java index c5ceaaa..7f058ba 100644 --- a/common_base/src/main/java/com/wss/common/bean/User.java +++ b/common_base/src/main/java/com/wss/common/bean/User.java @@ -6,11 +6,11 @@ import lombok.Setter; /** - * Describe:用户信息 - * Created by 吴天强 on 2018/11/13. + * Describe:置业顾问信息 + * Created by 吴天强 on 2020/5/6. */ -@Setter @Getter +@Setter public class User extends BaseBean { /** @@ -23,7 +23,7 @@ public class User extends BaseBean { * username : 于慢慢家的吴蜀黍 */ - private int id; + private Integer id; private String username; private String email; private String icon; @@ -38,4 +38,5 @@ public User(String username, String password) { this.username = username; this.password = password; } -} + +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/constants/ARouterConfig.java b/common_base/src/main/java/com/wss/common/constants/ARouterConfig.java index c5ea445..11e1eb7 100644 --- a/common_base/src/main/java/com/wss/common/constants/ARouterConfig.java +++ b/common_base/src/main/java/com/wss/common/constants/ARouterConfig.java @@ -4,7 +4,6 @@ * Describe:路由页面常量配置 注意:路径至少需要两级 {/xx/xx} * Created by 吴天强 on 2018/10/16. */ - public interface ARouterConfig { //************************************Main模块*****************************************/ diff --git a/common_base/src/main/java/com/wss/common/constants/CacheKey.java b/common_base/src/main/java/com/wss/common/constants/CacheKey.java deleted file mode 100644 index 66dca42..0000000 --- a/common_base/src/main/java/com/wss/common/constants/CacheKey.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.wss.common.constants; - -import com.wss.common.base.BaseApplication; - -/** - * Describe:缓存key - * Created by 吴天强 on 2018/11/13. - */ - -public interface CacheKey { - - /** - * 保存用户信息 - */ - String USER_INFO = BaseApplication.getApplication().getPackageName() + ".UserInfo"; - - /** - * 保存登录状态 - */ - String USER_LOGGED = BaseApplication.getApplication().getPackageName() + ".UserLogged"; -} diff --git a/common_base/src/main/java/com/wss/common/constants/Constants.java b/common_base/src/main/java/com/wss/common/constants/Constants.java index 6292a56..10883d1 100644 --- a/common_base/src/main/java/com/wss/common/constants/Constants.java +++ b/common_base/src/main/java/com/wss/common/constants/Constants.java @@ -1,46 +1,159 @@ package com.wss.common.constants; +import android.content.Context; + +import com.wss.common.base.BaseApplication; + /** * Describe:常量存放 * Created by 吴天强 on 2017/10/9. */ +public interface Constants { + /** + * 无法分类的散装常量 + */ + interface Common { + /** + * android + */ + int PLATFORM_ANDROID = 1; + + /** + * 渠道名称 + */ + String CHANEL = "android"; + /** + * API 版本 + */ + String API_VERSION = "1.0"; + } -public class Constants { /** - * 服务器类型 - * SERVER_DEVELOP 开发环境 - * SERVER_TEST 测试环境 - * SERVER_PRODUCTION 生产环境 + * WebView相关配置 */ - public static final int SERVER_TYPE = ServerType.SERVER_DEVELOP; + interface WebView { + String CACHE_DIR = BaseApplication.i().getDir("cache", Context.MODE_PRIVATE).getPath(); + } + /** - * 服务器类型 + * 网络请求相关 */ - public class ServerType { - public static final int SERVER_DEVELOP = 0;//开发环境 - public static final int SERVER_TEST = 1;//测试环境 - public static final int SERVER_PRODUCTION = 2;//生产环境 - } + interface Net { + //response + String STATE = "errorCode"; + String MESSAGE = "errorMsg"; + String DATA = "data"; + //request + String HEADER_CHANNEL = "channel"; + String HEADER_API_VERSION = "apiVersion"; + String HEADER_DEVICE_ID = "deviceid"; + String HEADER_TOKEN = "token"; + String HEADER_APP_VERSION = "appVersion"; + String HEADER_IP = "ip"; + String REQUEST_ID = "requestId"; + String REQUEST_DATA = "requestData"; + /** + * 超时时间 单位:秒 + */ + int TIME_OUT = 30; + + /** + * 接口响应码 + */ + interface Status { + /** + * 处理成功 + */ + String CODE_SUCCESS = "0"; + /** + * 该用户已经被禁用 + */ + String CODE_ACCOUNT_DISABLE = "1111"; + /** + * 该用户已经离职 + */ + String CODE_ACCOUNT_QUIT = "1112"; + /** + * 账号被锁定 + */ + String CODE_ACCOUNT_LOCKED = "1113"; + /** + * 此账户没有操作权限 + */ + String CODE_ACCOUNT_NO_AUTHORITY = "1114"; + /** + * 此账户没有归属团队 + */ + String CODE_ACCOUNT_NO_TEAM = "1118"; + /** + * 此账户同一项目归属多个团队 + */ + String CODE_ACCOUNT_MULTIPLE_TEAM = "1119"; + /** + * Token过期 + */ + String CODE_TOKEN_EXPIRED = "1120"; + /** + * 该用户的岗位信息有误 + */ + String CODE_ACCOUNT_POSITION_ERROR = "1128"; + + /** + * 参数异常 + */ + String INVALID_PARAMETER_ERROR = "403"; + } + } /** - * 模块类型 + * 选择文件的文件类型 */ - public static final int MODULE_TYPE_SHUTTLE = 0; - public static final int MODULE_TYPE_CHART = 1; - public static final int MODULE_TYPE_DEALS = 2; + interface FileType { + /** + * 图片 + */ + int IMAGE = 0; + /** + * 视频 + */ + int VIDEO = 1; + /** + * 音频 + */ + int AUDIO = 2; + /** + * 文档 + */ + int DOC = 3; + /** + * 压缩包 + */ + int PACKAGE = 4; + /** + * 其他 + */ + int OTHER = 5; + } + /** + * 数据库配置 + */ + interface DBConfig { + String DB_NAME = "AMD.db"; + } /** - * 默认日期格式 + * 页面跳转类型 */ - public static final String DATE_FORMAT_SLASH = "yyyy/MM/dd"; - public static final String DATE_FORMAT_LINE = "yyyy-MM-dd"; - public static final String DATE_FORMAT_DEFAULT = DATE_FORMAT_SLASH + " HH:mm:ss"; + interface TemplateType { - public static final String ERROR_MESSAGE = "网络连接失败"; - public static final int SUCCESS_CODE = 0; + int ACTIVITY = 0; + int AROUTER = 1; + int WEB_VIEW = 2; + int SYS_BROWSER = 3; + } } diff --git a/common_base/src/main/java/com/wss/common/constants/DBConfig.java b/common_base/src/main/java/com/wss/common/constants/DBConfig.java deleted file mode 100644 index 6a94bef..0000000 --- a/common_base/src/main/java/com/wss/common/constants/DBConfig.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.wss.common.constants; - -import com.wss.common.base.BaseApplication; -import com.wss.common.base.R; - -/** - * Describe:数据库配置文件 - * Created by 吴天强 on 2018/11/5. - */ - -public interface DBConfig { - String DB_NAME = BaseApplication.getApplication().getString(R.string.app_name) + ".db"; -} diff --git a/common_base/src/main/java/com/wss/common/constants/Dic.java b/common_base/src/main/java/com/wss/common/constants/Dic.java new file mode 100644 index 0000000..9259e1f --- /dev/null +++ b/common_base/src/main/java/com/wss/common/constants/Dic.java @@ -0,0 +1,84 @@ +package com.wss.common.constants; + +/** + * Describe:字典 存放Activity跳转传参key、缓存数据到SP中key等。 + * Created by 吴天强 on 2018/11/13. + */ +public interface Dic { + + /** + * 跳转画廊参数-图片集合 + */ + String IMAGE_LIST = "image_list"; + /** + * 跳转画廊参数-图片起始位置 + */ + String IMAGE_POSITION = "image_position"; + /** + * 跳转画廊参数-是否本地图片 + */ + String IMAGE_LOCAL = "image_local"; + /** + * 跳转画廊参数-是否全屏显示 + */ + String FULL_SCREEN = "full_screen"; + + /** + * 通过路由跳转的Fragment的路径 + */ + String TARGET_FRAGMENT_PATH = "target_fragment_path"; + + /** + * 进入类型 + */ + String FROM_TYPE = "from_type"; + + /** + * 链接 + */ + String URL = "url"; + + /** + * 需要actionBar + */ + String IS_ACTION_BAR = "is_action_bar"; + /** + * actionBar 文字 + */ + String TITLE_TEXT = "title_text"; + /** + * bundle带入的数据 + */ + String BUNDLE_DATA = "bundle_data"; + + /** + * 可选文件的最大值 + */ + String MAX_SELECT_FILE = "max_select_file"; + /** + * 选择的文件路径列表 + */ + String SELECT_FILE_PATHS = "select_file_paths"; + /** + * 商品信息 + */ + String GOODS_INFO = "goods_info"; + /** + * 登录用户 + */ + String LOGIN_USER_INFO = "login_user_info"; + /** + * 系列子类 + */ + String CLASSIFICATION_CHILD = "classification_child"; + /** + * HouseFragment中的ViewPager + */ + String HOUSE_FRAGMENT_VIEWPAGER = "viewpager"; + /** + * 供应商 商品 信息 + */ + String VENDOR_GOODS_INFO = "vendor_goods_info"; + + +} diff --git a/common_base/src/main/java/com/wss/common/constants/EventAction.java b/common_base/src/main/java/com/wss/common/constants/EventAction.java index 8192797..267af44 100644 --- a/common_base/src/main/java/com/wss/common/constants/EventAction.java +++ b/common_base/src/main/java/com/wss/common/constants/EventAction.java @@ -4,30 +4,38 @@ * Describe:EventBus事件 * Created by 吴天强 on 2018/10/19. */ - public interface EventAction { + //************************************Common模块****************************************/ + /** + * 删除画廊的图片, Action Data = 删除图片的position + */ + String IMAGE_GALLERY_DELETE = "image_gallery_delete"; /** - * 商城商品被点击 + * 二维码扫描结果 Action Data = String */ - String EVENT_MARKET_CLICK = "event_market_click"; + String SCAN_QR_CODE_RESULT = "scan_qr_code_result"; + + + //************************************Market模块*****************************************/ /** - * 刷新购物车 + * 购物车有变化 */ - String EVENT_SHOPPING_CART_REFRESH = "event_shopping_cart_refresh"; + String EVENT_SHOPPING_CART_CHANGED = "event_shopping_cart_changed"; /** - * 清空购物车 + * 刷新购物车 重新获取数据 */ - String EVENT_SHOPPING_CART_CLEAN = "event_shopping_cart_clean"; + String EVENT_SHOPPING_CART_REFRESH = "event_shopping_cart_refresh"; + //************************************User模块*****************************************/ /** * 登录成功 */ - String EVENT_LOGIN_SUCCESS = "EVENT_LOGIN_SUCCESS"; + String EVENT_LOGIN_SUCCESS = "event_login_success"; /** * 注册成功 */ - String EVENT_REGISTER_SUCCESS = "EVENT_REGISTER_SUCCESS"; + String EVENT_REGISTER_SUCCESS = "event_register_success"; } diff --git a/common_base/src/main/java/com/wss/common/dao/BaseDBManager.java b/common_base/src/main/java/com/wss/common/dao/BaseDBManager.java index fc50a9a..5dfc8cb 100644 --- a/common_base/src/main/java/com/wss/common/dao/BaseDBManager.java +++ b/common_base/src/main/java/com/wss/common/dao/BaseDBManager.java @@ -9,7 +9,6 @@ * Describe:所有的数据库操作类都继承自此 * Created by 吴天强 on 2018/11/5. */ - public class BaseDBManager { private AbstractDao mDao; diff --git a/common_base/src/main/java/com/wss/common/dao/DBMigrationHelper.java b/common_base/src/main/java/com/wss/common/dao/DBMigrationHelper.java index 1fa0ed0..b46cac6 100644 --- a/common_base/src/main/java/com/wss/common/dao/DBMigrationHelper.java +++ b/common_base/src/main/java/com/wss/common/dao/DBMigrationHelper.java @@ -2,20 +2,21 @@ import android.database.Cursor; +import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; -import android.support.annotation.NonNull; import android.text.TextUtils; -import android.util.Log; + +import com.orhanobut.logger.Logger; import org.greenrobot.greendao.AbstractDao; import org.greenrobot.greendao.database.Database; import org.greenrobot.greendao.database.StandardDatabase; import org.greenrobot.greendao.internal.DaoConfig; +import org.jetbrains.annotations.Contract; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; +import java.util.Date; import java.util.List; @@ -24,167 +25,216 @@ * Created by 吴天强 on 2018/11/5. */ public class DBMigrationHelper { - private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'IDatabase MATCH WITH THE CURRENT PARAMETERS"; - public void onUpgrade(SQLiteDatabase db, Class>... daoClasses) { + private static final String SQLITE_MASTER = "sqlite_master"; + private static final String SQLITE_TEMP_MASTER = "sqlite_temp_master"; + + static void migrate(SQLiteDatabase db, Class>... daoClasses) { + Logger.e("【The Old Database Version】" + db.getVersion()); Database database = new StandardDatabase(db); - generateTempTables(database, daoClasses); //备份数据(表结构改变的表) - dropAllTables(database, true, daoClasses); //删除旧表(结构修改/新增) - createAllTables(database, false, daoClasses); //创建 新表(结构修改/新增) - restoreData(database, daoClasses); //恢复数据(结构修改) + migrate(database, daoClasses); } - private void dropAllTables(Database db, boolean b, Class>... daoClasses) { - if (daoClasses != null) { - reflectMethod(db, "dropTable", b, daoClasses); + + @SafeVarargs + static void migrate(Database database, Class>... daoClasses) { + Logger.e("【Generate temp table】start"); + generateTempTables(database, daoClasses); + Logger.e("【Generate temp table】complete"); + + Logger.e("【Drop all table and recreate all table】"); + for (Class> daoClass : daoClasses) { + DaoConfig daoConfig = new DaoConfig(database, daoClass); + dropTable(database, true, daoConfig); + createTable(database, false, daoConfig); } + + Logger.e("【Restore data】start"); + restoreData(database, daoClasses); + Logger.e("【Restore data】complete"); } - private void createAllTables(Database db, boolean b, Class>... daoClasses) { - if (daoClasses != null) { - reflectMethod(db, "createTable", b, daoClasses); + private static void dropTable(Database database, boolean ifExists, DaoConfig daoConfig) { + String sql = String.format("DROP TABLE %s\"%s\"", ifExists ? "IF EXISTS " : "", daoConfig.tablename); + database.execSQL(sql); + } + + @SafeVarargs + private static void generateTempTables(Database db, Class>... daoClasses) { + for (Class> daoClass : daoClasses) { + String tempTableName = null; + + DaoConfig daoConfig = new DaoConfig(db, daoClass); + String tableName = daoConfig.tablename; + if (!isTableExists(db, false, tableName)) { + Logger.e("【New Table】" + tableName); + continue; + } + try { + tempTableName = daoConfig.tablename.concat("_TEMP"); + StringBuilder dropTableStringBuilder = new StringBuilder(); + dropTableStringBuilder.append("DROP TABLE IF EXISTS ").append(tempTableName).append(";"); + Logger.e("【Generate temp table】 dropTableStringBuilder:" + dropTableStringBuilder); + db.execSQL(dropTableStringBuilder.toString()); + + StringBuilder insertTableStringBuilder = new StringBuilder(); + insertTableStringBuilder.append("CREATE TEMPORARY TABLE ").append(tempTableName); + insertTableStringBuilder.append(" AS SELECT * FROM ").append(tableName).append(";"); + Logger.e("【Generate temp table】 insertTableStringBuilder:" + insertTableStringBuilder); + db.execSQL(insertTableStringBuilder.toString()); + Logger.e("【Table】" + tableName + "\n ---Columns-->" + getColumnsStr(daoConfig)); + Logger.e("【Generate temp table】" + tempTableName); + } catch (SQLException e) { + Logger.e("【Failed to generate temp table】" + tempTableName, e); + } } } - /** - * 反射出方法执行 - */ - private static void reflectMethod(Database db, String methodName, boolean isExists, @NonNull Class>... daoClasses) { - if (daoClasses.length < 1) { - return; + @Contract("null, _, _ -> false") + private static boolean isTableExists(Database db, boolean isTemp, String tableName) { + if (db == null || TextUtils.isEmpty(tableName)) { + return false; } + String dbName = isTemp ? SQLITE_TEMP_MASTER : SQLITE_MASTER; + String sql = "SELECT COUNT(*) FROM " + dbName + " WHERE type = ? AND name = ?"; + Cursor cursor = null; + int count = 0; try { - for (Class cls : daoClasses) { - // Method method = cls.getDeclaredMethod(methodName, cls); - Method method = cls.getDeclaredMethod(methodName, Database.class, boolean.class);//update by wragony on 2017-06-27 - method.invoke(null, db, isExists); + cursor = db.rawQuery(sql, new String[]{"table", tableName}); + if (cursor == null || !cursor.moveToFirst()) { + return false; } - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { + count = cursor.getInt(0); + } catch (Exception e) { e.printStackTrace(); + } finally { + if (cursor != null) { + cursor.close(); + } } + return count > 0; } - /** - * 备份数据 - * - * @param db - * @param daoClasses(表结构改变的表) - */ - private void generateTempTables(Database db, Class>... daoClasses) { - for (int i = 0; i < daoClasses.length; i++) { - DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]); - String divider = ""; - String tableName = daoConfig.tablename; - String tempTableName = daoConfig.tablename.concat("_TEMP"); - ArrayList properties = new ArrayList<>(); - StringBuilder createTableStringBuilder = new StringBuilder(); - createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" ("); - - for (int j = 0; j < daoConfig.properties.length; j++) { - String columnName = daoConfig.properties[j].columnName; - if (getColumns(db, tableName).contains(columnName)) { - properties.add(columnName); - String type = null; - try { - type = getTypeByClass(daoConfig.properties[j].type); - } catch (Exception exception) { -// Crashlytics.logException(exception); - } - createTableStringBuilder.append(divider).append(columnName).append(" ").append(type); - if (daoConfig.properties[j].primaryKey) { - createTableStringBuilder.append(" PRIMARY KEY"); - } - divider = ","; - } - } - createTableStringBuilder.append(");"); - db.execSQL(createTableStringBuilder.toString()); - StringBuilder insertTableStringBuilder = new StringBuilder(); - insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" ("); - insertTableStringBuilder.append(TextUtils.join(",", properties)); - insertTableStringBuilder.append(") SELECT "); - insertTableStringBuilder.append(TextUtils.join(",", properties)); - insertTableStringBuilder.append(" FROM ").append(tableName).append(";"); - db.execSQL(insertTableStringBuilder.toString()); + + private static String getColumnsStr(DaoConfig daoConfig) { + if (daoConfig == null) { + return "no columns"; + } + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < daoConfig.allColumns.length; i++) { + builder.append(daoConfig.allColumns[i]); + builder.append(","); } + if (builder.length() > 0) { + builder.deleteCharAt(builder.length() - 1); + } + return builder.toString(); } - /** - * 恢复数据 - * - * @param db - * @param daoClasses(结构修改的表) - */ - private void restoreData(Database db, Class>... daoClasses) { - for (int i = 0; i < daoClasses.length; i++) { - DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]); + @SafeVarargs + private static void restoreData(Database db, Class>... daoClasses) { + for (Class> daoClass : daoClasses) { + DaoConfig daoConfig = new DaoConfig(db, daoClass); String tableName = daoConfig.tablename; String tempTableName = daoConfig.tablename.concat("_TEMP"); - ArrayList properties = new ArrayList(); - - for (int j = 0; j < daoConfig.properties.length; j++) { - String columnName = daoConfig.properties[j].columnName; - - if (getColumns(db, tempTableName).contains(columnName)) { - properties.add(columnName); + isTableExists(db, true, tempTableName); + try { + // get all columns from tempTable, take careful to use the columns list + List columns = getColumns(db, tempTableName); + ArrayList properties = new ArrayList<>(columns.size()); + for (int j = 0; j < daoConfig.properties.length; j++) { + String columnName = daoConfig.properties[j].columnName; + if (columns.contains(columnName)) { + properties.add(columnName); + } } + if (properties.size() > 0) { + final String columnSQL = TextUtils.join(",", properties); + + StringBuilder insertTableStringBuilder = new StringBuilder(); + insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" ("); + insertTableStringBuilder.append(columnSQL); + insertTableStringBuilder.append(") SELECT "); + insertTableStringBuilder.append(columnSQL); + insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";"); + Logger.e("【Restore data】 db sql: " + insertTableStringBuilder); + db.execSQL(insertTableStringBuilder.toString()); + Logger.e("【Restore data】 to " + tableName); + } + StringBuilder dropTableStringBuilder = new StringBuilder(); + dropTableStringBuilder.append("DROP TABLE ").append(tempTableName); + db.execSQL(dropTableStringBuilder.toString()); + Logger.e("【Drop temp table】" + tempTableName); + } catch (SQLException e) { + Logger.e("【Failed to restore data from temp table 】" + tempTableName, e); } - - StringBuilder insertTableStringBuilder = new StringBuilder(); - - insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" ("); - insertTableStringBuilder.append(TextUtils.join(",", properties)); - insertTableStringBuilder.append(") SELECT "); - insertTableStringBuilder.append(TextUtils.join(",", properties)); - insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";"); - - StringBuilder dropTableStringBuilder = new StringBuilder(); - - //dropTableStringBuilder.append("DROP TABLE ").append(tempTableName); - dropTableStringBuilder.append("DROP TABLE IF EXISTS ").append(tempTableName).append(";");// update by wragony on 2017-06-27 - - db.execSQL(insertTableStringBuilder.toString()); - db.execSQL(dropTableStringBuilder.toString()); - } - } - - private String getTypeByClass(Class type) throws Exception { - if (type.equals(String.class)) { - return "TEXT"; - } - if (type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class)) { - return "INTEGER"; } - if (type.equals(Boolean.class)) { - return "BOOLEAN"; - } - - Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString())); -// Crashlytics.logException(exception); - throw exception; } private static List getColumns(Database db, String tableName) { - List columns = new ArrayList<>(); - Cursor cursor = null; - try { - cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null); - if (cursor != null) { - columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames())); + List columns = null; + try (Cursor cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 0", null)) { + if (null != cursor && cursor.getColumnCount() > 0) { + columns = Arrays.asList(cursor.getColumnNames()); } } catch (Exception e) { - Log.v(tableName, e.getMessage(), e); e.printStackTrace(); } finally { - if (cursor != null) - cursor.close(); + if (null == columns) { + columns = new ArrayList<>(); + } } return columns; } + private static void createTable(Database db, boolean ifNotExists, DaoConfig daoConfig) { + String tableName = daoConfig.tablename; + StringBuilder builder = new StringBuilder(); + builder.append("CREATE TABLE "); + builder.append(ifNotExists ? "IF NOT EXISTS " : ""); + builder.append(tableName); + builder.append(getColumnsSql(daoConfig)); + Logger.e("【createTable】 sql:" + builder.toString()); + db.execSQL(builder.toString()); // 6: Description + } + + private static String getColumnsSql(DaoConfig daoConfig) { + if (daoConfig == null) { + return ""; + } + StringBuilder builder = new StringBuilder(" ("); + for (int i = 0; i < daoConfig.properties.length; i++) { + builder.append(String.format("\"%s\" %s,", daoConfig.properties[i].columnName, + getPropertyType(daoConfig.properties[i].type))); + } + if (daoConfig.properties.length > 0 && builder.length() > 0) { + builder.deleteCharAt(builder.length() - 1); + } + builder.append("); "); + return builder.toString(); + } + + /** + * 根据字段类型返回对应的数据库字段语句 + * + * @param type + * @return + */ + private static String getPropertyType(Class type) { + if (type.equals(byte[].class)) { + return "BLOB"; + } else if (type.equals(String.class)) { + return "TEXT DEFAULT ''"; + } else if (type.equals(boolean.class) || type.equals(Boolean.class) + || type.equals(int.class) || type.equals(Integer.class) + || type.equals(long.class) || type.equals(Long.class) + || type.equals(Date.class) || type.equals(Byte.class)) { + return "INTEGER DEFAULT (0)"; + } else if (type.equals(float.class) || type.equals(Float.class) + || type.equals(double.class) || type.equals(Double.class)) { + return "REAL DEFAULT (0)"; + } + return "TEXT DEFAULT ''"; + } } diff --git a/common_base/src/main/java/com/wss/common/exception/NetErrorException.java b/common_base/src/main/java/com/wss/common/exception/NetErrorException.java new file mode 100644 index 0000000..deb20d6 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/exception/NetErrorException.java @@ -0,0 +1,53 @@ +package com.wss.common.exception; + +/** + * Describe:网络请求异常类 + * Created by 吴天强 on 2019/6/15. + */ +public class NetErrorException extends Exception { + + /** + * 网络请求错误码 + */ + private String errorCode; + /** + * 响应的Data + */ + private String responseData; + + public NetErrorException() { + } + + public NetErrorException(String message) { + this("", message); + } + + public NetErrorException(String errorCode, String message) { + this(errorCode, message, ""); + + } + + public NetErrorException(String errorCode, String message, String responseData) { + super(message); + this.errorCode = errorCode; + this.responseData = responseData; + } + + /** + * 返回网络请求错误码 + * + * @return errorCode + */ + public String getNetErrorCode() { + return errorCode; + } + + /** + * 返回网路响应的DATA + * + * @return responseData + */ + public String getNetResponseData() { + return responseData; + } +} diff --git a/common_base/src/main/java/com/wss/common/listener/OnListItemClickListener.java b/common_base/src/main/java/com/wss/common/listener/OnListItemClickListener.java deleted file mode 100644 index 00db6e5..0000000 --- a/common_base/src/main/java/com/wss/common/listener/OnListItemClickListener.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.wss.common.listener; - -import android.view.View; - -/** - * Describe:RecycleView 点击事件监听 - * Created by 吴天强 on 2018/10/18. - */ - -public interface OnListItemClickListener { - - void onItemClick(View view, int position); -} diff --git a/common_base/src/main/java/com/wss/common/manage/ActivityManage.java b/common_base/src/main/java/com/wss/common/manage/ActivityManage.java index 80b29d0..992ab1d 100644 --- a/common_base/src/main/java/com/wss/common/manage/ActivityManage.java +++ b/common_base/src/main/java/com/wss/common/manage/ActivityManage.java @@ -9,10 +9,11 @@ * Describe:管理所有的Activity * Created by 吴天强 on 2018/10/15. */ - public class ActivityManage { - //保存所有创建的Activity + /** + * 保存所有创建的Activity + */ private Set allActivities = new HashSet<>(); /** @@ -45,7 +46,5 @@ public void finishAll() { for (Activity activity : allActivities) { activity.finish(); } - } - } diff --git a/common_base/src/main/java/com/wss/common/manage/ActivityToActivity.java b/common_base/src/main/java/com/wss/common/manage/ActivityToActivity.java new file mode 100644 index 0000000..8d0a0af --- /dev/null +++ b/common_base/src/main/java/com/wss/common/manage/ActivityToActivity.java @@ -0,0 +1,301 @@ +package com.wss.common.manage; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; + +import com.alibaba.android.arouter.core.LogisticsCenter; +import com.alibaba.android.arouter.facade.Postcard; +import com.alibaba.android.arouter.launcher.ARouter; +import com.wss.common.base.bean.BaseBean; +import com.wss.common.bean.Template; +import com.wss.common.constants.Constants; +import com.wss.common.constants.Dic; +import com.wss.common.utils.ToastUtils; +import com.wss.common.utils.Utils; +import com.wss.common.view.browser.BrowserActivity; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import androidx.fragment.app.Fragment; + +/** + * Describe:Activity跳转 + * Created by 吴天强 on 2018/10/22. + */ +public class ActivityToActivity { + + + ////////////////////////////////////////普通Activity跳转//////////////////////////////////////// + + /** + * 普通Activity之间跳转 + * + * @param activity activity + * @param clazz 目标activity + */ + public static void toActivity(Context activity, Class clazz) { + toActivityForResult(activity, clazz, null, 0); + } + + /** + * 普通Activity之间跳转 + * + * @param activity activity + * @param clazz 目标activity + * @param params 携带参数 + */ + public static void toActivity(Context activity, Class clazz, Map params) { + toActivityForResult(activity, clazz, params, 0); + } + + /** + * 普通Activity之间跳转 + * + * @param activity activity + * @param clazz 目标activity + * @param requestCode 请求码 需大于0 + */ + public static void toActivityForResult(Context activity, Class clazz, int requestCode) { + toActivityForResult(activity, clazz, null, requestCode); + } + + /** + * 普通Activity之间跳转 + * ps:兼容从Fragment中使用ActivityForResult。传统方式Fragment中的onActivityResult中无法收到回调 + * + * @param fragment 当前fragment + * @param activity activity + * @param clazz 目标activity + * @param requestCode 请求码 需大于0 + */ + public static void toActivityForResult(Fragment fragment, Context activity, Class clazz, int requestCode) { + toActivityForResult(fragment, activity, clazz, null, requestCode); + } + + /** + * 普通Activity之间跳转 + * + * @param activity activity + * @param clazz 目标activity + * @param params 参数 + * @param requestCode 请求码 需大于0 + */ + public static void toActivityForResult(Context activity, Class clazz, Map params, int requestCode) { + Intent intent = new Intent(); + intent.setClass(activity, clazz); + assembleParams(intent, params); + if (requestCode > 0) { + ((Activity) activity).startActivityForResult(intent, requestCode); + } else { + activity.startActivity(intent); + } + } + + /** + * 在Fragment中调用startActivityForResult + * + * @param fragment 跳转所在的Fragment + * @param activity activity + * @param clazz 目标activity + * @param params 参数 + * @param requestCode 请求码 需大于0 + */ + public static void toActivityForResult(@NotNull Fragment fragment, Context activity, Class clazz, Map params, int requestCode) { + Intent intent = new Intent(); + intent.setClass(activity, clazz); + assembleParams(intent, params); + fragment.startActivityForResult(intent, requestCode); + } + + private static void assembleParams(Intent intent, Map params) { + if (params != null) { + for (Map.Entry entry : params.entrySet()) { + String key = entry.getKey(); + Object value = params.get(key); + if (value instanceof String) { + intent.putExtra(key, (String) value); + } else if (value instanceof Boolean) { + intent.putExtra(key, (boolean) value); + } else if (value instanceof Integer) { + intent.putExtra(key, (int) value); + } else if (value instanceof Float) { + intent.putExtra(key, (float) value); + } else if (value instanceof Double) { + intent.putExtra(key, (double) value); + } else if (value instanceof Long) { + intent.putExtra(key, (long) value); + } else if (value instanceof Short) { + intent.putExtra(key, (short) value); + } else if (value instanceof Bundle) { + intent.putExtra(key, (Bundle) value); + } else if (value instanceof BaseBean) { + intent.putExtra(key, (BaseBean) value); + } else if (value instanceof ArrayList) { + intent.putExtra(key, (ArrayList) value); + } else if (value instanceof HashMap) { + intent.putExtra(key, (HashMap) value); + } + } + } + } + //////////////////////////////////////WebView跳转////////////////////////////////////// + + /** + * 跳转WebView url 不可为空 + * + * @param context context + * @param url 链接 + * @param title 标题 + */ + public static void toWebView(Context context, String url, String title) { +// if (!NetworkUtil.isLink(url)) { +// return; +// } + Map param = new HashMap<>(); + param.put(Dic.URL, url); + param.put(Dic.TITLE_TEXT, title); + toActivity(context, BrowserActivity.class, param); + } + + /** + * 跳转WebView url 不可为空 + * + * @param context 链接 + * @param url 标题 + */ + public static void toWebView(Context context, String url) { + toWebView(context, url, ""); + } + + //////////////////////////////////////ARouter跳转////////////////////////////////////// + + /** + * ARouter跳转Activity + * + * @param activity Activity + * @param url 目标Activity Url + */ + public static void toActivity(Activity activity, String url) { + toActivityForResult(activity, url, null, 0); + } + + /** + * ARouter跳转Activity + * + * @param activity Activity + * @param url 目标Activity Url + */ + public static void toActivity(Activity activity, String url, Map params) { + toActivityForResult(activity, url, params, 0); + } + + /** + * ARouter跳转Activity + * + * @param activity Activity + * @param url 目标Activity Url + * @param requestCode 请求码 需大于0 + */ + public static void toActivityForResult(Activity activity, String url, int requestCode) { + toActivityForResult(activity, url, null, requestCode); + } + + /** + * ARouter跳转Activity + * + * @param activity Activity + * @param url 目标Activity Url + * @param params 参数 + * @param requestCode 请求码 需大于0 + */ + public static void toActivityForResult(Activity activity, String url, Map params, int requestCode) { + if (TextUtils.isEmpty(url)) { + return; + } + Postcard postcard = ARouter.getInstance() + .build(url); +// .withOptionsCompat(ActivityOptionsCompat.makeCustomAnimation(activity, R.anim.anim_right_in, R.anim.anim_right_out)); + if (params != null) { + for (Map.Entry entry : params.entrySet()) { + String key = entry.getKey(); + Object value = params.get(key); + if (value instanceof String) { + postcard.withString(key, (String) value); + } else if (value instanceof Boolean) { + postcard.withBoolean(key, (boolean) value); + } else if (value instanceof Integer) { + postcard.withInt(key, (int) value); + } else if (value instanceof Float) { + postcard.withFloat(key, (float) value); + } else if (value instanceof Double) { + postcard.withDouble(key, (double) value); + } else if (value instanceof Long) { + postcard.withLong(key, (long) value); + } else if (value instanceof Short) { + postcard.withShort(key, (short) value); + } else if (value instanceof Bundle) { + postcard.withBundle(key, (Bundle) value); + } else if (value instanceof BaseBean) { + postcard.withSerializable(key, (BaseBean) value); + } else if (value instanceof ArrayList) { + postcard.withSerializable(key, (ArrayList) value); + } else if (value instanceof HashMap) { + postcard.withSerializable(key, (HashMap) value); + } + } + } + if (requestCode > 0) { + LogisticsCenter.completion(postcard); + activity.startActivityForResult(new Intent(activity, postcard.getDestination()), requestCode); + } else { + postcard.navigation(); + } + } + + + /** + * 通过模板跳转Activity + * + * @param activity activity + * @param template 模板信息 + */ + @SuppressWarnings("unchecked") + public static void toActivity(Activity activity, Template template) { + switch (template.getType()) { + case Constants.TemplateType.ACTIVITY: + //跳转Activity + toActivity(activity, template.getClazz(), template.getParams()); + break; + case Constants.TemplateType.AROUTER: + //跳转Arouter + toActivity(activity, template.getUrl(), template.getParams()); + break; + case Constants.TemplateType.WEB_VIEW: + //跳转WebView + toWebView(activity, template.getUrl(), template.getDescribe()); + break; + case Constants.TemplateType.SYS_BROWSER: + //跳转手机浏览器 + Utils.toSystemBrowser(activity, template.getUrl()); + break; + default: + + } + } + + /** + * 跳转登录页 + * + * @param context ctx + */ + public static void toLoginActivity(Context context) { + ToastUtils.show("跳转登录页"); + } +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/manage/BlurTransformation.java b/common_base/src/main/java/com/wss/common/manage/BlurTransformation.java index 6005e9b..027edee 100644 --- a/common_base/src/main/java/com/wss/common/manage/BlurTransformation.java +++ b/common_base/src/main/java/com/wss/common/manage/BlurTransformation.java @@ -8,21 +8,24 @@ import android.renderscript.Element; import android.renderscript.RenderScript; import android.renderscript.ScriptIntrinsicBlur; -import android.support.annotation.NonNull; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; import java.security.MessageDigest; +import androidx.annotation.NonNull; + /** - * Describe:glide 加载图片转换器之模糊转换器 + * Describe:加载图片转换器之模糊转换器 * Created by 吴天强 on 2018/11/8. */ - public class BlurTransformation extends BitmapTransformation { private Context context; - private int blurRadius = 20;//模糊度 0=< blurRadius >=25 + /** + * 模糊度 0=< blurRadius<=25 + */ + private float blurRadius = 15; public BlurTransformation(Context context) { this.context = context; @@ -32,7 +35,7 @@ public BlurTransformation(Context context) { * @param context context * @param blurRadius 模糊度 最大25 */ - public BlurTransformation(Context context, int blurRadius) { + public BlurTransformation(Context context, float blurRadius) { this.context = context; this.blurRadius = blurRadius; } @@ -69,13 +72,11 @@ private Bitmap blurBitmap(Context context, Bitmap image, int outWidth, int outHe Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap); Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap); // 设置渲染的模糊程度, 25f是最大模糊度 - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - //模糊度最大到25 - if (blurRadius < 0 || blurRadius > 25) { - blurRadius = 20; - } - blurScript.setRadius(blurRadius); + //模糊度最大到25 + if (blurRadius < 0 || blurRadius > 25) { + blurRadius = 20; } + blurScript.setRadius(blurRadius); // 设置blurScript对象的输入内存 blurScript.setInput(tmpIn); // 将输出数据保存到输出内存中 diff --git a/common_base/src/main/java/com/wss/common/manage/CrashHandlerManage.java b/common_base/src/main/java/com/wss/common/manage/CrashHandlerManage.java deleted file mode 100644 index 164b98b..0000000 --- a/common_base/src/main/java/com/wss/common/manage/CrashHandlerManage.java +++ /dev/null @@ -1,188 +0,0 @@ -package com.wss.common.manage; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.os.Build; -import android.os.Environment; -import android.support.annotation.Nullable; - -import com.orhanobut.logger.Logger; -import com.wss.common.base.BaseApplication; -import com.wss.common.utils.DateUtils; -import com.wss.common.utils.FileUtils; -import com.wss.common.utils.ZipUtils; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.io.Writer; -import java.lang.Thread.UncaughtExceptionHandler; -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; - - -/** - * UncaughtException处理类,当程序发生Uncaught异常的时候,由该类来接管程序,并记录发送错误报告. - * Created by wtq on 2016/7/22. - */ -@SuppressLint("StaticFieldLeak") -public class CrashHandlerManage implements UncaughtExceptionHandler { - private static final String TAG = "CrashHandlerManage"; - private UncaughtExceptionHandler mDefaultHandler;// 系统默认的UncaughtException处理类 - private static CrashHandlerManage INSTANCE; - private Context mContext;// 程序的Context对象 - private Map info = new HashMap<>();// 用来存储设备信息和异常信息 - - /** - * 保证只有一个CrashHandler实例 - */ - private CrashHandlerManage() { - } - - public synchronized static CrashHandlerManage getInstance() { - if (INSTANCE == null) { - INSTANCE = new CrashHandlerManage(); - } - return INSTANCE; - } - - - /** - * 初始化 - */ - public void init(Context context) { - mContext = context; - mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();// 获取系统默认的UncaughtException处理器 - Thread.setDefaultUncaughtExceptionHandler(this);// 设置该CrashHandler为程序的默认处理器 - } - - /** - * 当UncaughtException发生时会转入该重写的方法来处理 - */ - public void uncaughtException(Thread thread, Throwable ex) { - if (!handleException(ex) && mDefaultHandler != null) { - // 如果自定义的没有处理则让系统默认的异常处理器来处理 - mDefaultHandler.uncaughtException(thread, ex); - } else { - try { - Thread.sleep(3000);// 如果处理了,让程序继续运行3秒再退出,保证文件保存并上传到服务器 - } catch (InterruptedException e) { - e.printStackTrace(); - } - ((BaseApplication) mContext.getApplicationContext()).exitApp(); - // 退出程序 - } - } - - - /** - * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. - * - * @param ex 异常信息 - * @return true 如果处理了该异常信息;否则返回false. - */ - public boolean handleException(Throwable ex) { - if (ex == null) - return false; - // 收集设备参数信息 - collectDeviceInfo(mContext); - // 保存日志文件 - saveCrashInfo2File(ex); - return true; - } - - /** - * 收集设备参数信息 - */ - public void collectDeviceInfo(Context context) { - try { - PackageManager pm = context.getPackageManager();// 获得包管理器 - PackageInfo pi = pm.getPackageInfo(context.getPackageName(), - PackageManager.GET_ACTIVITIES);// 得到该应用的信息,即主Activity - if (pi != null) { - String versionName = pi.versionName == null ? "null" - : pi.versionName; - String versionCode = pi.versionCode + ""; - info.put("versionName", versionName); - info.put("versionCode", versionCode); - } - } catch (NameNotFoundException e) { - e.printStackTrace(); - Logger.e("获取设置信息失败"); - } - - Field[] fields = Build.class.getDeclaredFields();// 反射机制 - for (Field field : fields) { - try { - field.setAccessible(true); - info.put(field.getName(), field.get("").toString()); - Logger.e(field.getName() + ":" + field.get("")); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - } - } - - @Nullable - private String saveCrashInfo2File(Throwable ex) { - StringBuilder sb = new StringBuilder(); - for (Map.Entry entry : info.entrySet()) { - String key = entry.getKey(); - String value = entry.getValue(); - sb.append(key).append("=").append(value).append("\r\n"); - } - Writer writer = new StringWriter(); - PrintWriter pw = new PrintWriter(writer); - ex.printStackTrace(pw); - Throwable cause = ex.getCause(); - // 循环着把所有的异常信息写入writer中 - while (cause != null) { - cause.printStackTrace(pw); - cause = cause.getCause(); - } - pw.close();// 记得关闭 - String result = writer.toString(); - sb.append(result); - // 保存文件 - String fileName = "crash-" + DateUtils.getCurrentDateStr() + "-" + DateUtils.getCurrentTimeStamp() + ".log"; - if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { - try { - File file = new File(FileUtils.getAppCrashPath(), fileName); - FileOutputStream fos = new FileOutputStream(file); - fos.write(sb.toString().getBytes()); - fos.close(); - return fileName; - } catch (IOException e) { - e.printStackTrace(); - } - } - return null; - } - - /** - * 上传日志文件 - */ - public static void uploadCrashFiles() { - final File outFile = FileUtils.getAppCrashPath(); - LinkedList files = FileUtils.listLinkedFiles(FileUtils.getAppCrashPath().getPath()); - if (files == null || files.size() == 0) { - return; - } - try { - ZipUtils.zipFiles(files, outFile); - } catch (IOException e) { - e.printStackTrace(); - } - if (!outFile.exists()) {//如果这个zip文件不存在的话,则不执行如下的操作 - return; - } - //TODO 做上传操作 - } -} diff --git a/common_base/src/main/java/com/wss/common/manage/GlideRoundTransform.java b/common_base/src/main/java/com/wss/common/manage/GlideRoundTransform.java new file mode 100644 index 0000000..dcd825c --- /dev/null +++ b/common_base/src/main/java/com/wss/common/manage/GlideRoundTransform.java @@ -0,0 +1,60 @@ +package com.wss.common.manage; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; + +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; +import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; +import com.bumptech.glide.load.resource.bitmap.TransformationUtils; +import com.wss.common.utils.PxUtils; + +import org.jetbrains.annotations.Contract; + +import java.security.MessageDigest; + +import androidx.annotation.NonNull; + +/** + * Describe:加载图片转换器之圆角转换器 + * Created by 吴天强 on 2019/7/2. + */ +public class GlideRoundTransform extends BitmapTransformation { + + private float radius = 0f; + + public GlideRoundTransform(Context context, int dp) { + super(); + radius = PxUtils.dp2px(dp); + } + + @Override + protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) { + Bitmap bitmap = TransformationUtils.centerCrop(pool, toTransform, outWidth, outHeight); + return roundCrop(pool, bitmap); + } + + @Contract("_, null -> null") + private Bitmap roundCrop(BitmapPool pool, Bitmap source) { + if (source == null){ return null;} + Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(result); + Paint paint = new Paint(); + paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP)); + paint.setAntiAlias(true); + RectF rectF = new RectF(0f, 0f, source.getWidth(), source.getHeight()); + canvas.drawRoundRect(rectF, radius, radius, paint); + return result; + } + + public String getId() { + return getClass().getName() + Math.round(radius); + } + + @Override + public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) { + } +} diff --git a/common_base/src/main/java/com/wss/common/manage/MediaScannerManage.java b/common_base/src/main/java/com/wss/common/manage/MediaScannerManage.java new file mode 100644 index 0000000..c09c792 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/manage/MediaScannerManage.java @@ -0,0 +1,74 @@ +package com.wss.common.manage; + +import android.content.Context; +import android.media.MediaScannerConnection; +import android.net.Uri; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.io.File; + +/** + * Describe:扫描媒体文件帮助类(主要用户保存文件、图片之后刷新到相册 操作) + * Created by 吴天强 on 2021/5/10. + */ +public class MediaScannerManage { + + private MediaScannerConnection mConn = null; + private File mFile = null; + + private MediaScannerManage(Context context) { + ScannerClient mClient = new ScannerClient(); + if (mConn == null) { + mConn = new MediaScannerConnection(context, mClient); + } + } + + @NotNull + @Contract("_ -> new") + public static synchronized MediaScannerManage getInstance(Context context) { + return new MediaScannerManage(context); + } + + + public void scanFile(File file) { + mFile = file; + mConn.connect(); + } + + private class ScannerClient implements MediaScannerConnection.MediaScannerConnectionClient { + + @Override + public void onMediaScannerConnected() { + if (mFile == null) { + return; + } + scan(mFile); + } + + @Override + public void onScanCompleted(String path, Uri uri) { + mConn.disconnect(); + } + + private void scan(@NotNull File file) { + + if (file.isFile()) { + mConn.scanFile(file.getAbsolutePath(), null); + return; + } + File[] files = file.listFiles(); + if (files == null) { + return; + } + File[] files1 = file.listFiles(); + if (files1 == null) { + return; + } + for (File f : files1) { + scan(f); + } + } + } +} diff --git a/common_base/src/main/java/com/wss/common/manage/UpdateManager.java b/common_base/src/main/java/com/wss/common/manage/UpdateManager.java deleted file mode 100644 index 45ae0b5..0000000 --- a/common_base/src/main/java/com/wss/common/manage/UpdateManager.java +++ /dev/null @@ -1,144 +0,0 @@ -package com.wss.common.manage; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Build; -import android.os.Handler; -import android.os.Message; -import android.text.TextUtils; -import android.view.View; - -import com.tamic.novate.Throwable; -import com.tamic.novate.callback.RxFileCallBack; -import com.wss.common.base.R; -import com.wss.common.net.HttpUtils; -import com.wss.common.net.NetConfig; -import com.wss.common.utils.FileUtils; -import com.wss.common.utils.ToastUtils; -import com.wss.common.widget.NumberProgressBar; -import com.wss.common.widget.dialog.AppDialog; - -import java.io.File; - - -/** - * 更新下载APK - * Created by wtq on 2016/7/22. - */ -@SuppressLint("StaticFieldLeak") -public class UpdateManager { - - private static final int DOWNLOADING = 0x00; - private static final int DOWNLOAD_SUCCESS = 0x02; - private static final int DOWNLOAD_FAILED = 0x03; - private static final int DOWNLOAD_CANCEL = 0x04; - private Context mContext; - private NumberProgressBar progressBar; - private AppDialog progressDialog; - private static UpdateManager manager; - private File tempFile;//下载后存文件路径 - - private UpdateManager(Context context) { - this.mContext = context; - View progressView = View.inflate(mContext, R.layout.update_progress_layout, null); - progressBar = progressView.findViewById(R.id.number_progress); - progressBar.setProgress(0); - progressDialog = new AppDialog(mContext); - progressDialog.setTitle("版本更新中···") - .addDialogView(progressView) - .show(); - } - - public static synchronized UpdateManager getInstance(Context context) { - if (manager == null) { - manager = new UpdateManager(context); - } - return manager; - } - - /** - * 弹出下载框 - */ - public void download(String url) { - if (TextUtils.isEmpty(url)) { - ToastUtils.showToast(mContext, "请设置下载Url"); - return; - } - progressDialog.show(); - HttpUtils.getInstance() - .setBaseUrl(NetConfig.Url.MY_SERVICE_URL) - .downloadFile(url, new RxFileCallBack("temp.apk") { - - @Override - public void onNext(Object tag, File file) { - tempFile = file; - updateHandler.sendEmptyMessage(DOWNLOAD_SUCCESS); - } - - @Override - public void onProgress(Object tag, float progress, long downloaded, long total) { - Message message = updateHandler.obtainMessage(); - message.what = DOWNLOADING; - message.obj = (int) progress; - updateHandler.sendMessage(message); - } - - @Override - public void onError(Object tag, Throwable e) { - updateHandler.sendEmptyMessage(DOWNLOAD_FAILED); - } - - @Override - public void onCancel(Object tag, Throwable e) { - updateHandler.sendEmptyMessage(DOWNLOAD_CANCEL); - } - }); - } - - - @SuppressLint("HandlerLeak") - private Handler updateHandler = new Handler() { - public void handleMessage(Message msg) { - switch (msg.what) { - case DOWNLOADING: - progressBar.setProgress((Integer) msg.obj); - break; - case DOWNLOAD_SUCCESS: - progressDialog.dismiss(); - ToastUtils.showToast(mContext, "下载完成"); - installApk(); - break; - case DOWNLOAD_FAILED: - progressDialog.dismiss(); - ToastUtils.showToast(mContext, "下载失败"); - break; - case DOWNLOAD_CANCEL: - progressDialog.dismiss(); - ToastUtils.showToast(mContext, "已取消下载"); - break; - default: - break; - } - } - - }; - - /** - * 安装apk - */ - private void installApk() { - // 安装,如果签名不一致,可能出现程序未安装提示 - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - Uri uriForFile = FileUtils.getUriForFile(mContext, tempFile); - intent.setDataAndType(uriForFile, "application/vnd.android.package-archive"); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - //7.0需要临时授权文件 - intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - } - mContext.startActivity(intent); - } -} diff --git a/common_base/src/main/java/com/wss/common/net/Api.java b/common_base/src/main/java/com/wss/common/net/Api.java index d841f8d..7eff724 100644 --- a/common_base/src/main/java/com/wss/common/net/Api.java +++ b/common_base/src/main/java/com/wss/common/net/Api.java @@ -1,11 +1,20 @@ package com.wss.common.net; + +import com.wss.common.profile.ProfileManager; + +import rxhttp.wrapper.annotation.DefaultDomain; + /** - * Describe:接口 + * Describe:接口名称 * Created by 吴天强 on 2018/10/17. */ - public interface Api { + /** + * 网络请求BaseUrl + */ + @DefaultDomain + String BASE_URL = ProfileManager.profile().getServiceBase(); //**********************************************鸿洋开放接口************************************** /** @@ -70,18 +79,19 @@ public interface Api { //**********************************************鸿洋开放接口************************************** - //**********************************************自己服务器接口************************************ + //**********************************************其他服务接口************************************ /** - * 检查更新 + * 上传文件(替换成自己的服务接口地址) */ - String CHECK_UPDATE = "/app/checkUpdate.json"; + String UPLOAD_FILE = "/app/upload/uploadFile.json"; /** - * 下载更新APK + * 下载文件(替换成自己的服务接口地址) */ - String DOWNLOAD_APK = "/app/download.json"; + String DOWNLOAD_FILE = "/app/download/downloadFile.json"; + + //**********************************************其他服务接口************************************ - //**********************************************自己服务器接口************************************ } diff --git a/common_base/src/main/java/com/wss/common/net/HttpUtils.java b/common_base/src/main/java/com/wss/common/net/HttpUtils.java deleted file mode 100644 index 7097fca..0000000 --- a/common_base/src/main/java/com/wss/common/net/HttpUtils.java +++ /dev/null @@ -1,310 +0,0 @@ -package com.wss.common.net; - -import android.text.TextUtils; - -import com.orhanobut.logger.Logger; -import com.tamic.novate.Novate; -import com.tamic.novate.callback.ResponseCallback; -import com.tamic.novate.callback.RxFileCallBack; -import com.wss.common.base.BaseApplication; -import com.wss.common.net.callback.OnResultCallBack; - -import java.io.File; -import java.util.List; - -/** - * Describe:网络请求帮助类 - * Created by 吴天强 on 2017/9/19. - */ - -public class HttpUtils { - - private static final int REQUEST_GET = 0; - private static final int REQUEST_POST = 1; - private static final int REQUEST_JSON = 2; - private Novate.Builder builder; - private static HttpUtils httpUtils; - private String baseUrl; - - private HttpUtils() { - builder = new Novate.Builder(BaseApplication.getApplication()); - builder.addCookie(true); //是否同步cooike 默认不同步 - - //https配置 xxx.cer放在asset目录下 -// builder.skipSSLSocketFactory(true);//信任所有证书 -// builder.addSSLSocketFactory(NovateHttpsFactroy.creatSSLSocketFactory( -// BaseApplication.getApplication().getBaseContext(), "xxx.cer")); - -// builder.addHeader(headers); //添加公共请求头 -// builder.addParameters(parameters);//公共参数 -// builder.connectTimeout(10); //连接时间 可以忽略 -// builder.addCache(true); //是否缓存 默认缓存 -// builder.addCache(cache, cacheTime); //自定义缓存 -// builder.addLog(true);//是否开启log -// builder.cookieManager(new NovateCookieManager()); // 自定义cooike,可以忽略 -// builder.addInterceptor(); // 自定义Interceptor -// builder.addNetworkInterceptor(); // 自定义NetworkInterceptor -// builder.proxy(proxy); //代理 -// builder.client(client); //clent 默认不需要 - } - - public static synchronized HttpUtils getInstance() { - if (httpUtils == null) { - httpUtils = new HttpUtils(); - } - return new HttpUtils(); - } - - public HttpUtils setBaseUrl(String baseUrl) { - this.baseUrl = baseUrl; - return this; - } - - ////////////////////////////////////////// GET请求 ///////////////////////////////////////////// - - /** - * Get无参无Tag - * - * @param url 请求地址 - * @param callback 回调 - */ - public void getRequest(String url, OnResultCallBack callback) { - request(REQUEST_GET, url, new RequestParam(), null, callback); - } - - /** - * Get 无参有Tag - * - * @param url 请求地址 - * @param tag 标签 - * @param callback 回调 - */ - public void getRequest(String url, String tag, OnResultCallBack callback) { - request(REQUEST_GET, url, new RequestParam(), tag, callback); - } - - /** - * Get有参无Tag - * - * @param url 请求地址 - * @param params 请求参数 - * @param callback 回调 - */ - public void getRequest(String url, RequestParam params, OnResultCallBack callback) { - request(REQUEST_GET, url, params, null, callback); - } - - /** - * Get有参有Tag - * - * @param url 请求地址 - * @param params 请求参数 - * @param tag 标签 - * @param callback 回调 - */ - public void getRequest(String url, RequestParam params, String tag, OnResultCallBack callback) { - request(REQUEST_GET, url, params, tag, callback); - } - - - ////////////////////////////////////////// POST请求 ///////////////////////////////////////////// - - /** - * Post 无参无TAG - * - * @param url 请求地址 - * @param callback 回调 - */ - public void postRequest(String url, OnResultCallBack callback) { - request(REQUEST_POST, url, new RequestParam(), null, callback); - } - - /** - * Post 无参有TAG - * - * @param url 请求地址 - * @param tag 标签 - * @param callback 回调 - */ - public void postRequest(String url, String tag, OnResultCallBack callback) { - request(REQUEST_POST, url, new RequestParam(), tag, callback); - } - - /** - * Post 有参无TAG - * - * @param url 请求地址 - * @param params 请求参数 - * @param callback 回调 - */ - public void postRequest(String url, RequestParam params, OnResultCallBack callback) { - request(REQUEST_POST, url, params, null, callback); - } - - /** - * Post 有参有TAG - * - * @param url 请求地址 - * @param params 请求参数 - * @param tag 标签 - * @param callback 回调 - */ - public void postRequest(String url, RequestParam params, String tag, OnResultCallBack callback) { - request(REQUEST_POST, url, params, tag, callback); - } - - ////////////////////////////////////////// JSON格式请求 ///////////////////////////////////////// - - /** - * Post 无参无TAG - * - * @param url 请求地址 - * @param callback 回调 - */ - public void jsonRequest(String url, OnResultCallBack callback) { - request(REQUEST_JSON, url, new RequestParam(), null, callback); - } - - /** - * Post 无参有TAG - * - * @param url 请求地址 - * @param tag 标签 - * @param callback 回调 - */ - public void jsonRequest(String url, String tag, OnResultCallBack callback) { - request(REQUEST_JSON, url, new RequestParam(), tag, callback); - } - - /** - * Post 有参无TAG - * - * @param url 请求地址 - * @param params 请求参数 - * @param callback 回调 - */ - public void jsonRequest(String url, RequestParam params, OnResultCallBack callback) { - request(REQUEST_JSON, url, params, null, callback); - } - - /** - * Post 有参有TAG - * - * @param url 请求地址 - * @param params 请求参数 - * @param tag 标签 - * @param callback 回调 - */ - public void jsonRequest(String url, RequestParam params, String tag, OnResultCallBack callback) { - request(REQUEST_JSON, url, params, tag, callback); - } - - - /** - * 最终请求 - * - * @param methodType 请求类型 get post - * @param url 接口 - * @param params 参数 - * @param tag tag - * @param callback 请求回调 - */ - private void request(int methodType, String url, RequestParam params, String tag, ResponseCallback callback) { - checkBaseUrl(); - Logger.e(baseUrl + url + params.toJson()); - switch (methodType) { - case REQUEST_POST: - builder.build().rxPost(tag, url, params.getParameter(), callback); - break; - case REQUEST_GET: - builder.build().rxGet(tag, url, params.getParameter(), callback); - break; - case REQUEST_JSON: - builder.build().rxJson(tag, url, params.toJson(), callback); - break; - default: - builder.build().rxGet(tag, url, params.getParameter(), callback); - break; - } - } - - ////////////////////////////////////////// 上传文件 ///////////////////////////////////////////// - - /** - * 上传单个文件 - * - * @param url 接口 - * @param file 文件 - * @param callback 回调 - */ - public void upLoadFile(String url, File file, OnResultCallBack callback) { - upLoadFile(url, file, null, callback); - } - - /** - * 上传单个文件 - * - * @param url 接口 - * @param file 文件 - * @param tag 标签 - * @param callback 回调 - */ - public void upLoadFile(String url, File file, String tag, ResponseCallback callback) { - //使用Part 方式上传文件 - checkBaseUrl(); - Logger.e(NetConfig.Url.getBaseUrl() + url + file.getAbsolutePath()); - builder.build().rxUploadWithPart(tag, url, file, callback); - } - - /** - * 上传多个文件 - * - * @param url 接口 - * @param files 文件 - * @param callback 回调 - */ - public void upLoadFile(String url, List files, OnResultCallBack callback) { - upLoadFile(url, files, null, callback); - } - - - /** - * 上传多个文件 - * - * @param url 接口 - * @param files 文件 - * @param tag 标签 - * @param callback 回调 - */ - public void upLoadFile(String url, List files, String tag, ResponseCallback callback) { - checkBaseUrl(); - Logger.e(NetConfig.Url.getBaseUrl() + url + files.size()); - builder.build().rxUploadWithPartListByFile(tag, url, files, callback); - } - - ////////////////////////////////////////// 下载文件 ///////////////////////////////////////////// - - /** - * 文件下载 - * - * @param url 文件路径 - * @param callBack 回调 - */ - public void downloadFile(String url, RxFileCallBack callBack) { - checkBaseUrl(); - Logger.e(NetConfig.Url.getBaseUrl() + url); - builder.build().rxDownload(url, callBack); - } - - /** - * 检查是否设置BaseURL - */ - private void checkBaseUrl() { - //如果没有设置请求BaseUrl 则使用默认的BaseUrl - if (TextUtils.isEmpty(baseUrl)) { - baseUrl = NetConfig.Url.getBaseUrl(); - } - builder.baseUrl(baseUrl); - } - -} diff --git a/common_base/src/main/java/com/wss/common/net/NetConfig.java b/common_base/src/main/java/com/wss/common/net/NetConfig.java deleted file mode 100644 index 47e26f2..0000000 --- a/common_base/src/main/java/com/wss/common/net/NetConfig.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.wss.common.net; - -import com.wss.common.constants.Constants; - - -/** - * Describe:网络请求URL - * Created by 吴天强 on 2017/9/26. - */ - -public class NetConfig { - - - /** - * 响应的返回key - */ - public class Code { - public static final String SUCCESS = "success"; - public static final String MSG = "errorMsg"; - public static final String CODE = "errorCode"; - public static final String MODEL = "data"; - } - - /** - * H5界面 - */ - public class Html { - - } - - /** - * 网络请求Url - */ - public static class Url { - - //自己服务器IP - public static String MY_SERVICE_URL = "http://sdk.xiaoyuyu.com.cn"; - - //服务器地址 - interface BaseUrl { - String SERVER_DEVELOP = "http://www.wanandroid.com"; - String SERVER_TEST = ""; - String SERVER_PRODUCTION = ""; - } - - /** - * 返回服务器基础地址 - */ - static String getBaseUrl() { - switch (Constants.SERVER_TYPE) { - case Constants.ServerType.SERVER_DEVELOP: - return BaseUrl.SERVER_DEVELOP; - case Constants.ServerType.SERVER_TEST: - return BaseUrl.SERVER_TEST; - case Constants.ServerType.SERVER_PRODUCTION: - return BaseUrl.SERVER_PRODUCTION; - } - return BaseUrl.SERVER_PRODUCTION; - } - - - } - -} diff --git a/common_base/src/main/java/com/wss/common/net/NetworkManage.java b/common_base/src/main/java/com/wss/common/net/NetworkManage.java new file mode 100644 index 0000000..c8ff90c --- /dev/null +++ b/common_base/src/main/java/com/wss/common/net/NetworkManage.java @@ -0,0 +1,617 @@ +package com.wss.common.net; + +import android.os.Handler; +import android.text.TextUtils; + +import com.orhanobut.logger.Logger; +import com.rxjava.rxlife.RxLife; +import com.wss.common.base.BaseApplication; +import com.wss.common.base.R; +import com.wss.common.constants.Constants; +import com.wss.common.exception.NetErrorException; +import com.wss.common.manage.ActivityToActivity; +import com.wss.common.net.request.RequestParam; +import com.wss.common.net.response.BaseResponse; +import com.wss.common.net.response.DownloadResponse; +import com.wss.common.profile.ProfileManager; +import com.wss.common.secret.AesUtils; +import com.wss.common.utils.JsonUtils; +import com.wss.common.utils.NetworkUtil; +import com.wss.common.utils.ToastUtils; +import com.wss.common.utils.Utils; +import com.wss.common.utils.ValidUtils; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.net.SocketTimeoutException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LifecycleOwner; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; +import rxhttp.wrapper.exception.HttpStatusCodeException; +import rxhttp.wrapper.param.RxHttp; +import rxhttp.wrapper.param.RxHttpFormParam; +import rxhttp.wrapper.param.RxHttpJsonParam; +import rxhttp.wrapper.param.RxHttpNoBodyParam; + + +/** + * Describe:网络请求帮助类 + * Created by 吴天强 on 2020/1/3. + */ +@SuppressWarnings("unchecked") +public class NetworkManage { + /** + * 取第一个进来的跳转到登录页 + */ + public volatile static int count = 0; + private static final String GET = "GET"; + private static final String POST_FORM = "POST_FORM"; + private static final String POST_JSON = "POST_JSON"; + private static final String PUT_FORM = "PUT_FORM"; + private static final String PUT_JSON = "PUT_JSON"; + private static final String DELETE_FORM = "DELETE_FORM"; + private static final String DELETE_JSON = "DELETE_JSON"; + /** + * 账户相关的报错信息 + */ + private static final List ACCOUNT_ERROR_CODE = new ArrayList<>(); + + /** + * 无须加密白名单 + */ + private static final List NO_DECRYPTION_LIST = new ArrayList<>(); + + static { + ACCOUNT_ERROR_CODE.add(Constants.Net.Status.CODE_ACCOUNT_DISABLE); + ACCOUNT_ERROR_CODE.add(Constants.Net.Status.CODE_ACCOUNT_QUIT); + ACCOUNT_ERROR_CODE.add(Constants.Net.Status.CODE_ACCOUNT_LOCKED); + ACCOUNT_ERROR_CODE.add(Constants.Net.Status.CODE_ACCOUNT_NO_AUTHORITY); + ACCOUNT_ERROR_CODE.add(Constants.Net.Status.CODE_ACCOUNT_NO_TEAM); + ACCOUNT_ERROR_CODE.add(Constants.Net.Status.CODE_ACCOUNT_MULTIPLE_TEAM); + ACCOUNT_ERROR_CODE.add(Constants.Net.Status.CODE_TOKEN_EXPIRED); + ACCOUNT_ERROR_CODE.add(Constants.Net.Status.CODE_ACCOUNT_POSITION_ERROR); + + NO_DECRYPTION_LIST.add(Api.UPLOAD_FILE); + NO_DECRYPTION_LIST.add(Api.DOWNLOAD_FILE); + } + + /** + * 构建Get请求 + */ + @NonNull + public static Request createGet() { + return create(GET); + } + + /** + * 构建PostFrom请求 + */ + @NonNull + public static Request createPostForm() { + return create(POST_FORM); + } + + /** + * 构建PostJson请求 + */ + @NonNull + public static Request createPostJson() { + return create(POST_JSON); + } + + /** + * 构建PutForm请求 + */ + @NonNull + public static Request createPutForm() { + return create(PUT_FORM); + } + + /** + * 构建PutJson请求 + */ + @NonNull + public static Request createPutJson() { + return create(PUT_JSON); + } + + /** + * 构建DeleteForm请求 + */ + @NonNull + public static Request createDeleteForm() { + return create(DELETE_FORM); + } + + /** + * 构建DeleteJson请求 + */ + @NonNull + public static Request createDeleteJson() { + return create(DELETE_JSON); + } + + + /** + * 构建请求类型 + */ + @Contract(value = "_ -> new", pure = true) + @NonNull + private static Request create(String method) { + return new Request(method); + } + + /** + * 网络请求主类 + */ + public static class Request { + private String method; + private String requestId; + + + Request(String method) { + this.method = method; + requestId = UUID.randomUUID().toString().replaceAll("-", ""); + } + + /** + * 无参请求返回String类型 + * + * @param life 声明周期实现类 + * @param url 请求URL + */ + public Observable request(LifecycleOwner life, String url) { + return request(life, url, null, (Class) String.class); + } + + /** + * 无参请求返回T类型 + * + * @param life 声明周期实现类 + * @param url 请求URL + * @param type 响应泛型类型 + */ + public Observable request(LifecycleOwner life, String url, Class type) { + return request(life, url, null, type); + } + + /** + * 有参请求返回String类型 + * + * @param life 声明周期实现类 + * @param url 请求URL + * @param param 请求参数 + */ + public Observable request(LifecycleOwner life, String url, RequestParam param) { + return request(life, url, param, (Class) String.class); + } + + /** + * 有参请求返回T类型 + * + * @param life 声明周期实现类 + * @param url 请求URLu + * @param param 请求参数 + * @param type 响应泛型类型 + */ + public Observable request(LifecycleOwner life, String url, RequestParam param, Class type) { + return Observable.create( + subscriber -> { + if (!NetworkUtil.isNetworkEnabled(BaseApplication.i())) { + //无可用网络 + subscriber.onError(new NetErrorException(BaseApplication.i().getString(R.string.network_error_no_net))); + return; + } + Disposable subscribe = checkRequest(url, param) + .as(RxLife.asOnMain(life)) //感知生命周期,并在主线程回调 + .subscribe(response -> + checkResponse(url, response).subscribe(baseResponse -> { + if (type == BaseResponse.class) { + subscriber.onNext((T) baseResponse); + } else if (type == String.class) { + subscriber.onNext((T) baseResponse.getData()); + } else { + //根据类型解析 + subscriber.onNext(JsonUtils.getObject(baseResponse.getData(), type)); + } + }, subscriber::onError), throwable -> subscriber.onError(handleError(throwable))); + BaseApplication.i().addNetDisposable(requestId, subscribe); + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + + /** + * 无参请求返回List类型 + * + * @param life 声明周期实现类 + * @param url 请求URL + * @param type 响应泛型类型 + */ + public Observable> requestList(LifecycleOwner life, String url, Class type) { + return requestList(life, url, null, type); + } + + /** + * 有参请求返回List类型 + * + * @param life 声明周期实现类 + * @param url 请求URL + * @param param 请求参数 + */ + public Observable> requestList(LifecycleOwner life, String url, RequestParam param) { + return requestList(life, url, param, (Class) String.class); + } + + /** + * 有参请求返回List类型 + * + * @param life 声明周期实现类 + * @param url 请求URL + * @param param 请求参数 + * @param type 响应泛型类型 + */ + public Observable> requestList(LifecycleOwner life, String url, RequestParam param, Class type) { + return Observable.>create( + subscriber -> { + if (!NetworkUtil.isNetworkEnabled(BaseApplication.i())) { + //无可用网络 + subscriber.onError(new NetErrorException(BaseApplication.i().getString(R.string.network_error_no_net))); + return; + } + Disposable subscribe = checkRequest(url, param) + .as(RxLife.asOnMain(life)) //感知生命周期,并在主线程回调 + .subscribe(response -> checkResponse(url, response).subscribe( + baseResponse -> subscriber.onNext(JsonUtils.getList(baseResponse.getData(), type)), + subscriber::onError), throwable -> subscriber.onError(handleError(throwable))); + BaseApplication.i().addNetDisposable(requestId, subscribe); + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + + + /** + * 下载文件 + * + * @param life 声明周期实现类 + * @param downloadUrl 文件的下载地址 + * @param localPath 本地保存的文件路径 + * @return 下载response + */ + public Observable requestDownload(LifecycleOwner life, String downloadUrl, String localPath) { + return Observable.create( + subscriber -> { + if (!NetworkUtil.isNetworkEnabled(BaseApplication.i())) { + //无可用网络 + subscriber.onError(new NetErrorException(BaseApplication.i().getString(R.string.network_error_no_net))); + return; + } + Logger.e("文件下载地址:" + downloadUrl); + DownloadResponse downloadResponse = new DownloadResponse(); + //下载失败,处理相关逻辑 + RxHttp.get(downloadUrl) + .asDownload(localPath, progress -> { + Logger.i("文件下载中," + progress); + //下载进度回调,0-100,仅在进度有更新时才会回调,最多回调101次,最后一次回调文件存储路径 + downloadResponse.setProgress(progress); + subscriber.onNext(downloadResponse); + }) + .observeOn(AndroidSchedulers.mainThread()) + .as(RxLife.as(life)) + .subscribe(s -> { + Logger.e("文件下载完成,保存:" + s); + //下载完成,处理相关逻辑 + downloadResponse.setSuccess(true); + subscriber.onNext(downloadResponse); + }, subscriber::onError); + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + + + /** + * 检查响应 + * + * @param apiUrl 接口地址 + * @param response 响应数据 + * @return BaseResponse + */ + private Observable checkResponse(String apiUrl, String response) { + return Observable.create(subscriber -> { + BaseApplication.i().removeNetDisposable(requestId); + Logger.e(String.format("Request-Id:%s\n响应:%s", requestId, response)); + String state = JsonUtils.getString(response, Constants.Net.STATE); + String message = JsonUtils.getString(response, Constants.Net.MESSAGE); + String data; + try { + //防止返回的data为null导致解析json失败 + data = JsonUtils.getString(response, Constants.Net.DATA); + } catch (Exception e) { + data = ""; + } + if (Constants.Net.Status.CODE_SUCCESS.equals(state)) { + subscriber.onNext(new BaseResponse(state, message, data)); + } else { + if (!Api.LOGIN.equals(apiUrl) && ACCOUNT_ERROR_CODE.contains(state)) { + //如果是非登录接口且错误码为定义的这部分,则需要跳转到登录页面 + synchronized (NetworkManage.class) { + //防止多个线程一瞬间进来了,让需要进来的进行排队 + if (count <= 0) { + //Token 过期 跳转登录页面 + toLoginActivity(message); + } + count++; + } + } else { + //接口返回 false 把message、data扔出去 + subscriber.onError(new NetErrorException(state, message, data)); + } + } + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + + + /** + * 网络请求之前参数检查,组装公共请求参数,加密等操作 + * + * @param url 接口地址 + * @param param 请求参数 + * @return Observable + */ + @NotNull + private Observable checkRequest(String url, RequestParam param) { + if (!ValidUtils.isValid(param)) { + param = new RequestParam(); + } + //打印请求 + Logger.e(String.format("Request-Id:%s\n%s %s%s\n请求参数:%s", requestId, method, Api.BASE_URL, url, JsonUtils.toJson(param.getParameter()))); + RxHttp rxHttp = buildRequest(url, param); + //添加Header + for (Map.Entry entry : buildHeader().entrySet()) { + rxHttp.addHeader(entry.getKey(), entry.getValue()); + } + return rxHttp.asString(); + } + + /** + * 构建请求 + * + * @param url 接口地址 + * @param param 请求参数 + * @return RxHttp + */ + private RxHttp buildRequest(String url, @NotNull RequestParam param) { + Map fileMap = new HashMap<>(16); + Map> fileListMap = new HashMap<>(16); + Map objectMap = new HashMap<>(16); + + //分离请求参数中的文件 + for (Map.Entry entry : param.getParameter().entrySet()) { + if (entry.getValue() instanceof File) { + //单个文件 + fileMap.put(entry.getKey(), (File) entry.getValue()); + continue; + } + if (entry.getValue() instanceof List && ((List) entry.getValue()).size() > 0) { + if (((List) entry.getValue()).get(0) instanceof File) { + //文件list + fileListMap.put(entry.getKey(), (List) entry.getValue()); + continue; + } + } + + if (entry.getValue() instanceof String) { + //把null转成"" + String value = String.valueOf(entry.getValue()); + if (!ValidUtils.isValid(value) || "null".equalsIgnoreCase(value)) { + value = ""; + } + objectMap.put(entry.getKey(), value); + continue; + } + objectMap.put(entry.getKey(), entry.getValue()); + } + + Map requestParam = new HashMap<>(); + String paramJson = JsonUtils.toJson(objectMap); + /* + *注:该加密方式为:把请求参数key、value以json的格式整体加密,然后再以key、value的形式发送给服务器 + */ + if (!NO_DECRYPTION_LIST.contains(url) && ProfileManager.profile().isSecret()) { + //请求是否需要加密 + requestParam.put(Constants.Net.REQUEST_DATA, AesUtils.getInstance().encrypt(paramJson)); + } else { + requestParam.put(Constants.Net.REQUEST_DATA, paramJson); + } + Logger.i(String.format("加密请求\nRequest-Id:%s\n%s %s%s\n请求参数:%s", + requestId, method, Api.BASE_URL, url, JsonUtils.toJson(requestParam))); + RxHttp rxHttp; + switch (method) { + case POST_JSON: + case PUT_JSON: + case DELETE_JSON: + //JSON格式请求 + if (TextUtils.equals(method, POST_JSON)) { + rxHttp = RxHttp.postJson(url); + } else if (TextUtils.equals(method, DELETE_JSON)) { + rxHttp = RxHttp.deleteJson(url); + } else { + rxHttp = RxHttp.putJson(url); + } + if (isUpLoadFile(url)) { + //上传文件传参特殊 + ((RxHttpJsonParam) rxHttp).addAll(objectMap); + } else { + ((RxHttpJsonParam) rxHttp).addAll(requestParam); + } + + //添加文件请求参数 + if (!fileMap.isEmpty()) { + for (Map.Entry entry : fileMap.entrySet()) { + ((RxHttpJsonParam) rxHttp).add(entry.getKey(), entry.getValue()); + } + } + if (!fileListMap.isEmpty()) { + for (Map.Entry> entry : fileListMap.entrySet()) { + ((RxHttpJsonParam) rxHttp).add(entry.getKey(), entry.getValue()); + } + } + break; + case POST_FORM: + case PUT_FORM: + case DELETE_FORM: + //POST格式请求 + if (TextUtils.equals(method, POST_FORM)) { + rxHttp = RxHttp.postForm(url); + } else if (TextUtils.equals(method, DELETE_FORM)) { + rxHttp = RxHttp.deleteForm(url); + } else { + rxHttp = RxHttp.putForm(url); + } + if (isUpLoadFile(url)) { + //上传文件传参特殊 + ((RxHttpFormParam) rxHttp).addAll(objectMap); + } else { + ((RxHttpFormParam) rxHttp).addAll(requestParam); + }//添加文件请求参数 + if (!fileMap.isEmpty()) { + for (Map.Entry entry : fileMap.entrySet()) { + ((RxHttpFormParam) rxHttp).addFile(entry.getKey(), entry.getValue()); + } + } + if (!fileListMap.isEmpty()) { + for (Map.Entry> entry : fileListMap.entrySet()) { + ((RxHttpFormParam) rxHttp).addFile(entry.getKey(), entry.getValue()); + } + } + break; + case GET: + default: + rxHttp = RxHttp.get(url); + ((RxHttpNoBodyParam) rxHttp).addAll(requestParam); + //添加文件请求参数 + if (!fileMap.isEmpty()) { + for (Map.Entry entry : fileMap.entrySet()) { + ((RxHttpNoBodyParam) rxHttp).add(entry.getKey(), entry.getValue()); + } + } + if (!fileListMap.isEmpty()) { + for (Map.Entry> entry : fileListMap.entrySet()) { + ((RxHttpNoBodyParam) rxHttp).add(entry.getKey(), entry.getValue()); + } + } + break; + } + return rxHttp; + } + + /** + * 构建请求头 + * + * @return 请求头Map + */ + @NotNull + private Map buildHeader() { + String deviceId = BaseApplication.i().getDeviceId(); + String token = BaseApplication.i().getLoginToken(); + Map header = new HashMap<>(); + header.put(Constants.Net.HEADER_CHANNEL, Constants.Common.CHANEL); + header.put(Constants.Net.HEADER_API_VERSION, Constants.Common.API_VERSION); + header.put(Constants.Net.HEADER_DEVICE_ID, ValidUtils.isValid(deviceId) ? deviceId : ""); + header.put(Constants.Net.HEADER_TOKEN, ValidUtils.isValid(token) ? token : ""); + header.put(Constants.Net.HEADER_APP_VERSION, Utils.getVersionName()); + header.put(Constants.Net.HEADER_IP, NetworkUtil.getIpAddress()); + header.put(Constants.Net.REQUEST_ID, requestId); + Logger.i("请求Header:\n" + JsonUtils.toJson(header)); + return header; + } + + /** + * 检查是否上传文件 + * + * @param url url + * @return boolean + */ + @Contract(value = "null -> false", pure = true) + private boolean isUpLoadFile(String url) { + return Api.UPLOAD_FILE.equals(url); + } + + + /** + * 处理网络请求中的异常 + * + * @param t Throwable + * @return NetErrorException + */ + @Contract("_ -> new") + @NotNull + private NetErrorException handleError(@NotNull Throwable t) { + BaseApplication.i().removeNetDisposable(requestId); + String errorMessage = null; + String loggerMessage = ""; + if (t instanceof SocketTimeoutException) { + errorMessage = BaseApplication.i().getString(R.string.request_time_out); + loggerMessage = errorMessage; + } else if (t instanceof HttpStatusCodeException) { + HttpStatusCodeException codeException = (HttpStatusCodeException) t; + try { + errorMessage = JsonUtils.getString(codeException.getResult(), Constants.Net.MESSAGE); + } catch (Exception e) { + errorMessage = BaseApplication.i().getString(R.string.network_error_server_error); + } + loggerMessage = String.format("%s %s", codeException.getStatusCode(), errorMessage); + } else { + loggerMessage = t.getMessage(); + } + if (!ValidUtils.isValid(errorMessage)) { + errorMessage = BaseApplication.i().getString(R.string.network_error_server_error); + } + Logger.e(String.format("Request-Id:%s\n请求报错:%s", requestId, loggerMessage)); + return new NetErrorException(errorMessage); + } + + /** + * 跳转登录页 + * + * @param errorMessage 错误信息 + */ + private void toLoginActivity(String errorMessage) { + Observable.create( + subscriber -> { + //检查是否存在未完成的请求,有就取消 + for (Map.Entry entry : BaseApplication.i().getNetDisposables().entrySet()) { + if (!entry.getValue().isDisposed()) { + entry.getValue().dispose(); + } + } + ToastUtils.show(errorMessage); + //延时1秒跳转到登录页,最大限度的,避免由于网络延时,带来的token过期退出到登录页的异常 + new Handler().postDelayed(() -> { + ActivityToActivity.toLoginActivity(BaseApplication.i()); + BaseApplication.i().loginOutClean(); + }, 500); + + }) + .subscribeOn(AndroidSchedulers.mainThread()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(); + } + + } +} diff --git a/common_base/src/main/java/com/wss/common/net/RequestParam.java b/common_base/src/main/java/com/wss/common/net/RequestParam.java deleted file mode 100644 index 6f2bf06..0000000 --- a/common_base/src/main/java/com/wss/common/net/RequestParam.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.wss.common.net; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.LinkedHashMap; -import java.util.Map; - - -/** - * Describe:请求参数封装类 - * Created by 吴天强 on 2017/9/19. - */ -public class RequestParam { - - private Map params; - - public RequestParam() { - params = new LinkedHashMap<>(); - } - - /** - * 普通文本参数 - * - * @param key key - * @param value 值 - */ - public void addParameter(String key, Object value) { - if (this.params == null) { - params = new LinkedHashMap<>(); - } - params.put(key, value); - } - - - public void addParameter(String key, int value) { - addParameter(key, String.valueOf(value)); - } - - public void addParameter(String key, long value) { - addParameter(key, String.valueOf(value)); - } - - public void addParameter(String key, float value) { - addParameter(key, String.valueOf(value)); - } - - public void addParameter(String key, double value) { - addParameter(key, String.valueOf(value)); - } - - /** - * 获取请求参数 - * - * @return Map - */ - public Map getParameter() { - if (null == params) { - params = new LinkedHashMap<>(); - } - return params; - } - - - /** - * 请求参数转Json - * - * @return String - */ - String toJson() { - JSONObject json = new JSONObject(); - for (Map.Entry entry : params.entrySet()) { - try { - json.put(entry.getKey(), entry.getValue()); - } catch (JSONException e) { - e.printStackTrace(); - } - } - return json.toString(); - } - - @Override - public String toString() { - StringBuilder stringBuffer = new StringBuilder(); - for (Map.Entry entry : params.entrySet()) { - stringBuffer.append(entry.getKey()); - stringBuffer.append(":"); - stringBuffer.append(entry.getValue()); - stringBuffer.append("\t"); - } - return stringBuffer.toString(); - } - -} diff --git a/common_base/src/main/java/com/wss/common/net/callback/OnResultCallBack.java b/common_base/src/main/java/com/wss/common/net/callback/OnResultCallBack.java deleted file mode 100644 index 627e4d4..0000000 --- a/common_base/src/main/java/com/wss/common/net/callback/OnResultCallBack.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.wss.common.net.callback; - - -import com.tamic.novate.Throwable; -import com.tamic.novate.callback.RxGenericsCallback; - -import java.io.IOException; - -import okhttp3.Call; -import okhttp3.ResponseBody; - -/** - * Describe:网络返回基类 - * Created by 吴天强 on 2017/9/26. - */ - -public abstract class OnResultCallBack extends RxGenericsCallback { - protected boolean success; - - @Override - public void onError(Object tag, Throwable e) { - e.printStackTrace(); - onFailure(tag, e); - } - - - @Override - public void onCancel(Object tag, Throwable e) { - } - - @Override - public void onFailure(Call call, IOException e) { - onFailure(tag, e); - } - - @Override - public void onNext(Object tag, int code, String message, T response) { - onSuccess(success, code, msg, tag, response); - } - - @Override - public void onCompleted(Object tag) { - super.onCompleted(tag); - onCompleted(); - } - - public abstract void onSuccess(boolean success, int code, String msg, Object tag, T response); - - public abstract void onFailure(Object tag, Exception e); - - public abstract void onCompleted(); - -} diff --git a/common_base/src/main/java/com/wss/common/net/callback/OnResultListCallBack.java b/common_base/src/main/java/com/wss/common/net/callback/OnResultListCallBack.java deleted file mode 100644 index a113abb..0000000 --- a/common_base/src/main/java/com/wss/common/net/callback/OnResultListCallBack.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.wss.common.net.callback; - -import com.alibaba.fastjson.JSON; -import com.google.gson.Gson; -import com.orhanobut.logger.Logger; -import com.wss.common.net.NetConfig; - -import org.json.JSONObject; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; - -import okhttp3.ResponseBody; - -/** - * Describe:返回数组类型数据 - * Created by 吴天强 on 2017/9/28. - */ - -public abstract class OnResultListCallBack extends OnResultCallBack { - - private Type collectionType; - - @Override - public T onHandleResponse(ResponseBody response) throws Exception { - if (collectionType == null) { - collectionType = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; - } - return transform(new String(response.bytes()), null); - } - - public T transform(String response, final Class classOfT) throws ClassCastException { - Logger.e(JSON.toJSONString(response)); - try { - JSONObject jsonObject = new JSONObject(response); - code = jsonObject.optInt(NetConfig.Code.CODE); - msg = jsonObject.optString(NetConfig.Code.MSG); - success = jsonObject.optBoolean(NetConfig.Code.SUCCESS); - dataStr = jsonObject.opt(NetConfig.Code.MODEL).toString(); - dataResponse = new Gson().fromJson(dataStr, collectionType); - } catch (Exception e) { - e.printStackTrace(); - } - - return dataResponse; - } -} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/net/callback/OnResultObjectCallBack.java b/common_base/src/main/java/com/wss/common/net/callback/OnResultObjectCallBack.java deleted file mode 100644 index 151c250..0000000 --- a/common_base/src/main/java/com/wss/common/net/callback/OnResultObjectCallBack.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.wss.common.net.callback; - -import com.google.gson.Gson; -import com.orhanobut.logger.Logger; -import com.wss.common.net.NetConfig; - -import org.json.JSONObject; - -import java.lang.reflect.ParameterizedType; - -import okhttp3.ResponseBody; - -/** - * Describe:返回对象类型数据 - * Created by 吴天强 on 2017/9/28. - */ - -public abstract class OnResultObjectCallBack extends OnResultCallBack { - - @Override - public T onHandleResponse(ResponseBody response) throws Exception { - Class entityClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; - return transform(new String(response.bytes()), entityClass); - } - - public T transform(String response, final Class classOfT) throws ClassCastException { - Logger.e(response); - try { - JSONObject jsonObject = new JSONObject(response); - - code = jsonObject.optInt(NetConfig.Code.CODE); - msg = jsonObject.optString(NetConfig.Code.MSG); - success = jsonObject.optBoolean(NetConfig.Code.SUCCESS); - dataStr = jsonObject.opt(NetConfig.Code.MODEL).toString(); - dataResponse = (T) new Gson().fromJson(dataStr, classOfT); - } catch (Exception e) { - e.printStackTrace(); - } - return dataResponse; - } -} - diff --git a/common_base/src/main/java/com/wss/common/net/callback/OnResultStringCallBack.java b/common_base/src/main/java/com/wss/common/net/callback/OnResultStringCallBack.java deleted file mode 100644 index eec4ce6..0000000 --- a/common_base/src/main/java/com/wss/common/net/callback/OnResultStringCallBack.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.wss.common.net.callback; - -import com.alibaba.fastjson.JSON; -import com.orhanobut.logger.Logger; -import com.wss.common.net.NetConfig; - -import org.json.JSONObject; - -import okhttp3.ResponseBody; - -/** - * Describe:String类型数据解析 - * Created by 吴天强 on 2017/9/28. - */ - -public abstract class OnResultStringCallBack extends OnResultCallBack { - - @Override - public String onHandleResponse(ResponseBody response) throws Exception { - return transform(new String(response.bytes())); - } - - private String transform(String response) { - Logger.e(JSON.toJSONString(response)); - try { - JSONObject jsonObject = new JSONObject(response); - code = jsonObject.optInt(NetConfig.Code.CODE); - msg = jsonObject.optString(NetConfig.Code.MSG); - success = jsonObject.optBoolean(NetConfig.Code.SUCCESS); - dataStr = jsonObject.opt(NetConfig.Code.MODEL).toString(); - dataResponse = dataStr; - } catch (Exception e) { - e.printStackTrace(); - } - return dataResponse; - } - -} diff --git a/common_base/src/main/java/com/wss/common/net/request/RequestParam.java b/common_base/src/main/java/com/wss/common/net/request/RequestParam.java new file mode 100644 index 0000000..5d0e5b4 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/net/request/RequestParam.java @@ -0,0 +1,133 @@ +package com.wss.common.net.request; + +import org.jetbrains.annotations.NotNull; + +import java.util.LinkedHashMap; +import java.util.Map; + + +/** + * Describe:请求参数封装类 + * Created by 吴天强 on 2017/9/19. + */ +public class RequestParam { + + /** + * 存放请求参数的Map + */ + private Map params; + + public RequestParam() { + params = new LinkedHashMap<>(); + } + + /** + * 添加请求参数 + * + * @param key key + * @param value 值 + */ + private void buildParameter(String key, Object value) { + if (this.params == null) { + params = new LinkedHashMap<>(); + } + params.put(key, value); + } + + /** + * 添加普通文本 + * + * @param key key + * @param value 值 + */ + public void addParameter(String key, String value) { + buildParameter(key, value); + } + + /** + * 添加int类型 + * + * @param key key + * @param value 值 + */ + public void addParameter(String key, Integer value) { + buildParameter(key, value); + } + + /** + * 添加long类型 + * + * @param key key + * @param value 值 + */ + public void addParameter(String key, Long value) { + buildParameter(key, value); + } + + /** + * 添加float类型 + * + * @param key key + * @param value 值 + */ + public void addParameter(String key, Float value) { + buildParameter(key, value); + } + + /** + * 添加double类型 + * + * @param key key + * @param value 值 + */ + public void addParameter(String key, Double value) { + buildParameter(key, value); + } + + /** + * 添加boolean类型 + * + * @param key key + * @param value 值 + */ + public void addParameter(String key, Boolean value) { + buildParameter(key, value); + } + + /** + * 添加Object类型 + * + * @param key key + * @param value 值 + */ + public void addParameter(String key, Object value) { + buildParameter(key, value); + } + + /** + * 获取请求参数 + * + * @return Map + */ + public Map getParameter() { + if (null == params) { + params = new LinkedHashMap<>(); + } + return params; + } + + + @NotNull + @Override + public String toString() { + StringBuilder stringBuffer = new StringBuilder(); + for (Map.Entry entry : params.entrySet()) { + stringBuffer.append(entry.getKey()); + stringBuffer.append(":"); + stringBuffer.append(entry.getValue()); + stringBuffer.append("\t"); + } + return stringBuffer.toString(); + } + +} diff --git a/common_base/src/main/java/com/wss/common/net/response/BaseResponse.java b/common_base/src/main/java/com/wss/common/net/response/BaseResponse.java new file mode 100644 index 0000000..08f2acd --- /dev/null +++ b/common_base/src/main/java/com/wss/common/net/response/BaseResponse.java @@ -0,0 +1,34 @@ +package com.wss.common.net.response; + + +import com.wss.common.base.bean.BaseBean; + +import lombok.Getter; +import lombok.Setter; + +/** + * Describe:响应基类 + * Created by 吴天强 on 2020/5/6. + */ +@Getter +@Setter +public class BaseResponse extends BaseBean { + /** + * 响应码 + */ + private String code; + /** + * 响应message + */ + private String msg; + /** + * 响应数据 + */ + private String data; + + public BaseResponse(String code, String msg, String data) { + this.code = code; + this.msg = msg; + this.data = data; + } +} diff --git a/common_base/src/main/java/com/wss/common/net/response/DownloadResponse.java b/common_base/src/main/java/com/wss/common/net/response/DownloadResponse.java new file mode 100644 index 0000000..2ad97dc --- /dev/null +++ b/common_base/src/main/java/com/wss/common/net/response/DownloadResponse.java @@ -0,0 +1,25 @@ +package com.wss.common.net.response; + + +import com.wss.common.base.bean.BaseBean; + +import lombok.Getter; +import lombok.Setter; +import rxhttp.wrapper.entity.Progress; + +/** + * Describe:下载文件响应 + * Created by 吴天强 on 2021/5/10. + */ +@Getter +@Setter +public class DownloadResponse extends BaseBean { + /** + * 下载文件进度对象 + */ + private Progress progress; + /** + * 是否下载完成 + */ + private boolean success; +} diff --git a/common_base/src/main/java/com/wss/common/profile/IProfile.java b/common_base/src/main/java/com/wss/common/profile/IProfile.java new file mode 100644 index 0000000..4e9839d --- /dev/null +++ b/common_base/src/main/java/com/wss/common/profile/IProfile.java @@ -0,0 +1,31 @@ +package com.wss.common.profile; + +/** + * Describe:编译环境相关的配置 + * 该类定义 由APP模块的具体实现类创建不同环境的配置 + * Created by 吴天强 on 2019/5/23. + */ +public interface IProfile { + + /** + * 服务地址 + * + * @return API地址 + */ + String getServiceBase(); + + /** + * 请求是否加密 + * + * @return boolean + */ + boolean isSecret(); + + /** + * 返回Aes加解密key + * + * @return key + */ + String getAesSecretKey(); + +} diff --git a/common_base/src/main/java/com/wss/common/profile/IProfileFactory.java b/common_base/src/main/java/com/wss/common/profile/IProfileFactory.java new file mode 100644 index 0000000..af8a080 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/profile/IProfileFactory.java @@ -0,0 +1,15 @@ +package com.wss.common.profile; + +/** + * Describe:环境配置工厂接口 + * Created by 吴天强 on 2019/5/23. + */ +public interface IProfileFactory { + + /** + * 创建配置文件 + * + * @return 配置文件 + */ + IProfile createProfile(); +} diff --git a/common_base/src/main/java/com/wss/common/profile/ProfileManager.java b/common_base/src/main/java/com/wss/common/profile/ProfileManager.java new file mode 100644 index 0000000..65895bb --- /dev/null +++ b/common_base/src/main/java/com/wss/common/profile/ProfileManager.java @@ -0,0 +1,41 @@ +package com.wss.common.profile; + +/** + * Describe:编译环境相关的配置 管理类 + * Created by 吴天强 on 2019/5/23. + */ +public class ProfileManager { + + private IProfileFactory mFactory; + private IProfile mProfile; + public static final ProfileManager inst; + + public void factory(IProfileFactory factory) { + this.mFactory = factory; + } + + public static IProfile profile() { + return inst.getProfile(); + } + + private IProfile getProfile() { + if (this.mProfile == null) { + this.mProfile = this.mFactory.createProfile(); + } + return this.mProfile; + } + + private ProfileManager() { + } + + static { + inst = Holder.holder; + } + + private static final class Holder { + private static final ProfileManager holder = new ProfileManager(); + + private Holder() { + } + } +} diff --git a/common_base/src/main/java/com/wss/common/secret/AesUtils.java b/common_base/src/main/java/com/wss/common/secret/AesUtils.java new file mode 100644 index 0000000..bad264b --- /dev/null +++ b/common_base/src/main/java/com/wss/common/secret/AesUtils.java @@ -0,0 +1,104 @@ +package com.wss.common.secret;//package com.xincheng.common.secret; + + +import com.wss.common.profile.ProfileManager; + +import org.bouncycastle.util.encoders.Base64; + +import java.net.URLEncoder; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + + +/** + * Describe:AES 加解密操作 + * Created by 吴天强 on 2018-08-03 17:47 + **/ +public class AesUtils { + + private static final String ALGORITHM = "AES/ECB/PKCS5Padding"; + private static final String KEY = ProfileManager.profile().getAesSecretKey(); + + private static AesUtils aesUtils; + + private AesUtils() { + } + + public static AesUtils getInstance() { + if (aesUtils == null) { + synchronized (AesUtils.class) { + if (aesUtils == null) { + aesUtils = new AesUtils(); + } + } + } + return aesUtils; + } + + /** + * 获取秘钥方法 + */ + private byte[] getKey() { + KeyGenerator kg; + try { + kg = KeyGenerator.getInstance("AES"); + kg.init(192); + SecretKey sk = kg.generateKey(); + byte[] b = sk.getEncoded(); + System.out.println("KEY---------" + new String(Base64.encode(b))); + return b; + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return null; + } + + /** + * AES加密方法 + * + * @param str 需要加密的字符串 + * @return 加密后数据 + */ + public String encrypt(String str) { + byte[] result; + try { + Cipher cipher = Cipher.getInstance(ALGORITHM); + //生成加密解密需要的Key + SecretKeySpec keySpec = new SecretKeySpec(Base64.decode(KEY.getBytes()), "AES"); + cipher.init(Cipher.ENCRYPT_MODE, keySpec); + result = cipher.doFinal(str.getBytes("UTF-8")); + return URLEncoder.encode(new String(Base64.encode(result)), "UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + + /** + * AES解密方法 + * + * @param str 需要加密的字符串 + * @return 解密后数据 + */ + public String decrypt(String str) { + String result = null; + try { + Cipher cipher = Cipher.getInstance(ALGORITHM); + SecretKeySpec keySpec = new SecretKeySpec(Base64.decode(KEY.getBytes()), "AES"); + cipher.init(Cipher.DECRYPT_MODE, keySpec); + byte[] decoded = cipher.doFinal(Base64.decode(str.getBytes())); + result = new String(decoded, "UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } + +} + + diff --git a/common_base/src/main/java/com/wss/common/secret/MD5.java b/common_base/src/main/java/com/wss/common/secret/MD5.java new file mode 100644 index 0000000..e8e9abf --- /dev/null +++ b/common_base/src/main/java/com/wss/common/secret/MD5.java @@ -0,0 +1,64 @@ +package com.wss.common.secret; + + +import org.jetbrains.annotations.NotNull; + +import java.security.MessageDigest; + +/** + * Describe:MD5加密 + * Created by 吴天强 on 2017/10/9. + */ +public class MD5 { + /** + * 生成md5 + * + * @param message 加密字段 + * @return String + */ + @NotNull + public static String getMD5(String message) { + String md5str = ""; + try { + // 1 创建一个提供信息摘要算法的对象,初始化为md5算法对象 + MessageDigest md = MessageDigest.getInstance("MD5"); + // 2 将消息变成byte数组 + byte[] input = message.getBytes(); + // 3 计算后获得字节数组,这就是那128位了 + byte[] buff = md.digest(input); + // 4 把数组每一字节(一个字节占八位)换成16进制连成md5字符串 + md5str = bytesToHex(buff); + + } catch (Exception e) { + e.printStackTrace(); + } + return md5str.toLowerCase(); + } + + /** + * 二进制转十六进制 + * + * @param bytes bytes + * @return String + */ + @NotNull + private static String bytesToHex(@NotNull byte[] bytes) { + StringBuilder md5str = new StringBuilder(); + // 把数组每一字节换成16进制连成md5字符串 + int digital; + for (byte aByte : bytes) { + digital = aByte; + + if (digital < 0) { + digital += 256; + } + if (digital < 16) { + md5str.append("0"); + } + md5str.append(Integer.toHexString(digital)); + } + return md5str.toString().toUpperCase(); + } + + +} diff --git a/common_base/src/main/java/com/wss/common/secret/ParseSystemUtil.java b/common_base/src/main/java/com/wss/common/secret/ParseSystemUtil.java new file mode 100644 index 0000000..bfc5d44 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/secret/ParseSystemUtil.java @@ -0,0 +1,50 @@ +package com.wss.common.secret; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Describe:16进制与二进制转换类 + * Created by 吴天强 on 2018-08-03 16:31 + **/ +public class ParseSystemUtil { + /** + * 将二进制转换成16进制 + * + * @param buf 数据 + * @return String + */ + @NotNull + public static String parseByte2HexStr(@NotNull byte[] buf) { + StringBuilder sb = new StringBuilder(); + for (byte b : buf) { + String hex = Integer.toHexString(b & 0xFF); + if (hex.length() == 1) { + hex = '0' + hex; + } + sb.append(hex.toUpperCase()); + } + return sb.toString(); + } + + /** + * 将16进制转换为二进制 + * + * @param hexStr 数据 + * @return byte[] + */ + @Nullable + public static byte[] parseHexStr2Byte(@NotNull String hexStr) { + if (hexStr.length() < 1) + return null; + byte[] result = new byte[hexStr.length() / 2]; + for (int i = 0; i < hexStr.length() / 2; i++) { + int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16); + int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16); + result[i] = (byte) (high * 16 + low); + } + return result; + } +} + + diff --git a/common_base/src/main/java/com/wss/common/utils/ARouterUtils.java b/common_base/src/main/java/com/wss/common/utils/ARouterUtils.java index eb0af33..ff5eebb 100644 --- a/common_base/src/main/java/com/wss/common/utils/ARouterUtils.java +++ b/common_base/src/main/java/com/wss/common/utils/ARouterUtils.java @@ -8,10 +8,8 @@ * Describe:ARouter帮助类 * Created by 吴天强 on 2018/11/13. */ - public class ARouterUtils { - /** * 根据path返回Fragment * diff --git a/common_base/src/main/java/com/wss/common/utils/ActivityToActivity.java b/common_base/src/main/java/com/wss/common/utils/ActivityToActivity.java deleted file mode 100644 index 1ceefed..0000000 --- a/common_base/src/main/java/com/wss/common/utils/ActivityToActivity.java +++ /dev/null @@ -1,162 +0,0 @@ -package com.wss.common.utils; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.text.TextUtils; - -import com.alibaba.android.arouter.facade.Postcard; -import com.alibaba.android.arouter.launcher.ARouter; -import com.wss.common.activity.WebViewActivity; -import com.wss.common.base.bean.BaseBean; -import com.wss.common.bean.Template; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -/** - * Describe:Activity跳转 - * Created by 吴天强 on 2018/10/22. - */ - -public class ActivityToActivity { - - - /** - * 通过模板跳转Activity - * - * @param activity activity - * @param template 模板信息 - */ - @SuppressWarnings("unchecked") - public static void toActivity(Context activity, Template template) { - switch (template.getType()) { - case 0: - //跳转Activity - toActivity(activity, template.getClazz(), template.getParams()); - break; - case 1: - //跳转其他业务模块 - toActivity(template.getUrl(), template.getParams()); - break; - case 2: - //跳转普通WebView - toWebView(activity, template.getUrl()); - break; - } - } - - /** - * 跳转普通WebView - * - * @param activity activity - * @param url 目标Url - */ - public static void toWebView(Context activity, String url) { - WebViewActivity.actionStart(activity, url); - } - - - /** - * 普通Activity之间跳转 - * - * @param activity activity - * @param clazz 目标activity - */ - public static void toActivity(Context activity, Class clazz) { - toActivity(activity, clazz, null); - } - - /** - * 普通Activity之间跳转 - * - * @param activity activity - * @param clazz 目标activity - * @param params 参数 - */ - public static void toActivity(Context activity, Class clazz, - Map params) { - Intent intent = new Intent(activity, clazz); - if (params != null) { - for (Map.Entry entry : params.entrySet()) { - String key = entry.getKey(); - Object value = params.get(key); - if (value instanceof String) { - intent.putExtra(key, (String) value); - } else if (value instanceof Boolean) { - intent.putExtra(key, (boolean) value); - } else if (value instanceof Integer) { - intent.putExtra(key, (int) value); - } else if (value instanceof Float) { - intent.putExtra(key, (float) value); - } else if (value instanceof Double) { - intent.putExtra(key, (double) value); - } else if (value instanceof Long) { - intent.putExtra(key, (long) value); - } else if (value instanceof Short) { - intent.putExtra(key, (short) value); - } else if (value instanceof BaseBean) { - intent.putExtra(key, (BaseBean) value); - } else if (value instanceof ArrayList) { - intent.putExtra(key, (ArrayList) value); - } else if (value instanceof HashMap) { - intent.putExtra(key, (HashMap) value); - } - } - } - activity.startActivity(intent); - } - - - /** - * ARouter跳转Activity - * - * @param url 目标Activity Url - */ - public static void toActivity(String url) { - toActivity(url, null); - } - - /** - * ARouter跳转Activity - * - * @param url 目标Activity Url - * @param params 参数 - */ - public static void toActivity(String url, Map params) { - if (TextUtils.isEmpty(url)) { - return; - } - Postcard postcard = ARouter.getInstance() - .build(url); - if (params != null) { - for (Map.Entry entry : params.entrySet()) { - String key = entry.getKey(); - Object value = params.get(key); - if (value instanceof String) { - postcard.withString(key, (String) value); - } else if (value instanceof Boolean) { - postcard.withBoolean(key, (boolean) value); - } else if (value instanceof Integer) { - postcard.withInt(key, (int) value); - } else if (value instanceof Float) { - postcard.withFloat(key, (float) value); - } else if (value instanceof Double) { - postcard.withDouble(key, (double) value); - } else if (value instanceof Long) { - postcard.withLong(key, (long) value); - } else if (value instanceof Short) { - postcard.withShort(key, (short) value); - } else if (value instanceof BaseBean) { - postcard.withSerializable(key, (BaseBean) value); - } else if (value instanceof ArrayList) { - postcard.withSerializable(key, (ArrayList) value); - } else if (value instanceof HashMap) { - postcard.withSerializable(key, (HashMap) value); - } - } - } - postcard.navigation(); - } -} diff --git a/common_base/src/main/java/com/wss/common/utils/BasicThreadFactory.java b/common_base/src/main/java/com/wss/common/utils/BasicThreadFactory.java new file mode 100644 index 0000000..0c0302b --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/BasicThreadFactory.java @@ -0,0 +1,14 @@ +package com.wss.common.utils; + +import java.util.concurrent.ThreadFactory; + +/** + * Describe: + * Created by 吴天强 on 2020/8/27. + */ +public class BasicThreadFactory implements ThreadFactory { + @Override + public Thread newThread(Runnable r) { + return null; + } +} diff --git a/common_base/src/main/java/com/wss/common/utils/BeanCopyUtils.java b/common_base/src/main/java/com/wss/common/utils/BeanCopyUtils.java index 8020fc7..7cbaf2f 100644 --- a/common_base/src/main/java/com/wss/common/utils/BeanCopyUtils.java +++ b/common_base/src/main/java/com/wss/common/utils/BeanCopyUtils.java @@ -42,4 +42,7 @@ public static T copy(T src) { } return dist; } + + + } \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/utils/CacheUtils.java b/common_base/src/main/java/com/wss/common/utils/CacheUtils.java index 426841e..bfe02b3 100644 --- a/common_base/src/main/java/com/wss/common/utils/CacheUtils.java +++ b/common_base/src/main/java/com/wss/common/utils/CacheUtils.java @@ -8,6 +8,9 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.json.JSONArray; import org.json.JSONObject; @@ -40,35 +43,40 @@ * Describe:缓存工具类。。。能缓存普通的字符串、JsonObject、JsonArray、 Bitmap、Drawable、序列化的java对象,和 byte数据。 * Created by 吴天强 on 2017/10/9. */ - public class CacheUtils { - public static final int TIME_MINUTE = 60; - public static final int TIME_HOUR = 60 * 60; - public static final int TIME_DAY = TIME_HOUR * 24; + private static final int TIME_MINUTE = 60; + private static final int TIME_HOUR = 60 * TIME_MINUTE; + private static final int TIME_DAY = TIME_HOUR * 24; + private static final int MAX_TIME_OUT = 90 * TIME_DAY;//最大缓存90天 private static final int MAX_SIZE = 1000 * 1000 * 50; // 50 mb private static final int MAX_COUNT = Integer.MAX_VALUE; // 不限制存放数据的数量 private static Map mInstanceMap = new HashMap<>(); private ACacheManager mCache; + @NotNull public static CacheUtils get(Context ctx) { return get(ctx, CacheUtils.class.getSimpleName()); } - public static CacheUtils get(Context ctx, String cacheName) { + @NotNull + public static CacheUtils get(@NotNull Context ctx, String cacheName) { File f = new File(ctx.getCacheDir(), cacheName); return get(f, MAX_SIZE, MAX_COUNT); } + @NotNull public static CacheUtils get(File cacheDir) { return get(cacheDir, MAX_SIZE, MAX_COUNT); } - public static CacheUtils get(Context ctx, long max_zise, int max_count) { + @NotNull + public static CacheUtils get(@NotNull Context ctx, long max_zise, int max_count) { File f = new File(ctx.getCacheDir(), CacheUtils.class.getSimpleName()); return get(f, max_zise, max_count); } - public static CacheUtils get(File cacheDir, long max_zise, int max_count) { + @NotNull + public static CacheUtils get(@NotNull File cacheDir, long max_zise, int max_count) { CacheUtils manager = mInstanceMap.get(cacheDir.getAbsoluteFile() + myPid()); if (manager == null) { manager = new CacheUtils(cacheDir, max_zise, max_count); @@ -77,11 +85,12 @@ public static CacheUtils get(File cacheDir, long max_zise, int max_count) { return manager; } + @NotNull private static String myPid() { return "_" + android.os.Process.myPid(); } - private CacheUtils(File cacheDir, long max_size, int max_count) { + private CacheUtils(@NotNull File cacheDir, long max_size, int max_count) { if (!cacheDir.exists() && !cacheDir.mkdirs()) { throw new RuntimeException("can't make dirs in " + cacheDir.getAbsolutePath()); @@ -117,6 +126,16 @@ public void close() throws IOException { // ============ String数据 读写 ============== // ======================================= + /** + * 保存 String数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的String数据 + */ + public void put(String key, boolean value) { + put(key, String.valueOf(value)); + } + /** * 保存 String数据 到 缓存中 * @@ -124,11 +143,23 @@ public void close() throws IOException { * @param value 保存的String数据 */ public void put(String key, String value) { + put(key, value, MAX_TIME_OUT); + } + + /** + * 保存 String数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的String数据 + * @param saveTime 保存的时间,单位:秒 + */ + public void put(String key, String value, int saveTime) { + String values = Utils.newStringWithDateInfo(saveTime, value); File file = mCache.newFile(key); BufferedWriter out = null; try { out = new BufferedWriter(new FileWriter(file), 1024); - out.write(value); + out.write(values); } catch (IOException e) { e.printStackTrace(); } finally { @@ -144,17 +175,6 @@ public void put(String key, String value) { } } - /** - * 保存 String数据 到 缓存中 - * - * @param key 保存的key - * @param value 保存的String数据 - * @param saveTime 保存的时间,单位:秒 - */ - public void put(String key, String value, int saveTime) { - put(key, Utils.newStringWithDateInfo(saveTime, value)); - } - /** * 读取 String数据 * @@ -196,6 +216,9 @@ public String getAsString(String key) { } } + public boolean getAsBoolean(String key) { + return Boolean.parseBoolean(getAsString(key)); + } // ======================================= // ============= JSONObject 数据 读写 ============== // ======================================= @@ -206,7 +229,7 @@ public String getAsString(String key) { * @param key 保存的key * @param value 保存的JSON数据 */ - public void put(String key, JSONObject value) { + public void put(String key, @NotNull JSONObject value) { put(key, value.toString()); } @@ -217,7 +240,7 @@ public void put(String key, JSONObject value) { * @param value 保存的JSONObject数据 * @param saveTime 保存的时间,单位:秒 */ - public void put(String key, JSONObject value, int saveTime) { + public void put(String key, @NotNull JSONObject value, int saveTime) { put(key, value.toString(), saveTime); } @@ -248,7 +271,7 @@ public JSONObject getAsJSONObject(String key) { * @param key 保存的key * @param value 保存的JSONArray数据 */ - public void put(String key, JSONArray value) { + public void put(String key, @NotNull JSONArray value) { put(key, value.toString()); } @@ -259,7 +282,7 @@ public void put(String key, JSONArray value) { * @param value 保存的JSONArray数据 * @param saveTime 保存的时间,单位:秒 */ - public void put(String key, JSONArray value, int saveTime) { + public void put(String key, @NotNull JSONArray value, int saveTime) { put(key, value.toString(), saveTime); } @@ -388,13 +411,13 @@ public byte[] getAsBinary(String key) { // ======================================= /** - * 保存 Serializable数据 到 缓存中 + * 保存 Serializable数据 到 缓存中 默认保存90天 * * @param key 保存的key * @param value 保存的value */ public void put(String key, Serializable value) { - put(key, value, -1); + put(key, value, MAX_TIME_OUT); } /** @@ -581,8 +604,7 @@ public class ACacheManager { private final AtomicInteger cacheCount; private final long sizeLimit; private final int countLimit; - private final Map lastUsageDates = Collections - .synchronizedMap(new HashMap()); + private final Map lastUsageDates = Collections.synchronizedMap(new HashMap<>()); protected File cacheDir; private ACacheManager(File cacheDir, long sizeLimit, int countLimit) { @@ -598,22 +620,19 @@ private ACacheManager(File cacheDir, long sizeLimit, int countLimit) { * 计算 cacheSize和cacheCount */ private void calculateCacheSizeAndCacheCount() { - new Thread(new Runnable() { - @Override - public void run() { - int size = 0; - int count = 0; - File[] cachedFiles = cacheDir.listFiles(); - if (cachedFiles != null) { - for (File cachedFile : cachedFiles) { - size += calculateSize(cachedFile); - count += 1; - lastUsageDates.put(cachedFile, - cachedFile.lastModified()); - } - cacheSize.set(size); - cacheCount.set(count); + new Thread(() -> { + int size = 0; + int count = 0; + File[] cachedFiles = cacheDir.listFiles(); + if (cachedFiles != null) { + for (File cachedFile : cachedFiles) { + size += calculateSize(cachedFile); + count += 1; + lastUsageDates.put(cachedFile, + cachedFile.lastModified()); } + cacheSize.set(size); + cacheCount.set(count); } }).start(); } @@ -636,21 +655,24 @@ private void put(File file) { } cacheSize.addAndGet(valueSize); - Long currentTime = System.currentTimeMillis(); + long currentTime = System.currentTimeMillis(); file.setLastModified(currentTime); lastUsageDates.put(file, currentTime); } + @NotNull private File get(String key) { File file = newFile(key); - Long currentTime = System.currentTimeMillis(); + long currentTime = System.currentTimeMillis(); file.setLastModified(currentTime); lastUsageDates.put(file, currentTime); return file; } - private File newFile(String key) { + @NotNull + @Contract("_ -> new") + private File newFile(@NotNull String key) { return new File(cacheDir, key.hashCode() + ""); } @@ -705,7 +727,7 @@ private long removeNext() { return fileSize; } - private long calculateSize(File file) { + private long calculateSize(@NotNull File file) { return file.length(); } } @@ -723,7 +745,7 @@ private static class Utils { * @param str * @return true:到期了 false:还没有到期 */ - private static boolean isDue(String str) { + private static boolean isDue(@NotNull String str) { return isDue(str.getBytes()); } @@ -750,11 +772,13 @@ private static boolean isDue(byte[] data) { return false; } + @NotNull private static String newStringWithDateInfo(int second, String strInfo) { return createDateInfo(second) + strInfo; } - private static byte[] newByteArrayWithDateInfo(int second, byte[] data2) { + @NotNull + private static byte[] newByteArrayWithDateInfo(int second, @NotNull byte[] data2) { byte[] data1 = createDateInfo(second).getBytes(); byte[] retdata = new byte[data1.length + data2.length]; System.arraycopy(data1, 0, retdata, 0, data1.length); @@ -762,6 +786,7 @@ private static byte[] newByteArrayWithDateInfo(int second, byte[] data2) { return retdata; } + @Contract("null -> null") private static String clearDateInfo(String strInfo) { if (strInfo != null && hasDateInfo(strInfo.getBytes())) { strInfo = strInfo.substring(strInfo.indexOf(mSeparator) + 1, @@ -778,11 +803,13 @@ private static byte[] clearDateInfo(byte[] data) { return data; } + @Contract(value = "null -> false", pure = true) private static boolean hasDateInfo(byte[] data) { return data != null && data.length > 15 && data[13] == '-' && indexOf(data, mSeparator) > 14; } + @Nullable private static String[] getDateInfoFromDate(byte[] data) { if (hasDateInfo(data)) { String saveDate = new String(copyOfRange(data, 0, 13)); @@ -793,6 +820,7 @@ private static String[] getDateInfoFromDate(byte[] data) { return null; } + @Contract(pure = true) private static int indexOf(byte[] data, char c) { for (int i = 0; i < data.length; i++) { if (data[i] == c) { @@ -802,6 +830,7 @@ private static int indexOf(byte[] data, char c) { return -1; } + @NotNull private static byte[] copyOfRange(byte[] original, int from, int to) { int newLength = to - from; if (newLength < 0) @@ -815,9 +844,9 @@ private static byte[] copyOfRange(byte[] original, int from, int to) { private static final char mSeparator = ' '; private static String createDateInfo(int second) { - String currentTime = System.currentTimeMillis() + ""; + StringBuilder currentTime = new StringBuilder(System.currentTimeMillis() + ""); while (currentTime.length() < 13) { - currentTime = "0" + currentTime; + currentTime.insert(0, "0"); } return currentTime + "-" + second + mSeparator; } @@ -825,6 +854,7 @@ private static String createDateInfo(int second) { /* * Bitmap → byte[] */ + @Contract("null -> null") private static byte[] Bitmap2Bytes(Bitmap bm) { if (bm == null) { return null; @@ -837,7 +867,8 @@ private static byte[] Bitmap2Bytes(Bitmap bm) { /* * byte[] → Bitmap */ - private static Bitmap Bytes2Bimap(byte[] b) { + @Nullable + private static Bitmap Bytes2Bimap(@NotNull byte[] b) { if (b.length == 0) { return null; } @@ -847,6 +878,7 @@ private static Bitmap Bytes2Bimap(byte[] b) { /* * Drawable → Bitmap */ + @Contract("null -> null") private static Bitmap drawable2Bitmap(Drawable drawable) { if (drawable == null) { return null; @@ -870,6 +902,7 @@ private static Bitmap drawable2Bitmap(Drawable drawable) { /* * Bitmap → Drawable */ + @Contract("null -> null") @SuppressWarnings("deprecation") private static Drawable bitmap2Drawable(Bitmap bm) { if (bm == null) { diff --git a/common_base/src/main/java/com/wss/common/utils/DateUtils.java b/common_base/src/main/java/com/wss/common/utils/DateUtils.java index 73e5c6d..1e4f303 100644 --- a/common_base/src/main/java/com/wss/common/utils/DateUtils.java +++ b/common_base/src/main/java/com/wss/common/utils/DateUtils.java @@ -2,13 +2,21 @@ import android.annotation.SuppressLint; import android.text.TextUtils; +import android.util.Log; -import com.wss.common.constants.Constants; +import com.orhanobut.logger.Logger; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Calendar; import java.util.Date; +import java.util.GregorianCalendar; +import java.util.List; import java.util.TimeZone; /** @@ -18,6 +26,16 @@ @SuppressLint("SimpleDateFormat") public class DateUtils { + public static final String DATE_FORMAT = "yyyyMMddHH"; + public static final String DATE_FORMAT_SLASH = "yyyy/MM/dd"; + public static final String DATE_FORMAT_LINE = "yyyy-MM-dd"; + public static final String DATE_FORMAT_TIME = "HH:mm:ss"; + public static final String DATE_FORMAT_DEFAULT = DATE_FORMAT_SLASH + " " + DATE_FORMAT_TIME; + private static final int SECOND = 60; + private static final int DAY = 60; + private static final int MOUTH = 60; + + /** * 获取当前时间戳 * @@ -33,9 +51,35 @@ public static long getCurrentTimeStamp() { * @return String */ public static String getCurrentDateStr() { - return getFormatDate(getCurrentTimeStamp(), Constants.DATE_FORMAT_LINE); + return getFormatDate(getCurrentTimeStamp(), DATE_FORMAT_LINE); } + /** + * 获取格式化的当前系统时间 + * + * @return String + */ + public static String getCurrentDateStr(String pattern) { + return getFormatDate(getCurrentTimeStamp(), pattern); + } + + /** + * 获取格式化时间 + * + * @param date date + * @param pattern 格式化格式(默认yyyy-MM-dd HH:mm:ss) + */ + @NotNull + public static String getFormatDate(Date date, String pattern) { + if (date == null) { + return ""; + } + if (!ValidUtils.isValid(pattern)) { + pattern = DATE_FORMAT_DEFAULT; + } + SimpleDateFormat format = new SimpleDateFormat(pattern); + return format.format(date); + } /** * 获取格式化时间 @@ -49,7 +93,7 @@ public static String getFormatDate(long timeStamp, String pattern) { timeStamp *= 1000; } if (TextUtils.isEmpty(pattern)) { - pattern = Constants.DATE_FORMAT_DEFAULT; + pattern = DATE_FORMAT_DEFAULT; } SimpleDateFormat format = new SimpleDateFormat(pattern); format.setTimeZone(TimeZone.getDefault()); @@ -64,21 +108,14 @@ public static String getFormatDate(long timeStamp, String pattern) { * @param pattern pattern * @return String */ - public static String getFormatDate(String stringDate, String pattern) { + public static String getFormatDate2(String stringDate, String pattern) { if (TextUtils.isEmpty(stringDate)) { return ""; } - String parentPattern; - if (stringDate.length() == 16) { - parentPattern = "yyyy-MM-dd HH:mm"; - } else if (stringDate.length() == 19) { - parentPattern = "yyyy-MM-dd HH:mm:ss"; - } else { - return stringDate; - } - SimpleDateFormat sdf1 = new SimpleDateFormat(pattern); try { - return sdf1.format(new SimpleDateFormat(parentPattern).parse(stringDate)); + SimpleDateFormat sdf1 = new SimpleDateFormat(pattern); + String sourcePattern = String.format("%s %s", DATE_FORMAT_LINE, DATE_FORMAT_TIME); + return sdf1.format(new SimpleDateFormat(sourcePattern).parse(stringDate)); } catch (ParseException e) { e.printStackTrace(); } @@ -86,39 +123,59 @@ public static String getFormatDate(String stringDate, String pattern) { } /** - * 获取系统的时间 + * 格式化返回日期时间 * + * @param stringDate stringDate + * @param pattern pattern * @return String */ - public static String getCurrentTimeStr() { - SimpleDateFormat fort = new SimpleDateFormat("HH:mm:ss"); - fort.setTimeZone(TimeZone.getTimeZone("GMT+8:00")); - return fort.format(getCurrentTimeStamp()); + public static String getFormatDate(String stringDate, String pattern) { + if (TextUtils.isEmpty(stringDate)) { + return ""; + } + String parentPattern; + switch (stringDate.length()) { + case 10: + parentPattern = "yyyy-MM-dd"; + break; + case 16: + parentPattern = "yyyy-MM-dd HH:mm"; + break; + case 19: + parentPattern = "yyyy-MM-dd HH:mm:ss"; + break; + default: + return stringDate; + } + SimpleDateFormat sdf1 = new SimpleDateFormat(pattern); + try { + return sdf1.format(new SimpleDateFormat(parentPattern).parse(stringDate)); + } catch (ParseException e) { + e.printStackTrace(); + } + return stringDate; } + /** - * 获取当前时间的下一天/ 前一天时间 - * - * @param time time - * @param day 正数为以后 负数为以前 - * @return + * 日期转日历 */ - public static long getNextDayTimeStamp(long time, int day) { - long timeStamp = 0; - Calendar cal = Calendar.getInstance(); - Date date = new Date(time); - SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); + @NotNull + public static Calendar getFormatDate(String stringDate) { + SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_LINE); + Calendar calendar = Calendar.getInstance(); try { - cal.setTime(date); - cal.add(Calendar.DATE, 1); - timeStamp = getStringToTimeStamp(sdf.format(cal.getTime())); - } catch (Exception e) { + Date date = sdf.parse(stringDate); + if (date != null) { + calendar.setTime(date); + } + } catch (ParseException e) { e.printStackTrace(); - return timeStamp; } - return timeStamp; + return calendar; } + /** * 根据字符串时间获取时间戳 * @@ -134,43 +191,15 @@ public static long getStringToTimeStamp(String stringDate) { } try { date = simpleDateFormat.parse(stringDate); - timeStamp = date.getTime(); + if (date != null) { + timeStamp = date.getTime(); + } } catch (ParseException e) { return timeStamp; } return timeStamp; } - /** - * 根据当前时间获取问候语 - * - * @return 问候语 - */ - public static String getTimeTransformation() { - Calendar calendar = Calendar.getInstance(); - int hour = calendar.get(Calendar.HOUR_OF_DAY); - if (hour >= 0 && hour < 5) { - return "凌晨"; - } else if (hour >= 5 && hour < 7) { - return "清晨"; - } else if (hour >= 7 && hour < 9) { - return "早上"; - } else if (hour >= 9 && hour < 12) { - return "上午"; - } else if (hour >= 12 && hour < 14) { - return "中午"; - } else if (hour >= 14 && hour < 17) { - return "下午"; - } else if (hour >= 17 && hour < 19) { - return "傍晚"; - } else if (hour >= 19 && hour < 21) { - return "晚上"; - } else if (hour >= 21 && hour < 24) { - return "深夜"; - } - return ""; - } - /** * 时间转换 * @@ -179,19 +208,206 @@ public static String getTimeTransformation() { public static String dateTransformation(long date) { long difference = (getCurrentTimeStamp() / 1000) - (date / 1000); if (difference > 0) { - if (difference < 60 * 60) { + if (difference < SECOND * SECOND) { + long temp = difference / 60; + if (temp < 1) { + return "1分钟前"; + } return difference / 60 + "分钟前"; - } else if (difference < 24 * 60 * 60) { + } else if (difference < DAY * SECOND * SECOND) { return (int) (difference / 60 / 60) + "小时前"; - } else if (difference < 30 * 24 * 60 * 60) { + } else if (difference < MOUTH * DAY * SECOND * SECOND) { return (int) (difference / 60 / 60 / 24) + "日前"; } else { - return getFormatDate(date, Constants.DATE_FORMAT_SLASH); + return getFormatDate(date, DATE_FORMAT_SLASH); + } + } else { + return getFormatDate(date, DATE_FORMAT_SLASH); + } + } + + /** + * 格式化时间 + * + * @param dateStr 5月21日 17:00 + * @return String + */ + @Nullable + public static String getMessageDate(long dateStr) { + try { + Date date = new Date(); + date.setTime(dateStr); + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + return String.format("%s月%s日%s:%s", (calendar.get(Calendar.MONTH) + 1), + calendar.get(Calendar.DAY_OF_MONTH), calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE)); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 根据月份返回中文 + * + * @param month 月份 + * @return 中文 + */ + @NotNull + @Contract(pure = true) + public static String getDateFormatMonth(int month) { + switch (month) { + case 1: + return "一月"; + case 2: + return "二月"; + case 3: + return "三月"; + case 4: + return "四月"; + case 5: + return "五月"; + case 6: + return "六月"; + case 7: + return "七月"; + case 8: + return "八月"; + case 9: + return "九月"; + case 10: + return "十月"; + case 11: + return "十一月"; + case 12: + return "十二月"; + default: + return ""; + } + } + + /** + * 计算两个时间的时间差 + * + * @param time 时间 + * @return 差值 + */ + public static long getTimeDifference(long time) { + long difference = System.currentTimeMillis() - time; + Log.e("时间差:", difference + "|" + difference / 1000); + return difference / 1000; + } + + /** + * 获取当前时间往前往后n的日期 + * eg: date ==null 默认是系统当前时间 否则以date为时间起点 + * n > 0 往后 + * n = 0 当前时间 + * n < 0 往前 + * + * @param date + * @param n + * @return + * @author zhangheng5@lenovo.com + */ + @NotNull + public static List getBeforeDate(Date date, int n) { + List list = new ArrayList<>(); + Calendar calender = Calendar.getInstance(); + Date today = new Date(); + if (null != date) { + today = date; + } + calender.setTime(today); + + if (n > 0) { + for (int i = 0; i <= n; i++) { + calender.add(Calendar.DATE, i); + list.add(getFormatDate(calender.getTime(), DATE_FORMAT_LINE)); + calender.setTime(today); + } + } else if (n < 0) { + for (int i = n; i <= 0; i++) { + calender.add(Calendar.DATE, i); + list.add(getFormatDate(calender.getTime(), DATE_FORMAT_LINE)); + calender.setTime(today); } } else { - return getFormatDate(date, Constants.DATE_FORMAT_SLASH); + calender.add(Calendar.DATE, 0); + list.add(getFormatDate(calender.getTime(), DATE_FORMAT_LINE)); + calender.setTime(today); + } + + return list; + } + + /** + * 根据时间戳判断是否是明天 + * + * @param time 秒级 时间戳 + * @return b + */ + public static boolean isTomorrow(long time) { + Calendar curDate = Calendar.getInstance(); + Calendar tomorrowCalendar = new GregorianCalendar(curDate + .get(Calendar.YEAR), curDate.get(Calendar.MONTH), curDate + .get(Calendar.DATE) + 1, 0, 0, 0); + long timeInMillis = tomorrowCalendar.getTimeInMillis(); + return time >= tomorrowCalendar.getTimeInMillis() / 1000; + } + + /** + * 格式化时间 + * + * @param dateStr 时间字符串 + * @return boolean + */ + public static boolean isToday(String dateStr) { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + Date date = null; + try { + date = format.parse(dateStr); + } catch (ParseException e) { + e.printStackTrace(); } + Calendar c1 = Calendar.getInstance(); + c1.setTime(date); + int year1 = c1.get(Calendar.YEAR); + int month1 = c1.get(Calendar.MONTH) + 1; + int day1 = c1.get(Calendar.DAY_OF_MONTH); + Calendar c2 = Calendar.getInstance(); + c2.setTime(new Date()); + int year2 = c2.get(Calendar.YEAR); + int month2 = c2.get(Calendar.MONTH) + 1; + int day2 = c2.get(Calendar.DAY_OF_MONTH); + return year1 == year2 && month1 == month2 && day1 == day2; + } + + /** + * 判断某一个时间是不是下午 + * + * @param dateStr 时间字符串 + * @return boolean + */ + public static boolean isDatePm(String dateStr) { + int a = Integer.parseInt(getFormatDate2(dateStr, "HH")); + return a >= 12 && a < 24; } + + + /** + * 获取afterMinute钟以前或者以后的时间 + * + * @param afterMinute 之前传负数 之后传正数 + * @return yyyy-MM-dd HH:mm:ss; + */ + public static String getAfterMinuteTime(int afterMinute) { + SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Date date = new Date(getCurrentTimeStamp() + 60 * 1000 * afterMinute); + return sd.format(date); + } + + } diff --git a/common_base/src/main/java/com/wss/common/utils/EventBusUtils.java b/common_base/src/main/java/com/wss/common/utils/EventBusUtils.java index 001b5ca..3a89779 100644 --- a/common_base/src/main/java/com/wss/common/utils/EventBusUtils.java +++ b/common_base/src/main/java/com/wss/common/utils/EventBusUtils.java @@ -1,14 +1,14 @@ package com.wss.common.utils; + import com.wss.common.bean.Event; import org.greenrobot.eventbus.EventBus; /** - * Describe:EventBusUtils + * Describe:EventBus帮助类 * Created by 吴天强 on 2018/10/22. */ - public class EventBusUtils { /** @@ -31,5 +31,18 @@ public static void unregister(Object subscriber) { public static void sendEvent(Event event) { EventBus.getDefault().post(event); } - //... + + /** + * 发送普通事件 + */ + public static void sendEvent(String action) { + sendEvent(new Event(action)); + } + + /** + * 发送普通事件 + */ + public static void sendEvent(String action, Object data) { + sendEvent(new Event<>(action, data)); + } } diff --git a/common_base/src/main/java/com/wss/common/utils/FileUtils.java b/common_base/src/main/java/com/wss/common/utils/FileUtils.java index 5b35a8d..f4c885c 100644 --- a/common_base/src/main/java/com/wss/common/utils/FileUtils.java +++ b/common_base/src/main/java/com/wss/common/utils/FileUtils.java @@ -1,30 +1,50 @@ package com.wss.common.utils; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.ContentUris; import android.content.Context; +import android.database.Cursor; import android.net.Uri; import android.os.Build; import android.os.Environment; -import android.support.annotation.Nullable; -import android.support.v4.content.FileProvider; +import android.provider.DocumentsContract; +import android.provider.MediaStore; import com.orhanobut.logger.Logger; import com.wss.common.base.BaseApplication; +import org.jetbrains.annotations.NotNull; + import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Calendar; import java.util.Collections; import java.util.LinkedList; +import androidx.annotation.Nullable; +import androidx.core.content.FileProvider; + /** * Describe:文件帮助类 * Created by 吴天强 on 2018/10/25. */ - public class FileUtils { - public static final String APPS_ROOT_DIR = getExternalStorePath() + File.separator + BaseApplication.getApplication().getPackageName(); - public static final String IMAGE_PATH = APPS_ROOT_DIR + "/Image"; - public static final String TEMP_PATH = APPS_ROOT_DIR + "/Temp"; - public static final String APP_CRASH_PATH = APPS_ROOT_DIR + "/AppCrash"; - public static final String FILE_PATH = APPS_ROOT_DIR + "/File"; + public static final String APPS_ROOT_DIR = getExternalStorePath() + File.separator + BaseApplication.i().getPackageName(); + public static final String IMAGE_PATH = APPS_ROOT_DIR + Constant.IMAGE; + public static final String TEMP_PATH = APPS_ROOT_DIR + Constant.TEMP; + public static final String APP_CRASH_PATH = APPS_ROOT_DIR + Constant.APP_CRASH; + public static final String FILE_PATH = APPS_ROOT_DIR + Constant.FILE; + + /** + * 存放文件的目录 + */ + public interface Constant { + String IMAGE = "/Image"; + String TEMP = "/Temp"; + String FILE = "/File"; + String APP_CRASH = "/AppCrash"; + } /** @@ -49,6 +69,7 @@ public static boolean isExistExternalStore() { return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED); } + @org.jetbrains.annotations.Nullable private static File create(String path) { if (!isExistExternalStore()) { Logger.e("储存卡已拔出"); @@ -56,7 +77,7 @@ private static File create(String path) { } File directory = new File(path); if (!directory.exists()) { - directory.mkdir(); + directory.mkdirs(); } return directory; } @@ -67,8 +88,9 @@ private static File create(String path) { * @return File */ @Nullable - public static File getImagePath() { - return create(IMAGE_PATH); + public static String getImagePath() { + File file = create(IMAGE_PATH); + return ValidUtils.isValid(file) ? file.getAbsolutePath() : ""; } /** @@ -77,8 +99,9 @@ public static File getImagePath() { * @return File */ @Nullable - public static File getTempPath() { - return create(TEMP_PATH); + public static String getTempPath() { + File file = create(TEMP_PATH); + return ValidUtils.isValid(file) ? file.getAbsolutePath() : ""; } /** @@ -86,8 +109,10 @@ public static File getTempPath() { * * @return File */ - public static File getAppCrashPath() { - return create(APP_CRASH_PATH); + @NotNull + public static String getAppCrashPath() { + File file = create(APP_CRASH_PATH); + return ValidUtils.isValid(file) ? file.getAbsolutePath() : ""; } /** @@ -95,8 +120,10 @@ public static File getAppCrashPath() { * * @return File */ - public static File getFilePath() { - return create(FILE_PATH); + @NotNull + public static String getFilePath() { + File file = create(FILE_PATH); + return ValidUtils.isValid(file) ? file.getAbsolutePath() : ""; } /** @@ -116,6 +143,108 @@ public static Uri getUriForFile(Context context, File file) { return fileUri; } + /** + * URI转文件 + * + * @param context context + * @param uri uri + * @return File + */ + @org.jetbrains.annotations.Nullable + public static String uriToFile(@NotNull Activity context, @NotNull Uri uri) { + if ("content".equalsIgnoreCase(uri.getScheme())) { + String filePath = null; + if (DocumentsContract.isDocumentUri(context, uri)) { + // 如果是document类型的 uri, 则通过document id来进行处理 + String documentId = DocumentsContract.getDocumentId(uri); + if (isMediaDocument(uri)) { // MediaProvider + // 使用':'分割 + String type = documentId.split(":")[0]; + String id = documentId.split(":")[1]; + + String selection = MediaStore.Images.Media._ID + "=?"; + String[] selectionArgs = {id}; + Uri contentUri = null; + if ("image".equals(type)) { + contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + } else if ("video".equals(type)) { + contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + } else if ("audio".equals(type)) { + contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; + } + + filePath = getDataColumn(context, contentUri, selection, selectionArgs); + } else if (isDownloadsDocument(uri)) { // DownloadsProvider + Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.parseLong(documentId)); + filePath = getDataColumn(context, contentUri, null, null); + } else if (isExternalStorageDocument(uri)) { + // ExternalStorageProvider + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + if ("primary".equalsIgnoreCase(type)) { + filePath = Environment.getExternalStorageDirectory() + "/" + split[1]; + } + } //Log.e("路径错误"); + + } else if ("content".equalsIgnoreCase(uri.getScheme())) { + // 如果是 content 类型的 Uri + filePath = getDataColumn(context, uri, null, null); + } else if ("file".equals(uri.getScheme())) { + // 如果是 file 类型的 Uri,直接获取图片对应的路径 + filePath = uri.getPath(); + } + return filePath; + } else if ("file".equalsIgnoreCase(uri.getScheme())) { + return uri.getPath(); + } + return ""; + } + + + /** + * 获取数据库表中的 _data 列,即返回Uri对应的文件路径 + * + * @return + */ + private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { + String path = null; + + String[] projection = new String[]{MediaStore.Images.Media.DATA}; + Cursor cursor = null; + try { + cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); + if (cursor != null && cursor.moveToFirst()) { + int columnIndex = cursor.getColumnIndexOrThrow(projection[0]); + path = cursor.getString(columnIndex); + } + } catch (Exception e) { + if (cursor != null) { + cursor.close(); + } + } + return path; + } + + /** + * @param uri the Uri to check + * @return Whether the Uri authority is MediaProvider + */ + private static boolean isMediaDocument(@NotNull Uri uri) { + return "com.android.providers.media.documents".equals(uri.getAuthority()); + } + + private static boolean isExternalStorageDocument(@NotNull Uri uri) { + return "com.android.externalstorage.documents".equals(uri.getAuthority()); + } + + /** + * @param uri the Uri to check + * @return Whether the Uri authority is DownloadsProvider + */ + private static boolean isDownloadsDocument(@NotNull Uri uri) { + return "com.android.providers.downloads.documents".equals(uri.getAuthority()); + } /** * 获取目录下的文件列表 @@ -159,4 +288,15 @@ public static void deleteFile(String filesName) { } } + /** + * 读取文件的最后修改时间的方法 + */ + public static String getFileLastModifiedTime(File f) { + Calendar cal = Calendar.getInstance(); + long time = f.lastModified(); + @SuppressLint("SimpleDateFormat") + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + cal.setTimeInMillis(time); + return formatter.format(cal.getTime()); + } } diff --git a/common_base/src/main/java/com/wss/common/utils/GroupUtils.java b/common_base/src/main/java/com/wss/common/utils/GroupUtils.java index b8fc9de..4ad3bfc 100644 --- a/common_base/src/main/java/com/wss/common/utils/GroupUtils.java +++ b/common_base/src/main/java/com/wss/common/utils/GroupUtils.java @@ -1,6 +1,5 @@ package com.wss.common.utils; -import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Log; @@ -12,20 +11,32 @@ import java.util.List; import java.util.Map; +import androidx.annotation.Nullable; + /** * Describe:Lis分组 * Created by 吴天强 on 2018-05-31 08:45 **/ public class GroupUtils { - public static final String TAG = GroupUtils.class.getSimpleName(); + private static final String TAG = GroupUtils.class.getSimpleName(); /** * 分组依据接口,用于集合分组时,获取分组依据 + * + * @param */ public interface GroupBy { T groupBy(Object obj); } + /** + * 待分组的集合 + * 分组依据 + * + * @param + * @param + * @return 分组数据 + */ public static , D> Map> group(Collection colls, GroupBy gb) { if (colls == null || colls.isEmpty()) { Log.e(TAG, "分组集合不能为空"); diff --git a/common_base/src/main/java/com/wss/common/utils/ImageUtils.java b/common_base/src/main/java/com/wss/common/utils/ImageUtils.java index 22398f2..fc42d9e 100644 --- a/common_base/src/main/java/com/wss/common/utils/ImageUtils.java +++ b/common_base/src/main/java/com/wss/common/utils/ImageUtils.java @@ -1,72 +1,273 @@ package com.wss.common.utils; +import android.app.Activity; +import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; -import android.graphics.drawable.ColorDrawable; import android.media.ExifInterface; -import android.support.annotation.Nullable; -import android.text.TextUtils; +import android.net.Uri; +import android.os.Environment; +import android.provider.MediaStore; +import android.view.View; import android.widget.ImageView; +import android.widget.ScrollView; import com.bigkoo.convenientbanner.ConvenientBanner; import com.bigkoo.convenientbanner.listener.OnItemClickListener; import com.bumptech.glide.Glide; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; import com.bumptech.glide.request.RequestOptions; import com.wss.common.adapter.BannerImgAdapter; import com.wss.common.base.R; import com.wss.common.manage.BlurTransformation; +import com.wss.common.manage.GlideRoundTransform; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.List; +import androidx.annotation.DrawableRes; +import androidx.annotation.Nullable; + /** * Describe:图片工具类 * Created by 吴天强 on 2018/10/17. */ - public class ImageUtils { + /** + * 加载手机图片 + * file + * + * @param imageView imageView + * @param file file + */ + public static void loadImage(@NotNull ImageView imageView, File file) { + loadImage(imageView, file, R.color.color_999999); + } + + /** + * 加载手机图片 + * + * @param imageView imageView + * @param file file + * @param error 加载失败占位图 + */ + public static void loadImage(@NotNull ImageView imageView, File file, @DrawableRes int error) { + Glide.with(imageView.getContext()) + .load(file) + .apply(new RequestOptions() + .placeholder(R.color.color_999999) + .error(error) + .fallback(error)) + .into(imageView); + } + + /** + * 加载手机图片 + * + * @param imageView imageView + */ + public static void loadImage(@NotNull ImageView imageView, Bitmap bitmap) { + Glide.with(imageView.getContext()) + .load(bitmap) + .apply(new RequestOptions() + .placeholder(R.color.color_999999)) + .into(imageView); + } + + /** + * 加载本地图片 + * + * @param drawable drawable + * @param imageView imageView + */ + public static void loadImage(@NotNull ImageView imageView, @DrawableRes int drawable) { + loadImage(imageView, drawable, R.color.color_999999); + } + + /** + * 加载本地图片 + * + * @param drawable drawable + * @param imageView imageView + * @param error 加载失败占位图 + */ + public static void loadImage(@NotNull ImageView imageView, int drawable, @DrawableRes int error) { + Glide.with(imageView.getContext()) + .load(drawable) + .apply(new RequestOptions() + .placeholder(R.color.color_999999) + .error(error) + .fallback(error)) + .into(imageView); + } + /** * 加载网络图片 * * @param url url * @param imageView imageView - * @param imageView transformation 转换器 */ public static void loadImage(ImageView imageView, String url) { - if (TextUtils.isEmpty(url)) { - return; - } + loadImage(imageView, url, R.color.color_999999); + } + + /** + * 加载网络图片 + * + * @param url url + * @param imageView imageView + * @param error 加载失败占位图 + */ + public static void loadImage(@NotNull ImageView imageView, String url, @DrawableRes int error) { Glide.with(imageView.getContext()) .load(url) .apply(new RequestOptions() - .placeholder(R.drawable.ic_loading_image) - .error(new ColorDrawable(Color.WHITE)) - .fallback(new ColorDrawable(Color.RED))) + .placeholder(R.color.color_999999) + .error(error) + .fallback(error)) .into(imageView); } /** - * 加载圆形 + * 加载圆形图片 * * @param url url * @param imageView imageView */ public static void loadImageCircle(ImageView imageView, String url) { - if (TextUtils.isEmpty(url)) { - return; - } + loadImageCircle(imageView, url, R.color.color_999999, R.color.color_999999); + } + + /** + * 加载圆形图片 + * + * @param url url + * @param imageView imageView + * @param error 加载失败占位图 + */ + public static void loadImageCircle(@NotNull ImageView imageView, String url, @DrawableRes int placeholder, @DrawableRes int error) { Glide.with(imageView.getContext()) .load(url) .apply(RequestOptions.circleCropTransform() - .placeholder(R.drawable.ic_loading_image) - .error(new ColorDrawable(Color.WHITE)) - .fallback(new ColorDrawable(Color.RED))) + .placeholder(placeholder) + .error(error) + .fallback(error)) + .into(imageView); + } + + + /** + * 加载圆角图片 + * + * @param imageView ImageView + * @param url URL + * @param dp 圆角角度 + */ + public static void loadImageCircleBead(@NotNull ImageView imageView, String url, int dp) { + loadImageCircleBead(imageView, url, dp, R.color.color_999999); + } + + /** + * 加载圆角图片 + * + * @param imageView ImageView + * @param url URL + * @param dp 圆角角度 + * @param error 加载失败占位图 + */ + public static void loadImageCircleBead(@NotNull ImageView imageView, String url, int dp, @DrawableRes int error) { + Glide.with(imageView.getContext()) + .load(url) + .apply(new RequestOptions() + .placeholder(R.color.color_999999) + .error(error) + .transform(new GlideRoundTransform(imageView.getContext(), dp))) + .into(imageView); + } + + public static void loadImageTest(@NotNull ImageView imageView, String url, int dp) { + + //设置图片圆角角度 + RoundedCorners roundedCorners = new RoundedCorners(dp); + //通过RequestOptions扩展功能,override:采样率,因为ImageView就这么大,可以压缩图片,降低内存消耗 + // RequestOptions options = RequestOptions.bitmapTransform(roundedCorners).override(300, 300); + RequestOptions options = RequestOptions.bitmapTransform(roundedCorners); + options.placeholder(R.color.color_999999); + Glide.with(imageView.getContext()).load(url).apply(options).into(imageView); + + } + + /** + * 加载圆角图片 + * + * @param imageView ImageView + * @param file file + * @param dp 圆角角度 + */ + public static void loadImageCircleBead(@NotNull ImageView imageView, File file, int dp) { + loadImageCircleBead(imageView, file, dp, R.color.color_999999); + } + + /** + * 加载圆角图片 + * + * @param imageView ImageView + * @param file file + * @param dp 圆角角度 + * @param error 加载失败占位图 + */ + public static void loadImageCircleBead(@NotNull ImageView imageView, File file, int dp, @DrawableRes int error) { + Glide.with(imageView.getContext()) + .load(file) + .apply(new RequestOptions() + .placeholder(R.color.color_999999) + .error(error) + .transform(new GlideRoundTransform(imageView.getContext(), dp))) + .into(imageView); + } + + + /** + * 加载高斯模糊图 + * + * @param imageView imageView + * @param drawable drawable + */ + public static void loadImageBlur(ImageView imageView, int drawable) { + Glide.with(imageView) + .load(drawable) + .apply(RequestOptions.bitmapTransform( + new BlurTransformation(imageView.getContext(), 5f)) + .error(R.color.theme)) + .into(imageView); + } + + /** + * 加载高斯模糊图 + * + * @param imageView imageView + * @param drawable drawable + * @param error 加载失败占位图 + */ + public static void loadImageBlur(ImageView imageView, @DrawableRes int drawable, @DrawableRes int error) { + Glide.with(imageView) + .load(drawable) + .apply(RequestOptions.bitmapTransform( + new BlurTransformation(imageView.getContext(), 5f)) + .placeholder(R.color.color_999999) + .error(error)) .into(imageView); } @@ -80,18 +281,47 @@ public static void loadImageBlur(ImageView imageView, String url) { Glide.with(imageView) .load(url) .apply(RequestOptions.bitmapTransform( - new BlurTransformation(imageView.getContext()))) + new BlurTransformation(imageView.getContext())) + .error(R.color.theme)) .into(imageView); } + /** + * 加载高斯模糊图 + * + * @param imageView imageView + * @param url url + * @param error 加载失败占位图 + */ + public static void loadImageBlur(ImageView imageView, String url, @DrawableRes int error) { + Glide.with(imageView) + .load(url) + .apply(RequestOptions.bitmapTransform( + new BlurTransformation(imageView.getContext())) + .placeholder(R.color.color_999999) + .error(error)) + .into(imageView); + } + + + /** + * 加载圆形头像 + * + * @param imageView imageView + * @param url 图片链接 + */ + public static void loadCircleHeader(ImageView imageView, String url) { + loadImageCircle(imageView, url, R.drawable.header_load_default, R.drawable.header_load_default); + } + /** * 加载只有一张图的Banner * - * @param banner banner - * @param imgUrl imgUrl + * @param banner banner控件 + * @param imgUrl banner图片集合 * @param listener listener */ - public static void loadBanner(ConvenientBanner banner, List imgUrl, OnItemClickListener listener) { + public static void loadBanner(ConvenientBanner banner, List imgUrl, OnItemClickListener listener) { banner.setPages(new BannerImgAdapter(), imgUrl) .setPageIndicator(new int[]{R.drawable.shape_item_index_white, R.drawable.shape_item_index_red}) .setPageIndicatorAlign(ConvenientBanner.PageIndicatorAlign.ALIGN_PARENT_RIGHT) @@ -99,6 +329,21 @@ public static void loadBanner(ConvenientBanner banner, List imgUrl, OnIt .startTurning(); } + /** + * 加载只有一张图的Banner + * + * @param banner banner控件 + * @param imgUrl banner图片集合 + * @param listener listener + */ + public static void loadBanner(ConvenientBanner banner, List imgUrl, boolean circle, OnItemClickListener listener) { + banner.setPages(new BannerImgAdapter(circle), imgUrl) + .setPageIndicator(new int[]{R.drawable.shape_item_index_white, R.drawable.shape_item_index_red}) + .setPageIndicatorAlign(ConvenientBanner.PageIndicatorAlign.ALIGN_PARENT_RIGHT) + .setOnItemClickListener(listener) + .startTurning(); + } + /** * 压缩图片 * @@ -110,10 +355,12 @@ public static File compressImage(String filePath) { if (!FileUtils.isExistExternalStore()) { return null; } - int quality = 100; - Bitmap bm = getSmallBitmap(filePath);//获取一定尺寸的图片 - int degree = readPictureDegree(filePath);//获取相片拍摄角度 - if (degree != 0) {//旋转照片角度,防止头像横着显示 + int quality = 100;//获取一定尺寸的图片 + Bitmap bm = getSmallBitmap(filePath); + //获取相片拍摄角度 + int degree = readPictureDegree(filePath); + if (degree != 0) { + //旋转照片角度,防止头像横着显示 bm = rotateBitmap(bm, degree); } File outputFile = null; @@ -136,10 +383,14 @@ public static File compressImage(String filePath) { /** * 根据路径获得图片信息并按比例压缩,返回bitmap + * + * @param filePath 图片地址 + * @return Bitmap */ public static Bitmap getSmallBitmap(String filePath) { final BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true;//只解析图片边沿,获取宽高 + //只解析图片边沿,获取宽高 + options.inJustDecodeBounds = true; BitmapFactory.decodeFile(filePath, options); // 计算缩放比 options.inSampleSize = calculateInSampleSize(options, 480, 800); @@ -148,15 +399,22 @@ public static Bitmap getSmallBitmap(String filePath) { return BitmapFactory.decodeFile(filePath, options); } - public static int calculateInSampleSize(BitmapFactory.Options options, - int reqWidth, int reqHeight) { + /** + * 计算缩放比 + * + * @param options options + * @param reqWidth 宽 + * @param reqHeight 高 + * @return 缩放比 + */ + public static int calculateInSampleSize(@NotNull BitmapFactory.Options options, int reqWidth, int reqHeight) { final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int heightRatio = Math.round((float) height / (float) reqHeight); final int widthRatio = Math.round((float) width / (float) reqWidth); - inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; + inSampleSize = Math.min(heightRatio, widthRatio); } return inSampleSize; } @@ -164,8 +422,8 @@ public static int calculateInSampleSize(BitmapFactory.Options options, /** * 获取照片角度 * - * @param path - * @return + * @param path 图片地址 + * @return int */ public static int readPictureDegree(String path) { int degree = 0; @@ -194,10 +452,11 @@ public static int readPictureDegree(String path) { /** * 旋转照片 * - * @param bitmap - * @param degress - * @return + * @param bitmap bitmap + * @param degress 旋转角度 + * @return Bitmap */ + @Contract("null, _ -> null") public static Bitmap rotateBitmap(Bitmap bitmap, int degress) { if (bitmap != null) { Matrix m = new Matrix(); @@ -206,7 +465,224 @@ public static Bitmap rotateBitmap(Bitmap bitmap, int degress) { bitmap.getHeight(), m, true); return bitmap; } - return bitmap; + return null; + } + + /** + * 把View转成Bitmap 注意:改view必须是已经显示到页面上的 + * + * @return Bitmap + */ + public static Bitmap viewConversionBitmap(@NotNull View view, String color) { + + int w = view.getWidth(); + int h = view.getHeight(); + + Bitmap bmp = Bitmap.createBitmap(w, w, Bitmap.Config.ARGB_8888); + Canvas c = new Canvas(bmp); + + c.drawColor(Color.parseColor(color)); + view.layout(0, 0, w, h); + view.draw(c); + return bmp; + + } + + /** + * 把View转成Bitmap 注意:改view必须是已经显示到页面上的 + * + * @return Bitmap + */ + public static Bitmap viewConversionBitmap(@NotNull ScrollView scrollView, String color) { + + int height = 20; + //正确获取ScrollView + for (int i = 0; i < scrollView.getChildCount(); i++) { + height += scrollView.getChildAt(i).getHeight(); + } + + int w = scrollView.getWidth(); + + Bitmap bmp = Bitmap.createBitmap(w, height, Bitmap.Config.ARGB_8888); + Canvas c = new Canvas(bmp); + + c.drawColor(Color.parseColor(color)); + scrollView.layout(0, 0, w, height); + scrollView.draw(c); + return bmp; + + } + + /** + * 把Bitmap转成图片 + * + * @param bitmap bitmap + * @param imageName 文件名称 + * @return 图片的本地地址 + */ + @org.jetbrains.annotations.Nullable + public static String bitmapSaveToImage(Bitmap bitmap, String imageName) { + FileOutputStream b = null; + String filePath = FileUtils.getImagePath() + File.separator + imageName + ".jpg"; + try { + b = new FileOutputStream(filePath); + // 把数据写入文件 + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, b); + return filePath; + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (b != null) { + b.flush(); + b.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + return null; + } + + + /** + * 添加图片到系统相册 + * + * @param activity activity + * @param filePath 图片路径 + * @param fileName 图片名称 + */ + public static boolean addImageToAlbum(@NotNull Activity activity, String filePath, String fileName) { + try { + MediaStore.Images.Media.insertImage(activity.getContentResolver(), filePath, fileName, null); + activity.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + Environment.getExternalStorageDirectory().getPath()))); + return true; + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + return false; + } + + /** + * 生成个人名片海报图片 + * + * @param activity activity + * @param scrollView ScrollView + */ + public static boolean generatePoster(Activity activity, ScrollView scrollView) { + String fileName = String.valueOf(DateUtils.getCurrentTimeStamp()); + String filePath = ImageUtils.bitmapSaveToImage(ImageUtils.viewConversionBitmap(scrollView, "#F5F5F5"), fileName); + if (ValidUtils.isValid(filePath)) { + return addImageToAlbum(activity, filePath, fileName); + } + return false; + } + + /** + * 生成个人名片海报图片 + * + * @param activity activity + * @param scrollView ScrollView + */ + public static String generatePosterPath(Activity activity, ScrollView scrollView) { + return ImageUtils.bitmapSaveToImage(ImageUtils.viewConversionBitmap(scrollView, "#F5F5F5"), String.valueOf(DateUtils.getCurrentTimeStamp())); + } + + /** + * Bitmap转二进制流 + * + * @param bitmap bitmap + * @return byte[] + */ + @NotNull + public static byte[] getBitmapByte(@NotNull Bitmap bitmap) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out); + try { + out.flush(); + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return out.toByteArray(); + } + + /** + * Bitmap转换成byte[]并且进行压缩,压缩到不大于maxkb + * + * @param bitmap bitmap + * @param maxKb 最大大小 + * @return 字节数组 + */ + @NotNull + public static byte[] bitmapBytes(@NotNull Bitmap bitmap, int maxKb) { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, 100, output); + int options = 100; + while (output.toByteArray().length > maxKb && options != 10) { + output.reset(); //清空output + //这里压缩options%,把压缩后的数据存放到output中 + bitmap.compress(Bitmap.CompressFormat.JPEG, options, output); + options -= 10; + } + return output.toByteArray(); + } + + /** + * 获取海报的图片二进制流 + * + * @param layoutView 海报view + * @return byte[] + */ + @NotNull + public static byte[] getPosterByte(View layoutView) { + return getBitmapByte(ImageUtils.viewConversionBitmap(layoutView, "#F5F5F5")); + } + + /** + * 获取微信分享图片的缩略图 + * + * @param image 图片流 + * @return 图片流 + */ + @NotNull + public static byte[] getWXShareThumbImage(byte[] image) { + return bitmapBytes(getBitmapByBytes(image, 200, 300), 32); + } + + /** + * 根据图片生成缩略图 + * + * @param bytes 图片流 + * @param maxHeight 最大高度 + * @param maxWidth 最大宽度 + * @return Bitmap + */ + @NotNull + public static Bitmap getBitmapByBytes(byte[] bytes, int maxHeight, int maxWidth) { + //对于图片的二次采样,主要得到图片的宽与高 + int width = 0; + int height = 0; + //默认缩放为1 + int sampleSize = 1; + BitmapFactory.Options options = new BitmapFactory.Options(); + //仅仅解码边缘区域 + options.inJustDecodeBounds = true; + //如果指定了inJustDecodeBounds,decodeByteArray将返回为空 + BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); + //得到宽与高 + height = options.outHeight; + width = options.outWidth; + + //图片实际的宽与高,根据默认最大大小值,得到图片实际的缩放比例 + while ((height / sampleSize > maxHeight) || (width / sampleSize > maxWidth)) { + sampleSize *= 2; + } + //不再只加载图片实际边缘 + options.inJustDecodeBounds = false; + //并且制定缩放比例 + options.inSampleSize = sampleSize; + return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); } } diff --git a/common_base/src/main/java/com/wss/common/utils/JsonUtils.java b/common_base/src/main/java/com/wss/common/utils/JsonUtils.java new file mode 100644 index 0000000..297a8fd --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/JsonUtils.java @@ -0,0 +1,306 @@ +package com.wss.common.utils; + +import android.text.TextUtils; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; +import com.google.gson.reflect.TypeToken; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; + +/** + * Describe:Gson 解析封装 + * Created by 吴天强 on 2018/12/12. + */ +public class JsonUtils { + + /** + * 对象转Json + * + * @param obj 对象 + * @return json String + */ + public static String toJson(Object obj) { + if (ValidUtils.isValid(obj)) { + return new Gson().toJson(obj); + } + return "{}"; + } + + /** + * 解析T对象 + * + * @param json json + * @param type 目标类型 + * @param 类型 + * @return T + */ + public static T getObject(String json, Class type) { + return new Gson().fromJson(json, type); + } + + /** + * 解析String + * + * @param json json + * @param key key + * @return String + */ + @Contract("null, _ -> !null") + public static String getString(JsonObject json, String key) { + if (json == null) { + return ""; + } + JsonElement jsonElement = json.get(key); + if (jsonElement == null) { + return ""; + } + return jsonElement.getAsString(); + } + + /** + * 解析String + * + * @param element json + * @return String + */ + @Contract("null, _ -> !null") + public static String getString(JsonElement element, String key) { + if (element == null) { + return ""; + } + return getString(element.getAsJsonObject(), key); + } + + /** + * 解析String + * + * @param json json + * @param key key + * @return String + */ + public static String getString(String json, String key) { + if (!isJsonObject(json)) { + return ""; + } + JsonElement jsonElement = getJsonObject(json).get(key); + if (jsonElement == null) { + return ""; + } + //判断json对象是否为Object + if (jsonElement.isJsonObject()) { + JsonObject asJsonObject = jsonElement.getAsJsonObject(); + return asJsonObject.toString(); + } + //判断json对象是否为数组 + if (jsonElement.isJsonArray()) { + JsonArray asJsonArray = jsonElement.getAsJsonArray(); + return asJsonArray.toString(); + } + return jsonElement.getAsString(); + } + + + /** + * 解析boolean + * + * @param json json + * @param key key + * @return boolean + */ + @Contract("null, _ -> false") + public static boolean getBoolean(String json, String key) { + if (json == null) { + return false; + } + JsonElement jsonElement = getJsonObject(json).get(key); + return jsonElement != null && jsonElement.getAsBoolean(); + } + + /** + * 解析int + * + * @param json json + * @param key key + * @return String + */ + public static int getInt(String json, String key) { + JsonElement jsonElement = getJsonObject(json).get(key); + if (jsonElement == null) { + return 0; + } + return jsonElement.getAsInt(); + } + + /** + * 解析int + * + * @param json json + * @param key key + * @return boolean + */ + public static int getInt(JsonObject json, String key) { + if (json == null) { + return 0; + } + JsonElement jsonElement = json.get(key); + if (jsonElement == null) { + return 0; + } + return jsonElement.getAsInt(); + } + + + /** + * 解析JsonObject + * + * @param json json + * @return JsonArray + */ + public static JsonObject getJsonObject(String json) { + if (TextUtils.isEmpty(json)) { + return new JsonObject(); + } + return new JsonParser().parse(json).getAsJsonObject(); + } + + /** + * 解析JsonArray + * + * @param json json + * @param key key + * @return JsonArray + */ + @Contract("null, _ -> new") + public static JsonArray getJsonArray(JsonObject json, String key) { + if (json == null) { + return new JsonArray(); + } + JsonElement jsonElement = json.get(key); + if (jsonElement == null) { + return new JsonArray(); + } + return jsonElement.getAsJsonArray(); + } + + + /** + * 解析Map + * + * @param json json + * @return List + */ + @NotNull + public static LinkedHashMap getMap(@NotNull String json) { + LinkedHashMap result = new LinkedHashMap<>(); + try { + JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject(); + result.putAll(new Gson().fromJson(jsonObject, new TypeToken>() { + }.getType())); + } catch (JsonSyntaxException e) { + e.printStackTrace(); + } + return result; + } + + /** + * 解析List + * + * @param json json + * @param clazz clazz + * @return List + */ + public static List getList(String json, Class clazz) { + if (!ValidUtils.isValid(json)) { + return new ArrayList<>(); + } + List list = null; + try { + list = new ArrayList<>(); + Type type = new TypeToken>() { + }.getType(); + List jsonObjects = new Gson().fromJson(json, type); + if (ValidUtils.isValid(jsonObjects)) { + for (JsonObject jsonObject : jsonObjects) { + list.add(new Gson().fromJson(jsonObject, clazz)); + } + } + } catch (JsonSyntaxException e) { + e.printStackTrace(); + } + return list; + } + + /** + * 解析List + * + * @param json json + * @return List + */ + public static List getList(String json) { + if (!isJsonArray(json)) { + return new ArrayList<>(); + } + return new Gson().fromJson(json, new TypeToken>() { + }.getType()); + } + + /** + * 判断是否JSON数组 + * + * @param json json + * @return boolean + */ + public static boolean isJsonArray(String json) { + JsonElement jsonElement = getJsonElement(json); + if (jsonElement == null) { + return false; + } + return jsonElement.isJsonArray(); + } + + /** + * 判断是否JSON对象 + * + * @param json json + * @return boolean + */ + public static boolean isJsonObject(String json) { + JsonElement jsonElement = getJsonElement(json); + if (jsonElement == null) { + return false; + } + return jsonElement.isJsonObject(); + } + + /** + * 获取JsonElement + * + * @param json json + * @return JsonElement + */ + @Nullable + private static JsonElement getJsonElement(String json) { + JsonElement jsonElement; + if (!ValidUtils.isValid(json)) { + return null; + } + try { + jsonElement = new JsonParser().parse(json); + } catch (Exception e) { + return null; + } + return jsonElement; + } +} diff --git a/common_base/src/main/java/com/wss/common/utils/KeyboardUtils.java b/common_base/src/main/java/com/wss/common/utils/KeyboardUtils.java index a4f2426..a6c3af4 100644 --- a/common_base/src/main/java/com/wss/common/utils/KeyboardUtils.java +++ b/common_base/src/main/java/com/wss/common/utils/KeyboardUtils.java @@ -4,13 +4,20 @@ import android.view.View; import android.view.inputmethod.InputMethodManager; +import org.jetbrains.annotations.NotNull; + /** * Describe:键盘辅助类 * Created by 吴天强 on 2017/11/2. */ public class KeyboardUtils { - public static void showKeyboard(View view) { + /** + * 显示键盘 + * + * @param view view + */ + public static void showKeyboard(@NotNull View view) { InputMethodManager imm = (InputMethodManager) view.getContext() .getSystemService(Context.INPUT_METHOD_SERVICE); if (imm != null) { @@ -19,19 +26,16 @@ public static void showKeyboard(View view) { } } - public static void hideKeyboard(View view) { + /** + * 隐藏键盘 + * + * @param view view + */ + public static void hideKeyboard(@NotNull View view) { InputMethodManager imm = (InputMethodManager) view.getContext() .getSystemService(Context.INPUT_METHOD_SERVICE); if (imm != null) { imm.hideSoftInputFromWindow(view.getWindowToken(), 0); } } - - public static void toggleSoftInput(View view) { - InputMethodManager imm = (InputMethodManager) view.getContext() - .getSystemService(Context.INPUT_METHOD_SERVICE); - if (imm != null) { - imm.toggleSoftInput(0, 0); - } - } } \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/utils/MoneyUtils.java b/common_base/src/main/java/com/wss/common/utils/MoneyUtils.java index 15d12d4..8768e44 100644 --- a/common_base/src/main/java/com/wss/common/utils/MoneyUtils.java +++ b/common_base/src/main/java/com/wss/common/utils/MoneyUtils.java @@ -10,7 +10,6 @@ * Describe:金钱工具类 * Created by 吴天强 on 2017/11/24. */ - public class MoneyUtils { /** * 计算类 @@ -20,32 +19,32 @@ public static class Algorithm { /** * 金钱加法 * - * @param v1 - * @param v2 - * @return + * @param value1 参数1 + * @param value2 参数2 + * @return 结果 */ - public static String add(String v1, String v2) { - BigDecimal b1 = new BigDecimal(v1); - BigDecimal b2 = new BigDecimal(v2); + public static String add(Object value1, Object value2) { + BigDecimal b1 = new BigDecimal(String.valueOf(value1)); + BigDecimal b2 = new BigDecimal(String.valueOf(value2)); return b1.add(b2).toString(); } /** * 金钱减法 * - * @param v1 - * @param v2 - * @return + * @param value1 参数1 + * @param value2 参数2 + * @return 结果 */ - public static String subtract(String v1, String v2) { - if (TextUtils.isEmpty(v1)) { - v1 = "0"; + public static String subtract(String value1, String value2) { + if (TextUtils.isEmpty(value1)) { + value1 = "0"; } - if (TextUtils.isEmpty(v2)) { - v2 = "0"; + if (TextUtils.isEmpty(value2)) { + value2 = "0"; } - BigDecimal b1 = new BigDecimal(v1); - BigDecimal b2 = new BigDecimal(v2); + BigDecimal b1 = new BigDecimal(value1); + BigDecimal b2 = new BigDecimal(value2); return b1.subtract(b2).toString(); } @@ -53,25 +52,25 @@ public static String subtract(String v1, String v2) { /** * 金钱乘法 * - * @param v1 - * @param v2 - * @return + * @param value1 参数1 + * @param value2 参数2 + * @return 结果 */ - public static String multiply(String v1, String v2) { - return multiply(v1, v2, 0); + public static String multiply(String value1, String value2) { + return multiply(value1, value2, 0); } /** * 金钱乘法 * - * @param v1 乘数 - * @param v2 被乘数 - * @param scale 小数点保留位数 - * @return + * @param value1 乘数 + * @param value2 被乘数 + * @param scale 小数点保留位数 + * @return 结果 */ - public static String multiply(String v1, String v2, int scale) { - BigDecimal b1 = new BigDecimal(v1); - BigDecimal b2 = new BigDecimal(v2); + public static String multiply(String value1, String value2, int scale) { + BigDecimal b1 = new BigDecimal(value1); + BigDecimal b2 = new BigDecimal(value2); BigDecimal result = b1.multiply(b2); result = result.setScale(scale, BigDecimal.ROUND_HALF_UP); return result.toString(); @@ -80,13 +79,13 @@ public static String multiply(String v1, String v2, int scale) { /** * 金钱除法 * - * @param v1 - * @param v2 - * @return + * @param value1 参数1 + * @param value2 参数2 + * @return 结果 */ - public static String divide(String v1, String v2) { - BigDecimal b1 = new BigDecimal(v1); - BigDecimal b2 = new BigDecimal(v2); + public static String divide(String value1, String value2) { + BigDecimal b1 = new BigDecimal(value1); + BigDecimal b2 = new BigDecimal(value2); return b1.divide(b2, BigDecimal.ROUND_HALF_UP).toString(); } } @@ -98,7 +97,7 @@ public static String divide(String v1, String v2) { * @return String */ public static String formatPrice(String textPrice) { - return formatPrice(Double.valueOf(textPrice) / 100); + return formatPrice(Double.parseDouble(textPrice) / 100); } /** @@ -108,13 +107,6 @@ public static String formatPrice(String textPrice) { * @return String */ public static String formatPrice(double price) { - if (price > 0 && price < 1) { - String temp = String.valueOf(price); - if (temp.contains(".") && temp.substring(temp.indexOf(".") + 1, temp.length()).length() <= 1) { - return String.format("%s%s", price, 0); - } - return String.format("%s", price); - } if (price <= 0) { return "0.00"; } @@ -123,4 +115,28 @@ public static String formatPrice(double price) { return String.format("%s", format.format(price)); } + /** + * 将金钱转成显示的格式¥xx.xx如此格式 + * + * @param price 单位为元的金额 + * @return String + */ + public static String formatPriceT(double price) { + if (price <= 0) { + return "0.00"; + } + DecimalFormat format = new DecimalFormat("0.00"); + format.setRoundingMode(RoundingMode.FLOOR); + return String.format("%s", format.format(price)); + } + /** + * 将金钱转成显示的格式¥xx.xx如此格式 + * + * @param textPrice 单位为分的金额 + * @return String + */ + public static String formatPriceT(String textPrice) { + return formatPriceT(Double.parseDouble(textPrice) / 10000); + } + } diff --git a/common_base/src/main/java/com/wss/common/utils/NetworkUtil.java b/common_base/src/main/java/com/wss/common/utils/NetworkUtil.java index d2fa331..047924f 100644 --- a/common_base/src/main/java/com/wss/common/utils/NetworkUtil.java +++ b/common_base/src/main/java/com/wss/common/utils/NetworkUtil.java @@ -6,8 +6,15 @@ import android.net.NetworkInfo; import android.telephony.TelephonyManager; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; import java.util.List; +import androidx.annotation.NonNull; + /** * Describe:网络状态工具类 * Created by 吴天强 on 2018/10/25. @@ -18,18 +25,15 @@ public class NetworkUtil { * 是否有可用网络 * * @param context context - * @return + * @return boolean */ - public static boolean isNetworkAvailable(Context context) { - ConnectivityManager connectivity = (ConnectivityManager) context - .getSystemService(Context.CONNECTIVITY_SERVICE); + public static boolean isNetworkEnabled(@NonNull Context context) { + ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); if (connectivity != null) { NetworkInfo[] info = connectivity.getAllNetworkInfo(); - if (info != null) { - for (int i = 0; i < info.length; i++) { - if (info[i].getState() == NetworkInfo.State.CONNECTED) { - return true; - } + for (NetworkInfo networkInfo : info) { + if (networkInfo.getState() == NetworkInfo.State.CONNECTED) { + return true; } } } @@ -37,60 +41,97 @@ public static boolean isNetworkAvailable(Context context) { } /** - * gps能用? + * gps能用 * - * @param context context - * @return + * @param context ctx + * @return boolean */ - public static boolean isGpsEnabled(Context context) { - LocationManager locationManager = ((LocationManager) context - .getSystemService(Context.LOCATION_SERVICE)); - List accessibleProviders = locationManager.getProviders(true); - return accessibleProviders != null && accessibleProviders.size() > 0; + public static boolean isGpsEnabled(@NonNull Context context) { + LocationManager locationManager = ((LocationManager) context.getSystemService(Context.LOCATION_SERVICE)); + if (locationManager != null) { + List accessibleProviders = locationManager.getProviders(true); + return accessibleProviders.size() > 0; + } + return false; } /** * Wifi是否可用 * * @param context context - * @return + * @return boolean */ - public static boolean isWifiEnabled(Context context) { - ConnectivityManager mgrConn = (ConnectivityManager) context - .getSystemService(Context.CONNECTIVITY_SERVICE); - TelephonyManager mgrTel = (TelephonyManager) context - .getSystemService(Context.TELEPHONY_SERVICE); - return ((mgrConn.getActiveNetworkInfo() != null && mgrConn - .getActiveNetworkInfo().getState() == NetworkInfo.State.CONNECTED) || mgrTel - .getNetworkType() == TelephonyManager.NETWORK_TYPE_UMTS); + public static boolean isWifiEnabled(@NonNull Context context) { + ConnectivityManager mgrConn = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + if (mgrConn != null && mgrConn.getActiveNetworkInfo() != null && + mgrConn.getActiveNetworkInfo().getState() == NetworkInfo.State.CONNECTED) { + return true; + } + TelephonyManager mgrTel = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + return mgrTel != null && mgrTel.getNetworkType() == TelephonyManager.NETWORK_TYPE_UMTS; } /** * 当前网络是否为Wifi * * @param context context - * @return + * @return boolean */ - public static boolean isWifi(Context context) { - ConnectivityManager connectivityManager = (ConnectivityManager) context - .getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo(); - return activeNetInfo != null - && activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI; + public static boolean isWifi(@NonNull Context context) { + ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + if (connectivityManager != null) { + NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo(); + return activeNetInfo != null && activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI; + } + return false; } /** - * 当前网络是否为收集数据 + * 当前网络是否为移动数据 * * @param context context - * @return + * @return boolean + */ + public static boolean isMobile(@NonNull Context context) { + ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + if (connectivityManager != null) { + NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo(); + return activeNetInfo != null && activeNetInfo.getType() == ConnectivityManager.TYPE_MOBILE; + } + return false; + } + + /** + * 获取当前网络IP + * + * @return 网络IP + */ + public static String getIpAddress() { + try { + for (Enumeration enNetI = NetworkInterface.getNetworkInterfaces(); enNetI + .hasMoreElements(); ) { + NetworkInterface netI = enNetI.nextElement(); + for (Enumeration enumIpAddr = netI.getInetAddresses(); enumIpAddr.hasMoreElements(); ) { + InetAddress inetAddress = enumIpAddr.nextElement(); + if (inetAddress instanceof Inet4Address && !inetAddress.isLoopbackAddress()) { + return inetAddress.getHostAddress(); + } + } + } + } catch (SocketException e) { + e.printStackTrace(); + } + return ""; + } + + /** + * 检查是否为连接 + * + * @param url url + * @return boolean */ - public static boolean is3G(Context context) { - ConnectivityManager connectivityManager = (ConnectivityManager) context - .getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo(); - return activeNetInfo != null - && activeNetInfo.getType() == ConnectivityManager.TYPE_MOBILE; + public static boolean isLink(String url) { + return ValidUtils.isValid(url) && (url.startsWith("http") || url.startsWith("https")); } } diff --git a/common_base/src/main/java/com/wss/common/utils/PermissionsUtils.java b/common_base/src/main/java/com/wss/common/utils/PermissionsUtils.java index b53bc02..d941132 100644 --- a/common_base/src/main/java/com/wss/common/utils/PermissionsUtils.java +++ b/common_base/src/main/java/com/wss/common/utils/PermissionsUtils.java @@ -1,63 +1,137 @@ package com.wss.common.utils; +import android.Manifest; import android.app.Activity; -import android.content.pm.PackageManager; -import android.os.Build; -import android.support.v4.app.ActivityCompat; -import android.support.v4.content.ContextCompat; -import java.util.ArrayList; +import com.hjq.permissions.OnPermission; +import com.hjq.permissions.Permission; +import com.hjq.permissions.XXPermissions; +import com.wss.common.base.R; + import java.util.List; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + /** - * Describe:6.0动态权限管理帮助类 + * Describe:6.0 + 动态权限管理帮助类 * Created by 吴天强 on 2018/10/25. */ - public class PermissionsUtils { + /** + * 授权所有权限 + * + * @param activity activity + */ + public static void authorizationAllPermissions(Activity activity) { + XXPermissions.with(activity) + .request(new OnPermission() { + @Override + public void hasPermission(List granted, boolean isAll) { + } + + @Override + public void noPermission(List denied, boolean quick) { + } + }); + } /** - * 判断权限 + * 检查权限 * - * @param context context - * @param permissions 权限列表 - */ - public static boolean checkPermissions(Activity context, String... permissions) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - List permissionsList = new ArrayList<>(); - if (permissions != null && permissions.length != 0) { - for (String permission : permissions) { - if (!isHavePermissions(context, permission)) { - permissionsList.add(permission); + * @param activity activity + * @param permissions 权限组 + * @return Observable + */ + public static Observable checkPermissions(Activity activity, String... permissions) { + return Observable.create( + subscriber -> { + if (XXPermissions.isHasPermission(activity, permissions)) { + subscriber.onNext(true); + } else { + XXPermissions.with(activity) + .permission(permissions) + .request(new OnPermission() { + @Override + public void hasPermission(List granted, boolean isAll) { + subscriber.onNext(isAll); + } + + @Override + public void noPermission(List denied, boolean quick) { + subscriber.onNext(false); + ToastUtils.show(activity, activity.getString(R.string.authorise_necessary_authorities)); + } + }); } - } - if (permissionsList.size() > 0) { - // 遍历完后申请 - applyPermissions(context, permissionsList); - return false; - } - } - } - return true; + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); } + /** - * 检查是否授权某权限 + * 检查相机权限 + * + * @param activity activity + * @return Observable */ - private static boolean isHavePermissions(Activity context, String permissions) { - return ContextCompat.checkSelfPermission(context, permissions) == PackageManager.PERMISSION_GRANTED; + public static Observable checkCamera(Activity activity) { + return checkPermissions(activity, Permission.CAMERA, Permission.WRITE_EXTERNAL_STORAGE); } /** - * 申请权限 + * 检查文件读写权限 + * + * @param activity activity + * @return boolean */ - private static void applyPermissions(Activity context, List permissions) { - if (!permissions.isEmpty()) { - ActivityCompat.requestPermissions(context, permissions.toArray(new String[permissions.size()]), 1); - } + public static Observable checkStorage(Activity activity) { + String[] storage = { + Permission.READ_EXTERNAL_STORAGE, + Permission.WRITE_EXTERNAL_STORAGE}; + return checkPermissions(activity, storage); } + /** + * 检查录音相关权限 + */ + public static Observable checkRecord(Activity activity) { + return checkPermissions(activity, Permission.READ_EXTERNAL_STORAGE, + Permission.WRITE_EXTERNAL_STORAGE, + Permission.RECORD_AUDIO); + } + + /** + * 检查拨打电话相关权限 + */ + public static Observable checkCallPhone(Activity activity) { + return checkPermissions(activity, Permission.CALL_PHONE); + } + + /** + * 检查定位权限 + * + * @param activity activity + * @return boolean + */ + public static Observable checkLocation(Activity activity) { + return checkPermissions(activity, Permission.ACCESS_FINE_LOCATION, + Permission.ACCESS_COARSE_LOCATION, Permission.RECORD_AUDIO); + } + + /** + * 允许锁屏状态下,app在后台运行 + * + * @param activity activity + * @return boolean + */ + public static Observable checkWakeLock(Activity activity) { + return checkPermissions(activity, Manifest.permission.WAKE_LOCK); + } + } diff --git a/common_base/src/main/java/com/wss/common/utils/PhoneUtils.java b/common_base/src/main/java/com/wss/common/utils/PhoneUtils.java new file mode 100644 index 0000000..a47b278 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/PhoneUtils.java @@ -0,0 +1,46 @@ +package com.wss.common.utils; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.net.Uri; + +import com.wss.common.base.BaseApplication; + +/** + * description: 拨打电话工具类 + * + * @author 杨伟-tony + * create by 2020/5/22 11:26 + */ +public class PhoneUtils { + /** + * 拨打电话 + * ps:调起拨号盘 + * + * @param phoneNum 电话号码 + */ + public static void callPhoneWaitFor(String phoneNum) { + Intent intent = new Intent(Intent.ACTION_DIAL); + Uri data = Uri.parse("tel:" + phoneNum); + intent.setData(data); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + BaseApplication.i().startActivity(intent); + + } + + /** + * 拨打电话 + * 吊起拨号盘 直接拨打电话 + * + * @param phoneNum 电话号码 + */ + @SuppressLint("MissingPermission") + public static void callPhoneDirect(String phoneNum) { + Intent intent = new Intent(Intent.ACTION_CALL); + Uri data = Uri.parse("tel:" + phoneNum); + intent.setData(data); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + BaseApplication.i().startActivity(intent); + } + +} diff --git a/common_base/src/main/java/com/wss/common/utils/PxUtils.java b/common_base/src/main/java/com/wss/common/utils/PxUtils.java index 005da2a..6522fa6 100644 --- a/common_base/src/main/java/com/wss/common/utils/PxUtils.java +++ b/common_base/src/main/java/com/wss/common/utils/PxUtils.java @@ -1,29 +1,43 @@ package com.wss.common.utils; import android.content.Context; +import android.graphics.Paint; +import android.view.View; + +import com.wss.common.base.BaseApplication; + +import androidx.annotation.NonNull; /** * Describe:尺寸工具类 * Created by 吴天强 on 2017/9/19. */ - public class PxUtils { /** * 得到设备屏幕的宽度 + * + * @param context ctx + * @return int */ - public static int getScreenWidth(Context context) { + public static int getScreenWidth(@NonNull Context context) { return context.getResources().getDisplayMetrics().widthPixels; } /** * 得到设备屏幕的高度 + * + * @param context ctx + * @return int */ - public static int getScreenHeight(Context context) { + public static int getScreenHeight(@NonNull Context context) { return context.getResources().getDisplayMetrics().heightPixels; } /** * 得到设备的密度 + * + * @param context ctx + * @return float */ public static float getScreenDensity(Context context) { return context.getResources().getDisplayMetrics().density; @@ -31,33 +45,64 @@ public static float getScreenDensity(Context context) { /** * 把密度转换为像素 + * + * @param dpValue dp值 + * @return int */ - public static int dp2px(Context context, float dipValue) { - final float scale = getScreenDensity(context); - return (int) (dipValue * scale + 0.5); + public static int dp2px(float dpValue) { + float scale = getScreenDensity(BaseApplication.i()); + return (int) (dpValue * scale + 0.5); } /** * 将像素转换成dp * - * @param context - * @param pxValue - * @return + * @param pxValue px值 + * @return int */ - public static int px2dp(Context context, float pxValue) { - final float scale = context.getResources().getDisplayMetrics().density; + public static int px2dp(float pxValue) { + float scale = getScreenDensity(BaseApplication.i()); return (int) (pxValue / scale + 0.5f); } /** * 将sp值转换为px值,保证文字大小不变 * - * @param context context - * @param spValue - * @return + * @param spValue sp值 + * @return int */ - public static int sp2px(Context context, float spValue) { - final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; + public static int sp2px(float spValue) { + float fontScale = getScreenDensity(BaseApplication.i()); return (int) (spValue * fontScale + 0.5f); } + + /** + * 测量 View + * + * @param measureSpec + * @param defaultSize View 的默认大小 + * @return + */ + public static int measure(int measureSpec, int defaultSize) { + int result = defaultSize; + int specMode = View.MeasureSpec.getMode(measureSpec); + int specSize = View.MeasureSpec.getSize(measureSpec); + + if (specMode == View.MeasureSpec.EXACTLY) { + result = specSize; + } else if (specMode == View.MeasureSpec.AT_MOST) { + result = Math.min(result, specSize); + } + return result; + } + /** + * 测量文字高度 + * + * @param paint + * @return + */ + public static float measureTextHeight(Paint paint) { + Paint.FontMetrics fontMetrics = paint.getFontMetrics(); + return (Math.abs(fontMetrics.ascent) - fontMetrics.descent); + } } diff --git a/common_base/src/main/java/com/wss/common/utils/RomUtil.java b/common_base/src/main/java/com/wss/common/utils/RomUtil.java new file mode 100644 index 0000000..ecc138b --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/RomUtil.java @@ -0,0 +1,152 @@ +package com.wss.common.utils; + +import android.os.Build; +import android.text.TextUtils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +/** + * Describe:判断手机ROM类型 + * Created by 吴天强 on 2020/6/24. + */ +public class RomUtil { + + public static final String ROM_MIUI = "MIUI"; + public static final String ROM_EMUI = "EMUI"; + public static final String ROM_FLYME = "FLYME"; + public static final String ROM_OPPO = "OPPO"; + public static final String ROM_SMARTISAN = "SMARTISAN"; + public static final String ROM_VIVO = "VIVO"; + public static final String ROM_QIKU = "QIKU"; + + private static final String KEY_VERSION_MIUI = "ro.miui.ui.version.name"; + private static final String KEY_VERSION_EMUI = "ro.build.version.emui"; + private static final String KEY_VERSION_OPPO = "ro.build.version.opporom"; + private static final String KEY_VERSION_SMARTISAN = "ro.smartisan.version"; + private static final String KEY_VERSION_VIVO = "ro.vivo.os.version"; + + private static String sName; + private static String sVersion; + + /** + * 华为 + * + * @return boolean + */ + public static boolean isEmui() { + return check(ROM_EMUI); + } + + /** + * 小米 + * + * @return boolean + */ + public static boolean isMiui() { + return check(ROM_MIUI); + } + + /** + * vivo + * + * @return boolean + */ + public static boolean isVivo() { + return check(ROM_VIVO); + } + + /** + * oppo + * + * @return boolean + */ + public static boolean isOppo() { + return check(ROM_OPPO); + } + + /** + * 魅族 + * + * @return boolean + */ + public static boolean isFlyme() { + return check(ROM_FLYME); + } + + /** + * 360手机 + * + * @return boolean + */ + public static boolean is360() { + return check(ROM_QIKU) || check("360"); + } + + public static boolean isSmartisan() { + return check(ROM_SMARTISAN); + } + + public static String getName() { + if (sName == null) { + check(""); + } + return sName; + } + + public static String getVersion() { + if (sVersion == null) { + check(""); + } + return sVersion; + } + + public static boolean check(String rom) { + if (sName != null) { + return sName.equals(rom); + } + if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_MIUI))) { + sName = ROM_MIUI; + } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_EMUI))) { + sName = ROM_EMUI; + } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_OPPO))) { + sName = ROM_OPPO; + } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_VIVO))) { + sName = ROM_VIVO; + } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_SMARTISAN))) { + sName = ROM_SMARTISAN; + } else { + sVersion = Build.DISPLAY; + if (sVersion.toUpperCase().contains(ROM_FLYME)) { + sName = ROM_FLYME; + } else { + sVersion = Build.UNKNOWN; + sName = Build.MANUFACTURER.toUpperCase(); + } + } + return sName.equals(rom); + } + + public static String getProp(String name) { + String line = null; + BufferedReader input = null; + try { + Process p = Runtime.getRuntime().exec("getprop " + name); + input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024); + line = input.readLine(); + input.close(); + } catch (IOException ex) { + return null; + } finally { + if (input != null) { + try { + input.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return line; + } +} diff --git a/common_base/src/main/java/com/wss/common/utils/SelectorPopupWindow.java b/common_base/src/main/java/com/wss/common/utils/SelectorPopupWindow.java new file mode 100644 index 0000000..3cb335c --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/SelectorPopupWindow.java @@ -0,0 +1,175 @@ +package com.wss.common.utils; + +import android.content.Context; +import android.graphics.Rect; +import android.graphics.drawable.ColorDrawable; +import android.os.Build; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.widget.PopupWindow; +import android.widget.TextView; + +import com.wss.common.base.R; +import com.wss.common.base.adapter.BaseListAdapter; +import com.wss.common.base.adapter.listener.OnListItemClickListener; +import com.wss.common.bean.SelectorData; + +import org.byteam.superadapter.SuperViewHolder; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +/** + * Describe:弹窗选择器 + * Created by 吴天强 on 2020/4/21. + */ +public class SelectorPopupWindow extends PopupWindow { + + private Context context; + private View parent; + private OnItemClickListener itemClickListener; + private PopupWindow.OnDismissListener dismissListener; + private List dataList = new ArrayList<>(); + private String defaultChecked; + + /** + * @param context context + * @param parent 显示位置父控件 + */ + public SelectorPopupWindow(Context context, View parent, List dataList) { + this.context = context; + this.parent = parent; + this.dataList.addAll(dataList); + } + + + /** + * 弹窗消失监听 + * + * @param dismissListener 监听 + * @return SelectorPopupWindow + */ + public SelectorPopupWindow setDismissListener(PopupWindow.OnDismissListener dismissListener) { + this.dismissListener = dismissListener; + return this; + } + + /** + * Item点击事件 + * + * @param itemClickListener 事件 + */ + public SelectorPopupWindow setOnItemClickListener(OnItemClickListener itemClickListener) { + this.itemClickListener = itemClickListener; + return this; + } + + /** + * 默认选择项 + * + * @param defaultChecked 默认值 + * @return SelectorPopupWindow + */ + public SelectorPopupWindow setDefaultChecked(String defaultChecked) { + this.defaultChecked = defaultChecked; + return this; + } + + public void show() { + initView(ViewGroup.LayoutParams.MATCH_PARENT); + } + + /** + * 显示自定义宽度值 + * + * @param value 宽度值 + */ + public void showMonthPopup(int value) { + initView(PxUtils.dp2px(value)); + } + + private void initView(int width) { + View childView = View.inflate(context, R.layout.pop_selector, null); + childView.findViewById(R.id.close).setOnClickListener(v -> dismiss()); + initItems(childView); + setWidth(width); + setHeight(ViewGroup.LayoutParams.MATCH_PARENT); + ColorDrawable dw = new ColorDrawable(0); + setBackgroundDrawable(dw); + setFocusable(true); + setOutsideTouchable(true); + setContentView(childView); + showAsDropDown(parent); + update(); + setOnDismissListener(dismissListener); + } + + private void initItems(@NotNull View childView) { + RecyclerView recyclerView = childView.findViewById(R.id.recycle_view); + recyclerView.setLayoutManager(new LinearLayoutManager(context)); + recyclerView.setAdapter(new SelectorAdapter(context, dataList, R.layout.item_of_selector_pop, + (data, position) -> { + if (itemClickListener != null) { + itemClickListener.onItemClick(data); + } + dismiss(); + }, defaultChecked)); + } + + + @Override + public void showAsDropDown(View anchor) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + Rect visibleFrame = new Rect(); + anchor.getGlobalVisibleRect(visibleFrame); + int height; + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1 && !RomUtil.isVivo()) { + //9.0 + height = anchor.getResources().getDisplayMetrics().heightPixels - (visibleFrame.bottom - PxUtils.dp2px(30)); + } else { + height = anchor.getResources().getDisplayMetrics().heightPixels - visibleFrame.bottom; + } + setHeight(height); + } + super.showAsDropDown(anchor); + } + + /** + * 列表适配器 + */ + private static class SelectorAdapter extends BaseListAdapter { + + private String defaultChecked; + + SelectorAdapter(Context context, List mData, int layoutResId, OnListItemClickListener listener, String defaultChecked) { + super(context, mData, layoutResId, listener); + this.defaultChecked = defaultChecked; + } + + @Override + public void onBindData(@NotNull SuperViewHolder holder, int viewType, int layoutPosition, @NotNull SelectorData data) { + TextView tvName = holder.findViewById(R.id.tv_name); + tvName.setText(data.getName()); + tvName.setSelected(TextUtils.equals(defaultChecked, data.getName())); + } + } + + + /** + * Item点击事件监听 + */ + public interface OnItemClickListener { + + /** + * Item点击回调 + * + * @param data 选择数据 + */ + void onItemClick(SelectorData data); + } +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/utils/StringUtils.java b/common_base/src/main/java/com/wss/common/utils/StringUtils.java deleted file mode 100644 index 55a80df..0000000 --- a/common_base/src/main/java/com/wss/common/utils/StringUtils.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.wss.common.utils; - -/** - * Describe:字符串工具类 - * Created by 吴天强 on 2018/10/17. - */ - -public class StringUtils { - - -} diff --git a/common_base/src/main/java/com/wss/common/utils/SystemUtils.java b/common_base/src/main/java/com/wss/common/utils/SystemUtils.java new file mode 100644 index 0000000..54c55a1 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/SystemUtils.java @@ -0,0 +1,247 @@ +package com.wss.common.utils; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.os.Build; +import android.provider.Settings; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.security.MessageDigest; +import java.util.Locale; +import java.util.UUID; + +/** + * Describe:系统工具类 + * Created by 吴天强 on 2019/5/5. + */ +public class SystemUtils { + /** + * 获取当前手机系统语言。 + * + * @return 返回当前系统语言。例如:当前设置的是“中文-中国”,则返回“zh-CN” + */ + @NotNull + public static String getSystemLanguage() { + return Locale.getDefault().getLanguage(); + } + + /** + * 获取当前系统上的语言列表(Locale列表) + * + * @return 语言列表 + */ + @NotNull + public static Locale[] getSystemLanguageList() { + return Locale.getAvailableLocales(); + } + + /** + * 获取当前手机系统版本号 + * + * @return 系统版本号 + */ + @Contract(pure = true) + public static String getSystemVersion() { + return android.os.Build.VERSION.RELEASE; + } + + /** + * 获取手机型号 + * + * @return 手机型号 + */ + @Contract(pure = true) + public static String getSystemModel() { + return android.os.Build.MODEL; + } + + /** + * 获取手机厂商 + * + * @return 手机厂商 + */ + @Contract(pure = true) + public static String getDeviceBrand() { + return android.os.Build.BRAND; + } + + /** + * 获取手机IMEI(需要“android.permission.READ_PHONE_STATE”权限) + * + * @return 手机IMEI + */ + @Nullable + public static String getDeviceId(@NotNull Context context) { + StringBuilder sbDeviceId = new StringBuilder(); + + //获得设备默认IMEI(>=6.0 需要ReadPhoneState权限) + //获得AndroidId(无需权限) + String androidId = getAndroidId(context); + //获得设备序列号(无需权限) + String serial = getSerial(); + //获得硬件uuid(根据硬件相关属性,生成uuid)(无需权限) + String uuid = getDeviceUUID().replace("-", ""); + //追加androidId + if (androidId != null && androidId.length() > 0) { + sbDeviceId.append(androidId); + sbDeviceId.append("|"); + } + //追加serial + if (serial != null && serial.length() > 0) { + sbDeviceId.append(serial); + sbDeviceId.append("|"); + } + //追加硬件uuid + if (uuid.length() > 0) { + sbDeviceId.append(uuid); + } + + //生成SHA1,统一DeviceId长度 + if (sbDeviceId.length() > 0) { + try { + byte[] hash = getHashByString(sbDeviceId.toString()); + String sha1 = bytesToHex(hash); + if (sha1.length() > 0) { + //返回最终的DeviceId + return sha1; + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + //如果以上硬件标识数据均无法获得, + //则DeviceId默认使用系统随机数,这样保证DeviceId不为空 + return UUID.randomUUID().toString().replace("-", ""); + } + + + /** + * 获得设备的AndroidId + * + * @param context 上下文 + * @return 设备的AndroidId + */ + @SuppressLint("HardwareIds") + private static String getAndroidId(Context context) { + try { + return Settings.Secure.getString(context.getContentResolver(), + Settings.Secure.ANDROID_ID); + } catch (Exception ex) { + ex.printStackTrace(); + } + return ""; + } + + /** + * 获得设备序列号(如:WTK7N16923005607), 个别设备无法获取 + * + * @return 设备序列号 + */ + private static String getSerial() { + try { + return Build.SERIAL; + } catch (Exception ex) { + ex.printStackTrace(); + } + return ""; + } + + /** + * 获得设备硬件uuid + * 使用硬件信息,计算出一个随机数 + * + * @return 设备硬件uuid + */ + @NotNull + private static String getDeviceUUID() { + try { + String dev = "3883756" + + Build.BOARD.length() % 10 + + Build.BRAND.length() % 10 + + Build.DEVICE.length() % 10 + + Build.HARDWARE.length() % 10 + + Build.ID.length() % 10 + + Build.MODEL.length() % 10 + + Build.PRODUCT.length() % 10 + + Build.SERIAL.length() % 10; + return new UUID(dev.hashCode(), + Build.SERIAL.hashCode()).toString(); + } catch (Exception ex) { + ex.printStackTrace(); + return ""; + } + } + + /** + * 取SHA1 + * + * @param data 数据 + * @return 对应的hash值 + */ + private static byte[] getHashByString(String data) { + try { + MessageDigest messageDigest = MessageDigest.getInstance("SHA1"); + messageDigest.reset(); + messageDigest.update(data.getBytes("UTF-8")); + return messageDigest.digest(); + } catch (Exception e) { + return "".getBytes(); + } + } + + /** + * 转16进制字符串 + * + * @param data 数据 + * @return 16进制字符串 + */ + @NotNull + private static String bytesToHex(@NotNull byte[] data) { + StringBuilder sb = new StringBuilder(); + String stmp; + for (byte datum : data) { + stmp = (Integer.toHexString(datum & 0xFF)); + if (stmp.length() == 1) { + sb.append("0"); + } + sb.append(stmp); + } + return sb.toString().toUpperCase(Locale.CHINA); + } + + + public static int getStatusBarHeight(@NotNull Context context) { + int result = 0; + int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); + if (resourceId > 0) { + result = context.getResources().getDimensionPixelSize(resourceId); + } + return result; + } + + public static int getScreenWidth(Context context) { + int screenWith = -1; + try { + screenWith = context.getResources().getDisplayMetrics().widthPixels; + } catch (Exception e) { + e.printStackTrace(); + } + return screenWith; + } + + public static int getScreenHeight(Context context) { + int screenHeight = -1; + try { + screenHeight = context.getResources().getDisplayMetrics().heightPixels; + } catch (Exception e) { + e.printStackTrace(); + } + return screenHeight; + } + + +} diff --git a/common_base/src/main/java/com/wss/common/utils/ToastUtils.java b/common_base/src/main/java/com/wss/common/utils/ToastUtils.java index bf07c16..4ed6680 100644 --- a/common_base/src/main/java/com/wss/common/utils/ToastUtils.java +++ b/common_base/src/main/java/com/wss/common/utils/ToastUtils.java @@ -1,40 +1,382 @@ package com.wss.common.utils; +import android.app.AppOpsManager; +import android.app.Application; +import android.app.NotificationManager; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.res.Resources; +import android.graphics.drawable.GradientDrawable; +import android.os.Build; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; import android.widget.Toast; +import com.wss.common.utils.toast.BaseToast; +import com.wss.common.utils.toast.IToastInterceptor; +import com.wss.common.utils.toast.IToastStrategy; +import com.wss.common.utils.toast.IToastStyle; +import com.wss.common.utils.toast.SafeToast; +import com.wss.common.utils.toast.SupportToast; +import com.wss.common.utils.toast.ToastInterceptor; +import com.wss.common.utils.toast.ToastStrategy; +import com.wss.common.utils.toast.style.ToastBlackStyle; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + /** * Describe:Toast * Created by 吴天强 on 2017/11/2. */ +public final class ToastUtils { + + private static IToastInterceptor sInterceptor; + + private static IToastStrategy sStrategy; + + private static Toast sToast; + + /** + * 不允许外部实例化 + */ + private ToastUtils() { + } + + /** + * 初始化 ToastUtils,在 Application 中初始化 + * + * @param application 应用的上下文 + */ + public static void init(Application application) { + init(application, new ToastBlackStyle(application)); + } + + /** + * 初始化 ToastUtils 及样式 + * + * @param application 应用的上下文 + * @param style Toast样式 + */ + public static void init(Application application, IToastStyle style) { + checkNullPointer(application); + // 初始化 Toast 拦截器 + if (sInterceptor == null) { + setToastInterceptor(new ToastInterceptor()); + } + + // 初始化 Toast 显示处理器 + if (sStrategy == null) { + setToastStrategy(new ToastStrategy()); + } + + // 初始化吐司 + if (areNotificationsEnabled(application)) { + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) { + // 解决 Android 7.1 上主线程被阻塞后吐司会报错的问题 + setToast(new SafeToast(application)); + } else { + setToast(new BaseToast(application)); + } + } else { + // 解决关闭通知栏权限后 Toast 不显示的问题 + setToast(new SupportToast(application)); + } + + // 设置 Toast 视图 + setView(createTextView(application, style)); + + // 设置 Toast 重心 + setGravity(style.getGravity(), style.getXOffset(), style.getYOffset()); + } + + /** + * 显示一个对象的吐司 + * + * @param object 对象 + */ + public static void show(Object object) { + show(object != null ? object.toString() : "null"); + } + + /** + * 显示一个吐司 + * + * @param id 如果传入的是正确的 string id 就显示对应字符串 + * 如果不是则显示一个整数的string + */ + public static void show(int id) { + checkToastState(); + try { + // 如果这是一个资源 id + show(getContext().getResources().getText(id)); + } catch (Resources.NotFoundException ignored) { + // 如果这是一个 int 整数 + show(String.valueOf(id)); + } + } + + /** + * 显示一个吐司 + * + * @param id 资源 id + * @param args 参数集 + */ + public static void show(int id, Object... args) { + show(getContext().getResources().getString(id), args); + } + + /** + * 显示一个吐司 + * + * @param format 原字符串 + * @param args 参数集 + */ + public static void show(String format, Object... args) { + show(String.format(format, args)); + } + + /** + * 显示一个吐司 + * + * @param text 需要显示的文本 + */ + public static synchronized void show(CharSequence text) { + checkToastState(); + if (sInterceptor.intercept(sToast, text)) { + return; + } + sStrategy.show(text); + } + -public class ToastUtils { + //***************************************兼容老的Toast的调用方法 start************************************* - public static void showToast(Context context, int strings) { - showToast(context, context.getString(strings)); + /** + * 老的Toast调用方法 + * + * @param context context + * @param text 显示的内容 + */ + public static void show(Context context, String text) { + show(text); } + //***************************************兼容老的Toast的调用方法 end************************************* - public static void showToast(Context context, String text) { -// showToast(context, title, Gravity.BOTTOM); - Toast.makeText(context, text, Toast.LENGTH_SHORT).show(); + /** + * 取消吐司的显示 + */ + public static synchronized void cancel() { + checkToastState(); + + sStrategy.cancel(); } /** - * 自定义显示Toast弹出提示框 + * 设置吐司的位置 * - * @param s s - * @param gravity 弹出位置 + * @param gravity 重心 + * @param xOffset x轴偏移 + * @param yOffset y轴偏移 + */ + private static void setGravity(int gravity, int xOffset, int yOffset) { + checkToastState(); + gravity = Gravity.getAbsoluteGravity(gravity, sToast.getView().getResources().getConfiguration().getLayoutDirection()); + sToast.setGravity(gravity, xOffset, yOffset); + } + + /** + * 给当前Toast设置新的布局,具体实现可看{@link BaseToast#setView(View)} + */ + public static void setView(int id) { + checkToastState(); + + setView(View.inflate(getContext(), id, null)); + } + + public static void setView(View view) { + checkToastState(); + + // 这个 View 不能为空 + checkNullPointer(view); + + // 当前必须用 Application 的上下文创建的 View,否则可能会导致内存泄露 + Context context = view.getContext(); + if (!(context instanceof Application)) { + throw new IllegalArgumentException("The view must be initialized using the context of the application"); + } + + // 如果吐司已经创建,就重新初始化吐司 + if (sToast != null) { + // 取消原有吐司的显示 + sToast.cancel(); + sToast.setView(view); + } + } + + /** + * 获取当前 Toast 的视图 + */ + @SuppressWarnings("unchecked") + public static V getView() { + checkToastState(); + + return (V) sToast.getView(); + } + + /** + * 初始化全局的Toast样式 + * + * @param style 样式实现类,框架已经实现三种不同的样式 + */ + public static void initStyle(IToastStyle style) { + checkNullPointer(style); + // 如果吐司已经创建,就重新初始化吐司 + if (sToast != null) { + // 取消原有吐司的显示 + sToast.cancel(); + sToast.setView(createTextView(getContext(), style)); + sToast.setGravity(style.getGravity(), style.getXOffset(), style.getYOffset()); + } + } + + /** + * 设置当前Toast对象 + */ + public static void setToast(Toast toast) { + checkNullPointer(toast); + if (sToast != null && toast.getView() == null) { + // 移花接木 + toast.setView(sToast.getView()); + toast.setGravity(sToast.getGravity(), sToast.getXOffset(), sToast.getYOffset()); + toast.setMargin(sToast.getHorizontalMargin(), sToast.getVerticalMargin()); + } + sToast = toast; + if (sStrategy != null) { + sStrategy.bind(sToast); + } + } + + /** + * 设置 Toast 显示策略 + */ + public static void setToastStrategy(IToastStrategy handler) { + checkNullPointer(handler); + sStrategy = handler; + if (sToast != null) { + sStrategy.bind(sToast); + } + } + + /** + * 设置 Toast 拦截器(可以根据显示的内容决定是否拦截这个Toast) + * 场景:打印 Toast 内容日志、根据 Toast 内容是否包含敏感字来动态切换其他方式显示(这里可以使用我的另外一套框架 XToast) + */ + public static void setToastInterceptor(IToastInterceptor interceptor) { + checkNullPointer(interceptor); + sInterceptor = interceptor; + } + + /** + * 获取当前Toast对象 + */ + public static Toast getToast() { + return sToast; + } + + /** + * 检查吐司状态,如果未初始化请先调用{@link com.wss.common.utils.ToastUtils#init(Application)} + */ + private static void checkToastState() { + // 吐司工具类还没有被初始化,必须要先调用init方法进行初始化 + if (sToast == null) { + throw new IllegalStateException("ToastUtils has not been initialized"); + } + } + + /** + * 检查对象是否为空 + */ + private static void checkNullPointer(Object object) { + if (object == null) { + throw new NullPointerException("are you ok?"); + } + } + + /** + * 生成默认的 TextView 对象 + */ + private static TextView createTextView(Context context, IToastStyle style) { + + GradientDrawable drawable = new GradientDrawable(); + // 设置背景色 + drawable.setColor(style.getBackgroundColor()); + // 设置圆角大小 + drawable.setCornerRadius(style.getCornerRadius()); + + TextView textView = new TextView(context); + textView.setId(android.R.id.message); + textView.setTextColor(style.getTextColor()); + textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, style.getTextSize()); + + // 适配布局反方向 + textView.setPaddingRelative(style.getPaddingStart(), style.getPaddingTop(), style.getPaddingEnd(), style.getPaddingBottom()); + + textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + + // setBackground API 版本兼容 + textView.setBackground(drawable); + + // 设置 Z 轴阴影 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + textView.setZ(style.getZ()); + } + + // 设置最大显示行数 + if (style.getMaxLines() > 0) { + textView.setMaxLines(style.getMaxLines()); + } + + return textView; + } + + /** + * 获取上下文对象 + */ + private static Context getContext() { + checkToastState(); + return sToast.getView().getContext(); + } + + /** + * 检查通知栏权限有没有开启 + * 参考 SupportCompat 包中的方法: NotificationManagerCompat.from(context).areNotificationsEnabled(); */ + private static boolean areNotificationsEnabled(Context context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + return manager != null && manager.areNotificationsEnabled(); + } else { + AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + ApplicationInfo appInfo = context.getApplicationInfo(); + String packageName = context.getApplicationContext().getPackageName(); + int uid = appInfo.uid; - public static void showToast(Context context, CharSequence s, int gravity) { -// Toast toast = new Toast(context); -// View toastView = View.inflate(context, R.layout.toast, null); -// toast.setView(toastView); -// toast.setDuration(Toast.LENGTH_SHORT); -// TextView textView = toastView.findViewById(R.id.tv_message); -// textView.setText(s); -// toast.setGravity(gravity, 0, 100); -// toast.show(); + try { + Class appOpsClass = Class.forName(AppOpsManager.class.getName()); + Method checkOpNoThrowMethod = appOpsClass.getMethod("checkOpNoThrow", Integer.TYPE, Integer.TYPE, String.class); + Field opPostNotificationValue = appOpsClass.getDeclaredField("OP_POST_NOTIFICATION"); + int value = Integer.parseInt(String.valueOf(opPostNotificationValue.get(Integer.class))); + return ((int) checkOpNoThrowMethod.invoke(appOps, value, uid, packageName) == AppOpsManager.MODE_ALLOWED); + } catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException + | InvocationTargetException | IllegalAccessException | RuntimeException ignored) { + return true; + } + } } } diff --git a/common_base/src/main/java/com/wss/common/utils/UserInfoUtils.java b/common_base/src/main/java/com/wss/common/utils/UserInfoUtils.java deleted file mode 100644 index d898e31..0000000 --- a/common_base/src/main/java/com/wss/common/utils/UserInfoUtils.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.wss.common.utils; - -import com.wss.common.base.BaseApplication; -import com.wss.common.bean.User; -import com.wss.common.constants.CacheKey; - -/** - * Describe:用户信息帮助类 - * Created by 吴天强 on 2018/11/13. - */ - -public class UserInfoUtils { - - - /** - * 保存用户信息 - * - * @param user user - */ - public static void saveUser(User user) { - CacheUtils.get(BaseApplication.getApplication()) - .put(CacheKey.USER_INFO, user); - CacheUtils.get(BaseApplication.getApplication()) - .put(CacheKey.USER_LOGGED, true); - } - - /** - * 获取用户信息 - * - * @return user - */ - public static User getUser() { - User user = (User) CacheUtils.get(BaseApplication.getApplication()) - .getAsObject(CacheKey.USER_INFO); - if (user == null) { - user = new User(); - } - return user; - } - - /** - * 清除用户信息 - */ - public static void cleanUser() { - saveUser(null); - CacheUtils.get(BaseApplication.getApplication()) - .put(CacheKey.USER_LOGGED, false); - } - - /** - * 是否登录 - * - * @return boolean - */ - public static boolean isLogged() { - Object result = CacheUtils.get(BaseApplication.getApplication()) - .getAsObject(CacheKey.USER_LOGGED); - return result != null && (boolean) result; - } - -} diff --git a/common_base/src/main/java/com/wss/common/utils/Utils.java b/common_base/src/main/java/com/wss/common/utils/Utils.java index fe99f9f..63c460f 100644 --- a/common_base/src/main/java/com/wss/common/utils/Utils.java +++ b/common_base/src/main/java/com/wss/common/utils/Utils.java @@ -1,35 +1,42 @@ package com.wss.common.utils; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; +import android.graphics.drawable.GradientDrawable; +import android.net.Uri; +import android.widget.TextView; import com.wss.common.base.BaseApplication; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.regex.Matcher; import java.util.regex.Pattern; +import androidx.annotation.NonNull; + /** * Describe:工具类 * Created by 吴天强 on 2018/10/15. */ - public class Utils { - /** * 读取 asset下的文件 * * @param context context * @param fileName fileName - * @return + * @return String */ - public static String getAssetFileData(Context context, String fileName) { - + @NonNull + public static String getAssetFileData(@NotNull Context context, String fileName) { StringBuilder stringBuilder = new StringBuilder(); try { AssetManager assetManager = context.getAssets(); @@ -76,13 +83,23 @@ public static boolean isNumber(String str) { return isNum.matches(); } + /** + * 判断是否为电话,只校验位数 + * + * @param str str + * @return boolean + */ + public static boolean isPhone(String str) { + return ValidUtils.isValid(str) && str.length() == 11; + } + /** * 获取APP包名 * * @return String */ public static String getPackageName() { - return BaseApplication.getApplication().getPackageName(); + return BaseApplication.i().getPackageName(); } /** @@ -91,7 +108,7 @@ public static String getPackageName() { * @return String */ public static String getVersionName() { - PackageManager packageManager = BaseApplication.getApplication().getPackageManager(); + PackageManager packageManager = BaseApplication.i().getPackageManager(); try { PackageInfo packageInfo = packageManager.getPackageInfo(getPackageName(), 0); return packageInfo.versionName; @@ -107,7 +124,7 @@ public static String getVersionName() { * @return Integer */ public static Integer getVersionCode() { - PackageManager packageManager = BaseApplication.getApplication().getPackageManager(); + PackageManager packageManager = BaseApplication.i().getPackageManager(); try { PackageInfo packageInfo = packageManager.getPackageInfo( getPackageName(), 0); @@ -117,4 +134,71 @@ public static Integer getVersionCode() { } return 0; } + + /** + * 设置TextView的背景色 + * + * @param textView textView + * @param color 颜色 + */ + public static void setTextViewDrawable(@NotNull TextView textView, int color) { + setTextViewDrawable(textView, color, 4); + } + + /** + * 设置TextView的背景色 + * + * @param textView textView + * @param color 颜色 + * @param radius 圆角角度 + */ + public static void setTextViewDrawable(@NotNull TextView textView, int color, float radius) { + GradientDrawable drawable = new GradientDrawable(); + drawable.setCornerRadius(radius); + drawable.setColor(color); + textView.setBackground(drawable); + } + + /** + * 跳转浏览器 + */ + public static void toSystemBrowser(@NonNull Context context, String url) { + //应用内下载失败 跳转浏览器下载 + Intent intent = new Intent(); + intent.setAction("android.intent.action.VIEW"); + Uri contentUrl = Uri.parse(url); + intent.setData(contentUrl); + context.startActivity(intent); + } + + + + + /** + * 电话号码中间替换成* + * + * @param phone 原电话 + * @return 替换后的电话 + */ + @Contract("_ -> param1") + public static String replacePhone(String phone) { + if (!isPhone(phone)) { + return phone; + } + String replace = phone.substring(3, 7); + return phone.replace(replace, "****"); + } + + /** + * 把等于null的字符串转成“” + * + * @param text 原字符串 + * @return 转换后字符串 + */ + public static String checkText(String text) { + if (!ValidUtils.isValid(text)) { + return ""; + } + return text; + } } diff --git a/common_base/src/main/java/com/wss/common/utils/ValidUtils.java b/common_base/src/main/java/com/wss/common/utils/ValidUtils.java new file mode 100644 index 0000000..822401d --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/ValidUtils.java @@ -0,0 +1,39 @@ +package com.wss.common.utils; + +import android.text.TextUtils; + +import org.jetbrains.annotations.Contract; + +import java.util.Collection; +import java.util.Map; + +/** + * 对象空判断验证类 + * Created by 吴天强 on 2017/12/3. + */ +public class ValidUtils { + @Contract(value = "null -> false", pure = true) + public static boolean isValid(Collection collection) { + return collection != null && !collection.isEmpty(); + } + + @Contract("null, _ -> false") + public static boolean isValid(Collection collection, int position) { + return collection != null && !collection.isEmpty() && collection.size() > position; + } + + @Contract(value = "null -> false", pure = true) + public static boolean isValid(Map map) { + return map != null && !map.isEmpty(); + } + + @Contract("null -> false") + public static boolean isValid(String str) { + return !TextUtils.isEmpty(str); + } + + @Contract(value = "null -> false; !null -> true", pure = true) + public static boolean isValid(Object obj) { + return obj != null; + } +} diff --git a/common_base/src/main/java/com/wss/common/utils/ZipUtils.java b/common_base/src/main/java/com/wss/common/utils/ZipUtils.java deleted file mode 100644 index eafd00a..0000000 --- a/common_base/src/main/java/com/wss/common/utils/ZipUtils.java +++ /dev/null @@ -1,390 +0,0 @@ -package com.wss.common.utils; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Enumeration; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; -import java.util.zip.ZipOutputStream; - -/** - * Java utils 实现的Zip工具 - * - * @author miaowei - */ -public class ZipUtils { - - private static final int BUFF_SIZE = 1024 * 1024; // 1M Byte - - /** - * 批量压缩文件(夹) - * - * @param resFileList 要压缩的文件(夹)列表 - * @param zipFile 生成的压缩文件 - * @throws IOException 当压缩过程出错时抛出 - */ - public static void zipFiles(Collection resFileList, File zipFile) throws IOException { - if (resFileList != null && zipFile != null) { - ZipOutputStream zipout = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile), BUFF_SIZE)); - for (File resFile : resFileList) { - zipFile(resFile, zipout, ""); - } - zipout.close(); - } - } - - /** - * 批量压缩文件(夹) - * - * @param resFileList 要压缩的文件(夹)列表 - * @param zipFile 生成的压缩文件 - * @param comment 压缩文件的注释 - * @throws IOException 当压缩过程出错时抛出 - */ - public static void zipFiles(Collection resFileList, File zipFile, String comment) throws IOException { - ZipOutputStream zipout = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile), BUFF_SIZE)); - for (File resFile : resFileList) { - zipFile(resFile, zipout, ""); - } - zipout.setComment(comment); - zipout.close(); - } - - /** - * 解压缩一个文件 - * - * @param zipFile 压缩文件 - * @param folderPath 解压缩的目标目录 - * @throws IOException 当解压缩过程出错时抛出 - */ - public static void upZipFile(File zipFile, String folderPath) throws IOException { - File desDir = new File(folderPath); - if (!desDir.exists()) { - desDir.mkdirs(); - } - ZipFile zf = new ZipFile(zipFile); - for (Enumeration entries = zf.entries(); entries.hasMoreElements(); ) { - ZipEntry entry = ((ZipEntry) entries.nextElement()); - if (entry.isDirectory()) { - - continue; - } - InputStream in = zf.getInputStream(entry); - String str = folderPath + File.separator + entry.getName(); - str = new String(str.getBytes(), "utf-8"); - File desFile = new File(str); - if (!desFile.exists()) { - File fileParentDir = desFile.getParentFile(); - if (!fileParentDir.exists()) { - fileParentDir.mkdirs(); - } - desFile.createNewFile(); - } - OutputStream out = new FileOutputStream(desFile); - byte buffer[] = new byte[BUFF_SIZE]; - int realLength; - while ((realLength = in.read(buffer)) > 0) { - out.write(buffer, 0, realLength); - } - in.close(); - out.close(); - } - } - - /** - * 解压文件名包含传入文字的文件 - * - * @param zipFile 压缩文件 - * @param folderPath 目标文件夹 - * @param nameContains 传入的文件匹配名 - * @throws ZipException 压缩格式有误时抛出 - * @throws IOException IO错误时抛出 - */ - public static ArrayList upZipSelectedFile(File zipFile, String folderPath, String nameContains) throws IOException { - ArrayList fileList = new ArrayList(); - - File desDir = new File(folderPath); - if (!desDir.exists()) { - desDir.mkdir(); - } - - ZipFile zf = new ZipFile(zipFile); - for (Enumeration entries = zf.entries(); entries.hasMoreElements(); ) { - ZipEntry entry = ((ZipEntry) entries.nextElement()); - if (entry.getName().contains(nameContains)) { - InputStream in = zf.getInputStream(entry); - String str = folderPath + File.separator + entry.getName(); - str = new String(str.getBytes("utf-8"), "gbk"); - // str.getBytes("GB2312"),"8859_1" 输出 - // str.getBytes("8859_1"),"GB2312" 输入 - File desFile = new File(str); - if (!desFile.exists()) { - File fileParentDir = desFile.getParentFile(); - if (!fileParentDir.exists()) { - fileParentDir.mkdirs(); - } - desFile.createNewFile(); - } - OutputStream out = new FileOutputStream(desFile); - byte buffer[] = new byte[BUFF_SIZE]; - int realLength; - while ((realLength = in.read(buffer)) > 0) { - out.write(buffer, 0, realLength); - } - in.close(); - out.close(); - fileList.add(desFile); - } - } - return fileList; - } - - /** - * 获得压缩文件内文件列表 - * - * @param zipFile 压缩文件 - * @return 压缩文件内文件名称 - * @throws ZipException 压缩文件格式有误时抛出 - * @throws IOException 当解压缩过程出错时抛出 - */ - public static ArrayList getEntriesNames(File zipFile) throws IOException { - ArrayList entryNames = new ArrayList(); - Enumeration entries = getEntriesEnumeration(zipFile); - while (entries.hasMoreElements()) { - ZipEntry entry = ((ZipEntry) entries.nextElement()); - entryNames.add(new String(getEntryName(entry).getBytes("GB2312"), "8859_1")); - } - return entryNames; - } - - /** - * 获得压缩文件内压缩文件对象以取得其属性 - * - * @param zipFile 压缩文件 - * @return 返回一个压缩文件列表 - * @throws ZipException 压缩文件格式有误时抛出 - * @throws IOException IO操作有误时抛出 - */ - public static Enumeration getEntriesEnumeration(File zipFile) throws IOException { - ZipFile zf = new ZipFile(zipFile); - return zf.entries(); - - } - - /** - * 取得压缩文件对象的注释 - * - * @param entry 压缩文件对象 - * @return 压缩文件对象的注释 - * @throws UnsupportedEncodingException - */ - public static String getEntryComment(ZipEntry entry) throws UnsupportedEncodingException { - return new String(entry.getComment().getBytes("GB2312"), "8859_1"); - } - - /** - * 取得压缩文件对象的名称 - * - * @param entry 压缩文件对象 - * @return 压缩文件对象的名称 - * @throws UnsupportedEncodingException - */ - public static String getEntryName(ZipEntry entry) throws UnsupportedEncodingException { - return new String(entry.getName().getBytes("GB2312"), "8859_1"); - } - - /** - * 压缩文件 - * - * @param resFile 需要压缩的文件(夹) - * @param zipout 压缩的目的文件 - * @param rootpath 压缩的文件路径 - * @throws FileNotFoundException 找不到文件时抛出 - * @throws IOException 当压缩过程出错时抛出 - */ - private static void zipFile(File resFile, ZipOutputStream zipout, String rootpath) throws IOException { - rootpath = rootpath + (rootpath.trim().length() == 0 ? "" : File.separator) + resFile - .getName(); - rootpath = new String(rootpath.getBytes(), "utf-8"); - if (resFile.isDirectory()) { - File[] fileList = resFile.listFiles(); - for (File file : fileList) { - zipFile(file, zipout, rootpath); - } - } else { - byte buffer[] = new byte[BUFF_SIZE]; - BufferedInputStream in = new BufferedInputStream(new FileInputStream(resFile), BUFF_SIZE); - zipout.putNextEntry(new ZipEntry(rootpath)); - int realLength; - while ((realLength = in.read(buffer)) != -1) { - zipout.write(buffer, 0, realLength); - } - in.close(); - zipout.flush(); - zipout.closeEntry(); - } - } - - //第二种实现 - public static void zip(String src, String dest) throws IOException { - // 提供了一个数据项压缩成一个ZIP归档输出流 - ZipOutputStream out = null; - try { - - //DirTraversal.makeRootDirectory(dest); - //File outFile = DirTraversal.getFilePath(dest,"cache.zip"); - - File outFile = new File(dest);// 源文件或者目录 - File fileOrDirectory = new File(src);// 压缩文件路径 - out = new ZipOutputStream(new FileOutputStream(outFile)); - // 如果此文件是一个文件,否则为false。 - if (fileOrDirectory.isFile()) { - zipFileOrDirectory(out, fileOrDirectory, ""); - } else { - // 返回一个文件或空阵列。 - File[] entries = fileOrDirectory.listFiles(); - for (int i = 0; i < entries.length; i++) { - // 递归压缩,更新curPaths - zipFileOrDirectory(out, entries[i], ""); - } - } - } catch (IOException ex) { - ex.printStackTrace(); - } finally { - // 关闭输出流 - if (out != null) { - try { - out.close(); - } catch (IOException ex) { - ex.printStackTrace(); - } - } - } - } - - private static void zipFileOrDirectory(ZipOutputStream out, File fileOrDirectory, String curPath) throws IOException { - // 从文件中读取字节的输入流 - FileInputStream in = null; - try { - // 如果此文件是一个目录,否则返回false。 - if (!fileOrDirectory.isDirectory()) { - // 压缩文件 - byte[] buffer = new byte[4096]; - int bytes_read; - in = new FileInputStream(fileOrDirectory); - // 实例代表一个条目内的ZIP归档 - ZipEntry entry = new ZipEntry(curPath + fileOrDirectory.getName()); - // 条目的信息写入底层流 - out.putNextEntry(entry); - while ((bytes_read = in.read(buffer)) != -1) { - out.write(buffer, 0, bytes_read); - } - out.closeEntry(); - } else { - // 压缩目录 - File[] entries = fileOrDirectory.listFiles(); - for (int i = 0; i < entries.length; i++) { - // 递归压缩,更新curPaths - zipFileOrDirectory(out, entries[i], curPath + fileOrDirectory.getName() + "/"); - } - } - } catch (IOException ex) { - ex.printStackTrace(); - // throw ex; - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException ex) { - ex.printStackTrace(); - } - } - } - } - - @SuppressWarnings("unchecked") - public static void unzip(String zipFileName, String outputDirectory) throws IOException { - ZipFile zipFile = null; - try { - zipFile = new ZipFile(zipFileName); - Enumeration e = zipFile.entries(); - ZipEntry zipEntry = null; - File dest = new File(outputDirectory); - dest.mkdirs(); - while (e.hasMoreElements()) { - zipEntry = (ZipEntry) e.nextElement(); - String entryName = zipEntry.getName(); - InputStream in = null; - FileOutputStream out = null; - try { - if (zipEntry.isDirectory()) { - String name = zipEntry.getName(); - name = name.substring(0, name.length() - 1); - File f = new File(outputDirectory + File.separator + name); - f.mkdirs(); - } else { - int index = entryName.lastIndexOf("\\"); - if (index != -1) { - File df = new File(outputDirectory + File.separator + entryName - .substring(0, index)); - df.mkdirs(); - } - index = entryName.lastIndexOf("/"); - if (index != -1) { - File df = new File(outputDirectory + File.separator + entryName - .substring(0, index)); - df.mkdirs(); - } - File f = new File(outputDirectory + File.separator + zipEntry.getName()); - // f.createNewFile(); - in = zipFile.getInputStream(zipEntry); - out = new FileOutputStream(f); - int c; - byte[] by = new byte[1024]; - while ((c = in.read(by)) != -1) { - out.write(by, 0, c); - } - out.flush(); - } - } catch (IOException ex) { - ex.printStackTrace(); - throw new IOException("解压失败:" + ex.toString()); - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException ex) { - } - } - if (out != null) { - try { - out.close(); - } catch (IOException ex) { - } - } - } - } - } catch (IOException ex) { - ex.printStackTrace(); - throw new IOException("解压失败:" + ex.toString()); - } finally { - if (zipFile != null) { - try { - zipFile.close(); - } catch (IOException ex) { - } - } - } - } -} diff --git a/common_base/src/main/java/com/wss/common/utils/toast/BaseToast.java b/common_base/src/main/java/com/wss/common/utils/toast/BaseToast.java new file mode 100644 index 0000000..47ab095 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/toast/BaseToast.java @@ -0,0 +1,70 @@ +package com.wss.common.utils.toast; + +import android.app.Application; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import android.widget.Toast; + +/** + * author : Android 轮子哥 + * github : https://github.com/getActivity/ToastUtils + * time : 2018/11/03 + * desc : Toast 基类 + */ +public class BaseToast extends Toast { + + /** 吐司消息 View */ + private TextView mMessageView; + + public BaseToast(Application application) { + super(application); + } + + @Override + public void setView(View view) { + super.setView(view); + mMessageView = getMessageView(view); + } + + @Override + public void setText(CharSequence s) { + mMessageView.setText(s); + } + + /** + * 智能获取用于显示消息的 TextView + */ + private static TextView getMessageView(View view) { + if (view instanceof TextView) { + return (TextView) view; + } else if (view.findViewById(android.R.id.message) instanceof TextView) { + return ((TextView) view.findViewById(android.R.id.message)); + } else if (view instanceof ViewGroup) { + TextView textView = findTextView((ViewGroup) view); + if (textView != null) { + return textView; + } + } + // 如果设置的布局没有包含一个 TextView 则抛出异常,必须要包含一个 TextView 作为 MessageView + throw new IllegalArgumentException("The layout must contain a TextView"); + } + + /** + * 递归获取 ViewGroup 中的 TextView 对象 + */ + private static TextView findTextView(ViewGroup group) { + for (int i = 0; i < group.getChildCount(); i++) { + View view = group.getChildAt(i); + if ((view instanceof TextView)) { + return (TextView) view; + } else if (view instanceof ViewGroup) { + TextView textView = findTextView((ViewGroup) view); + if (textView != null) { + return textView; + } + } + } + return null; + } +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/utils/toast/IToastInterceptor.java b/common_base/src/main/java/com/wss/common/utils/toast/IToastInterceptor.java new file mode 100644 index 0000000..ff4bc25 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/toast/IToastInterceptor.java @@ -0,0 +1,21 @@ +package com.wss.common.utils.toast; + +import android.widget.Toast; + +/** + * author : Android 轮子哥 + * github : https://github.com/getActivity/ToastUtils + * time : 2019/05/19 + * desc : Toast 拦截器接口 + */ +public interface IToastInterceptor { + + /** + * 根据显示的文本决定是否拦截该 Toast + * + * @param toast Toast + * @param text 显示的Toast内容 + * @return boolean + */ + boolean intercept(Toast toast, CharSequence text); +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/utils/toast/IToastStrategy.java b/common_base/src/main/java/com/wss/common/utils/toast/IToastStrategy.java new file mode 100644 index 0000000..657213b --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/toast/IToastStrategy.java @@ -0,0 +1,40 @@ +package com.wss.common.utils.toast; + +import android.widget.Toast; + +/** + * author : Android 轮子哥 + * github : https://github.com/getActivity/ToastUtils + * time : 2019/05/19 + * desc : Toast 处理策略 + */ +public interface IToastStrategy { + + /** + * 短吐司显示的时长 + */ + int SHORT_DURATION_TIMEOUT = 1500; + /** + * 长吐司显示的时长 + */ + int LONG_DURATION_TIMEOUT = 3500; + + /** + * 绑定 Toast 对象 + * + * @param toast Toast + */ + void bind(Toast toast); + + /** + * 显示 Toast + * + * @param text 文本 + */ + void show(CharSequence text); + + /** + * 取消 Toast + */ + void cancel(); +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/utils/toast/IToastStyle.java b/common_base/src/main/java/com/wss/common/utils/toast/IToastStyle.java new file mode 100644 index 0000000..ac85720 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/toast/IToastStyle.java @@ -0,0 +1,101 @@ +package com.wss.common.utils.toast; + +/** + * author : Android 轮子哥 + * github : https://github.com/getActivity/ToastUtils + * time : 2018/09/01 + * desc : 默认样式接口 + */ +public interface IToastStyle { + + /** + * 吐司的重心 + * + * @return 重心 + */ + int getGravity(); + + /** + * X轴偏移 + * + * @return X轴偏移 + */ + int getXOffset(); + + /** + * Y轴偏移 + * + * @return Y轴偏移 + */ + int getYOffset(); + + /** + * 吐司 Z 轴坐标 + * + * @return 吐司 Z 轴坐标 + */ + int getZ(); + + /** + * 背景圆角大小 + * + * @return 圆角大小 + */ + int getCornerRadius(); + + /** + * 背景颜色 + * + * @return 背景颜色 + */ + int getBackgroundColor(); + + /** + * 文本颜色 + * + * @return 文本颜色 + */ + int getTextColor(); + + /** + * 文本大小 + * + * @return 文本大小 + */ + float getTextSize(); + + /** + * 最大行数 + * + * @return 最大显示行数 + */ + int getMaxLines(); + + /** + * 开始内边距 + * + * @return 顶部内边距 + */ + int getPaddingStart(); + + /** + * 顶部内边距 + * + * @return 顶部内边距 + */ + int getPaddingTop(); + + /** + * 结束内边距 + * + * @return 结束内边距 + */ + int getPaddingEnd(); + + /** + * 底部内边距 + * + * @return 底部内边距 + */ + int getPaddingBottom(); +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/utils/toast/SafeHandler.java b/common_base/src/main/java/com/wss/common/utils/toast/SafeHandler.java new file mode 100644 index 0000000..cb93144 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/toast/SafeHandler.java @@ -0,0 +1,34 @@ +package com.wss.common.utils.toast; + +import android.os.Handler; +import android.os.Message; +import android.view.WindowManager; + +/** + * author : Android 轮子哥 + * github : https://github.com/getActivity/ToastUtils + * time : 2018/12/06 + * desc : Toast 显示安全处理 + */ +final class SafeHandler extends Handler { + + private Handler mHandler; + + SafeHandler(Handler handler) { + mHandler = handler; + } + + @Override + public void handleMessage(Message msg) { + // 捕获这个异常,避免程序崩溃 + try { + // 目前发现在 Android 7.1 主线程被阻塞之后弹吐司会导致崩溃,可使用 Thread.sleep(5000) 进行复现 + // 查看源码得知 Google 已经在 Android 8.0 已经修复了此问题 + // 主线程阻塞之后 Toast 也会被阻塞,Toast 因为超时导致 Window Token 失效 + mHandler.handleMessage(msg); + } catch (WindowManager.BadTokenException | IllegalStateException ignored) { + // android.view.WindowManager$BadTokenException:Unable to add window -- token android.os.BinderProxy is not valid; is your activity running? + // java.lang.IllegalStateException:java.lang.IllegalStateException:View android.widget.LinearLayout has already been added to the window manager. + } + } +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/utils/toast/SafeToast.java b/common_base/src/main/java/com/wss/common/utils/toast/SafeToast.java new file mode 100644 index 0000000..45439e5 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/toast/SafeToast.java @@ -0,0 +1,39 @@ +package com.wss.common.utils.toast; + +import android.app.Application; +import android.os.Handler; +import android.widget.Toast; + +import java.lang.reflect.Field; + +/** + * author : Android 轮子哥 + * github : https://github.com/getActivity/ToastUtils + * time : 2018/12/06 + * desc : Toast 显示安全处理 + */ +public final class SafeToast extends BaseToast { + + public SafeToast(Application application) { + super(application); + + // 反射 Toast 中的字段 + try { + + // 获取 mTN 字段对象 + Field mTnField = Toast.class.getDeclaredField("mTN"); + mTnField.setAccessible(true); + Object mTn = mTnField.get(this); + + // 获取 mTN 中的 mHandler 字段对象 + Field mHandlerField = mTnField.getType().getDeclaredField("mHandler"); + mHandlerField.setAccessible(true); + Handler mHandler = (Handler) mHandlerField.get(mTn); + + // 偷梁换柱 + mHandlerField.set(mTn, new SafeHandler(mHandler)); + + } catch (IllegalAccessException | NoSuchFieldException ignored) { + } + } +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/utils/toast/SupportToast.java b/common_base/src/main/java/com/wss/common/utils/toast/SupportToast.java new file mode 100644 index 0000000..0160916 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/toast/SupportToast.java @@ -0,0 +1,32 @@ +package com.wss.common.utils.toast; + +import android.app.Application; + +/** + * author : Android 轮子哥 + * github : https://github.com/getActivity/ToastUtils + * time : 2018/11/02 + * desc : Toast 无通知栏权限兼容 + */ +public final class SupportToast extends BaseToast { + + /** 吐司弹窗显示辅助类 */ + private final ToastHelper mToastHelper; + + public SupportToast(Application application) { + super(application); + mToastHelper = new ToastHelper(this, application); + } + + @Override + public void show() { + // 显示吐司 + mToastHelper.show(); + } + + @Override + public void cancel() { + // 取消显示 + mToastHelper.cancel(); + } +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/utils/toast/ToastHelper.java b/common_base/src/main/java/com/wss/common/utils/toast/ToastHelper.java new file mode 100644 index 0000000..da4ee47 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/toast/ToastHelper.java @@ -0,0 +1,152 @@ +package com.wss.common.utils.toast; + +import android.app.Activity; +import android.app.Application; +import android.content.Context; +import android.graphics.PixelFormat; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.view.WindowManager; +import android.widget.Toast; + +/** + * author : Android 轮子哥 + * github : https://github.com/getActivity/ToastUtils + * time : 2018/11/02 + * desc : 自定义 Toast 辅助类 + */ +final class ToastHelper extends Handler { + + /** + * 当前的吐司对象 + */ + private final Toast mToast; + + /** + * WindowManager 辅助类 + */ + private final WindowHelper mWindowHelper; + + /** + * 当前应用的包名 + */ + private final String mPackageName; + + /** + * 当前是否已经显示 + */ + private boolean mShow; + + ToastHelper(Toast toast, Application application) { + super(Looper.getMainLooper()); + mToast = toast; + mPackageName = application.getPackageName(); + mWindowHelper = WindowHelper.register(this, application); + } + + @Override + public void handleMessage(Message msg) { + // 收到取消显示的消息 + cancel(); + } + + boolean isShow() { + return mShow; + } + + void setShow(boolean show) { + mShow = show; + } + + /*** + * 显示吐司弹窗 + */ + void show() { + if (!isShow()) { + /* + 这里解释一下,为什么不复用 WindowManager.LayoutParams 这个对象 + 因为如果复用了,不同 Activity 之间不能共用一个,第一个 Activity 调用显示方法可以显示出来,但是会导致后面的 Activity 都显示不出来 + 又或者说,非第一次调用显示方法的 Activity 都会把这个显示请求推送给之前第一个调用显示的 Activity 上面,如果第一个 Activity 已经销毁,还会报以下异常 + android.view.WindowManager$BadTokenException: + Unable to add window -- token android.os.BinderProxy@ef1ccb6 is not valid; is your activity running? + */ + final WindowManager.LayoutParams params = new WindowManager.LayoutParams(); + + /* + // 为什么不能加 TYPE_TOAST,因为通知权限在关闭后设置显示的类型为 Toast 会报错 + // android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running? + params.type = WindowManager.LayoutParams.TYPE_TOAST; + */ + + /* + // 这个是旧版本的写法,新版本已经废弃,因为 Activity onPause 方法被调用后这里把 Toast 取消显示了,这样做的原因:防止内存泄露 + // 判断是否为 Android 6.0 及以上系统并且有悬浮窗权限 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.canDrawOverlays(mToast.getView().getContext())) { + // 解决使用 WindowManager 创建的 Toast 只能显示在当前 Activity 的问题 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + } else { + params.type = WindowManager.LayoutParams.TYPE_PHONE; + } + } + */ + params.height = WindowManager.LayoutParams.WRAP_CONTENT; + params.width = WindowManager.LayoutParams.WRAP_CONTENT; + params.format = PixelFormat.TRANSLUCENT; + params.windowAnimations = android.R.style.Animation_Toast; + params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + params.packageName = mPackageName; + // 重新初始化位置 + params.gravity = mToast.getGravity(); + params.x = mToast.getXOffset(); + params.y = mToast.getYOffset(); + + try { + Activity topActivity = mWindowHelper.getTopActivity(); + if (topActivity != null && !topActivity.isFinishing()) { + WindowManager windowManager = (WindowManager) topActivity.getSystemService(Context.WINDOW_SERVICE); + if (windowManager != null) { + windowManager.addView(mToast.getView(), params); + } + } + // 添加一个移除吐司的任务 + sendEmptyMessageDelayed(hashCode(), mToast.getDuration() == Toast.LENGTH_LONG ? + IToastStrategy.LONG_DURATION_TIMEOUT : IToastStrategy.SHORT_DURATION_TIMEOUT); + // 当前已经显示 + setShow(true); + } catch (IllegalStateException | WindowManager.BadTokenException ignored) { + // 如果这个 View 对象被重复添加到 WindowManager 则会抛出异常 + // java.lang.IllegalStateException: View android.widget.TextView has already been added to the window manager. + // 如果 WindowManager 绑定的 Activity 已经销毁,则会抛出异常 + // android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@ef1ccb6 is not valid; is your activity running? + } + } + } + + /** + * 取消吐司弹窗 + */ + void cancel() { + // 移除之前移除吐司的任务 + removeMessages(hashCode()); + if (isShow()) { + try { + Activity topActivity = mWindowHelper.getTopActivity(); + if (topActivity != null) { + WindowManager windowManager = (WindowManager) topActivity.getSystemService(Context.WINDOW_SERVICE); + if (windowManager != null) { + windowManager.removeViewImmediate(mToast.getView()); + } + } + } catch (IllegalArgumentException ignored) { + // 如果当前 WindowManager 没有附加这个 View 则会抛出异常 + // java.lang.IllegalArgumentException: View=android.widget.TextView not attached to window manager + } + // 当前没有显示 + setShow(false); + } + } +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/utils/toast/ToastInterceptor.java b/common_base/src/main/java/com/wss/common/utils/toast/ToastInterceptor.java new file mode 100644 index 0000000..f0311ce --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/toast/ToastInterceptor.java @@ -0,0 +1,18 @@ +package com.wss.common.utils.toast; + +import android.widget.Toast; + +/** + * author : Android 轮子哥 + * github : https://github.com/getActivity/ToastUtils + * time : 2019/05/19 + * desc : Toast 默认拦截器 + */ +public class ToastInterceptor implements IToastInterceptor { + + @Override + public boolean intercept(Toast toast, CharSequence text) { + // 如果是空对象或者空文本就进行拦截 + return text == null || "".equals(text.toString()); + } +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/utils/toast/ToastStrategy.java b/common_base/src/main/java/com/wss/common/utils/toast/ToastStrategy.java new file mode 100644 index 0000000..24ebdfe --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/toast/ToastStrategy.java @@ -0,0 +1,144 @@ +package com.wss.common.utils.toast; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.widget.Toast; + +import java.util.Queue; +import java.util.concurrent.ArrayBlockingQueue; + +/** + * author : Android 轮子哥 + * github : https://github.com/getActivity/ToastUtils + * time : 2018/11/12 + * desc : Toast 默认处理器 + */ +public class ToastStrategy extends Handler implements IToastStrategy { + + /** + * 延迟时间 + */ + private static final int DELAY_TIMEOUT = 200; + + /** + * 显示吐司 + */ + private static final int TYPE_SHOW = 1; + /** + * 继续显示 + */ + private static final int TYPE_CONTINUE = 2; + /** + * 取消显示 + */ + private static final int TYPE_CANCEL = 3; + + /** + * 队列最大容量 + */ + private static final int MAX_TOAST_CAPACITY = 3; + + /** + * 吐司队列 + */ + private volatile Queue mQueue; + + /** + * 当前是否正在执行显示操作 + */ + private volatile boolean mShow; + + /** + * 吐司对象 + */ + private Toast mToast; + + public ToastStrategy() { + super(Looper.getMainLooper()); + mQueue = getToastQueue(); + } + + @Override + public void bind(Toast toast) { + mToast = toast; + } + + @Override + public void show(CharSequence text) { + if (mQueue.isEmpty() || !mQueue.contains(text)) { + // 添加一个元素并返回true,如果队列已满,则返回false + if (!mQueue.offer(text)) { + // 移除队列头部元素并添加一个新的元素 + mQueue.poll(); + mQueue.offer(text); + } + } + + if (!mShow) { + mShow = true; + // 延迟一段时间之后再执行,因为在没有通知栏权限的情况下,Toast 只能显示当前 Activity + // 如果当前 Activity 在 ToastUtils.show 之后进行 finish 了,那么这个时候 Toast 可能会显示不出来 + // 因为 Toast 会显示在销毁 Activity 界面上,而不会显示在新跳转的 Activity 上面 + sendEmptyMessageDelayed(TYPE_SHOW, DELAY_TIMEOUT); + } + } + + @Override + public void cancel() { + if (mShow) { + mShow = false; + sendEmptyMessage(TYPE_CANCEL); + } + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case TYPE_SHOW: + // 返回队列头部的元素,如果队列为空,则返回null + CharSequence text = mQueue.peek(); + if (text != null) { + mToast.setText(text); + mToast.show(); + // 等这个 Toast 显示完后再继续显示,要加上一些延迟 + // 不然在某些手机上 Toast 可能会来不及消失就要进行显示,这样是显示不出来的 + sendEmptyMessageDelayed(TYPE_CONTINUE, getToastDuration(text) + DELAY_TIMEOUT); + } else { + mShow = false; + } + break; + case TYPE_CONTINUE: + // 移除并返问队列头部的元素,如果队列为空,则返回null + mQueue.poll(); + if (!mQueue.isEmpty()) { + sendEmptyMessage(TYPE_SHOW); + } else { + mShow = false; + } + break; + case TYPE_CANCEL: + mShow = false; + mQueue.clear(); + mToast.cancel(); + break; + default: + break; + } + } + + /** + * 获取吐司队列 + */ + public Queue getToastQueue() { + return new ArrayBlockingQueue<>(MAX_TOAST_CAPACITY); + } + + /** + * 根据文本来获取吐司的显示时长 + */ + public int getToastDuration(CharSequence text) { + // 如果显示的文字超过了10个就显示长吐司,否则显示短吐司 + return text.length() > 20 ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT; + } +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/utils/toast/WindowHelper.java b/common_base/src/main/java/com/wss/common/utils/toast/WindowHelper.java new file mode 100644 index 0000000..214bdba --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/toast/WindowHelper.java @@ -0,0 +1,91 @@ +package com.wss.common.utils.toast; + +import android.app.Activity; +import android.app.Application; +import android.os.Bundle; + +import org.jetbrains.annotations.NotNull; + +/** + * author : Android 轮子哥 + * github : https://github.com/getActivity/ToastUtils + * time : 2018/11/06 + * desc : WindowManager 辅助类(用于获取当前 Activity 的 WindowManager 对象) + */ +final class WindowHelper implements Application.ActivityLifecycleCallbacks { + + /** + * 栈顶 Activity + */ + private Activity mTopActivity; + + /** + * 用于 Activity 暂停时移除 WindowManager + */ + private final ToastHelper mToastHelper; + + private WindowHelper(ToastHelper toast) { + mToastHelper = toast; + } + + static WindowHelper register(ToastHelper toast, Application application) { + WindowHelper window = new WindowHelper(toast); + application.registerActivityLifecycleCallbacks(window); + return window; + } + + /** + * 获取栈顶的 Activity + */ + Activity getTopActivity() { + return mTopActivity; + } + + /** + * {@link Application.ActivityLifecycleCallbacks} + */ + + @Override + public void onActivityCreated(@NotNull Activity activity, Bundle savedInstanceState) { + mTopActivity = activity; + } + + @Override + public void onActivityStarted(@NotNull Activity activity) { + mTopActivity = activity; + } + + @Override + public void onActivityResumed(@NotNull Activity activity) { + mTopActivity = activity; + } + + // A 跳转 B 页面的生命周期方法执行顺序: + // onPause(A) ---> onCreate(B) ---> onStart(B) ---> onResume(B) ---> onStop(A) ---> onDestroyed(A) + + @Override + public void onActivityPaused(@NotNull Activity activity) { + // 取消这个吐司的显示 + if (mToastHelper.isShow()) { + // 不能放在 onStop 或者 onDestroyed 方法中,因为此时新的 Activity 已经创建完成,必须在这个新的 Activity 未创建之前关闭这个 WindowManager + // 调用取消显示会直接导致新的 Activity 的 onCreate 调用显示吐司可能显示不出来的问题,又或者有时候会立马显示然后立马消失的那种效果 + mToastHelper.cancel(); + } + } + + @Override + public void onActivityStopped(@NotNull Activity activity) { + } + + @Override + public void onActivitySaveInstanceState(@NotNull Activity activity, @NotNull Bundle outState) { + } + + @Override + public void onActivityDestroyed(@NotNull Activity activity) { + if (mTopActivity == activity) { + // 移除对这个 Activity 的引用 + mTopActivity = null; + } + } +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/utils/toast/style/BaseToastStyle.java b/common_base/src/main/java/com/wss/common/utils/toast/style/BaseToastStyle.java new file mode 100644 index 0000000..618b040 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/toast/style/BaseToastStyle.java @@ -0,0 +1,72 @@ +package com.wss.common.utils.toast.style; + +import android.content.Context; +import android.util.TypedValue; +import android.view.Gravity; + +import com.wss.common.utils.toast.IToastStyle; + + +/** + * author : Android 轮子哥 + * github : https://github.com/getActivity/ToastUtils + * time : 2019/05/19 + * desc : 默认样式基类 + */ +public abstract class BaseToastStyle implements IToastStyle { + + private Context mContext; + + public BaseToastStyle(Context context) { + mContext = context; + } + + @Override + public int getGravity() { + return Gravity.CENTER; + } + + @Override + public int getXOffset() { + return 0; + } + + @Override + public int getYOffset() { + return 0; + } + + @Override + public int getZ() { + return 30; + } + + @Override + public int getMaxLines() { + return 5; + } + + @Override + public int getPaddingEnd() { + return getPaddingStart(); + } + + @Override + public int getPaddingBottom() { + return getPaddingTop(); + } + + /** + * dp转px + */ + protected int dp2px(float dpValue) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, mContext.getResources().getDisplayMetrics()); + } + + /** + * sp转px + */ + protected int sp2px(float spValue) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spValue, mContext.getResources().getDisplayMetrics()); + } +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/utils/toast/style/ToastBlackStyle.java b/common_base/src/main/java/com/wss/common/utils/toast/style/ToastBlackStyle.java new file mode 100644 index 0000000..a2c04c7 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/utils/toast/style/ToastBlackStyle.java @@ -0,0 +1,46 @@ +package com.wss.common.utils.toast.style; + +import android.content.Context; + +/** + * author : Android 轮子哥 + * github : https://github.com/getActivity/ToastUtils + * time : 2018/09/01 + * desc : 默认黑色样式实现 + */ +public class ToastBlackStyle extends BaseToastStyle { + + public ToastBlackStyle(Context context) { + super(context); + } + + @Override + public int getCornerRadius() { + return dp2px(4); + } + + @Override + public int getBackgroundColor() { + return 0XBF000000; + } + + @Override + public int getTextColor() { + return 0XEEFFFFFF; + } + + @Override + public float getTextSize() { + return sp2px(14); + } + + @Override + public int getPaddingStart() { + return dp2px(12); + } + + @Override + public int getPaddingTop() { + return dp2px(6); + } +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/view/SpringboardActivity.java b/common_base/src/main/java/com/wss/common/view/SpringboardActivity.java new file mode 100644 index 0000000..72be373 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/view/SpringboardActivity.java @@ -0,0 +1,44 @@ +package com.wss.common.view; + +import android.view.View; + +import com.wss.common.base.BaseActionBarActivity; +import com.wss.common.base.BaseFragment; +import com.wss.common.base.R; +import com.wss.common.base.mvp.BasePresenter; +import com.wss.common.constants.Dic; +import com.wss.common.utils.ARouterUtils; + +import androidx.fragment.app.FragmentTransaction; + +/** + * Describe:跳板Activity,主要是跳转一些Fragment + * 统一采用ARouter方式跳转 + * Created by 吴天强 on 2020/5/7. + */ +public class SpringboardActivity extends BaseActionBarActivity { + + @Override + protected int getLayoutId() { + return R.layout.activity_springboard; + } + + @Override + protected void initView() { + boolean isActionBar = getIntent().getBooleanExtra(Dic.IS_ACTION_BAR, false); + String titleText = getIntent().getStringExtra(Dic.TITLE_TEXT); + getTitleBar().setVisibility(isActionBar ? View.VISIBLE : View.GONE); + setCenterText(titleText); + BaseFragment fragment = ARouterUtils.getFragment(getIntent().getStringExtra(Dic.TARGET_FRAGMENT_PATH)); + //给Fragment设置带入参数 + fragment.setArguments(getIntent().getBundleExtra(Dic.BUNDLE_DATA)); + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.add(R.id.fl_content, fragment); + transaction.commitAllowingStateLoss(); + } + + @Override + protected BasePresenter createPresenter() { + return null; + } +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/view/browser/BrowserActivity.java b/common_base/src/main/java/com/wss/common/view/browser/BrowserActivity.java new file mode 100644 index 0000000..aff80ec --- /dev/null +++ b/common_base/src/main/java/com/wss/common/view/browser/BrowserActivity.java @@ -0,0 +1,490 @@ +package com.wss.common.view.browser; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.graphics.Bitmap; +import android.net.Uri; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.webkit.ConsoleMessage; +import android.webkit.JsResult; +import android.webkit.WebChromeClient; +import android.webkit.WebResourceRequest; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.orhanobut.logger.Logger; +import com.wss.common.base.BaseMvpActivity; +import com.wss.common.base.R; +import com.wss.common.base.R2; +import com.wss.common.constants.Constants; +import com.wss.common.constants.Dic; +import com.wss.common.utils.NetworkUtil; +import com.wss.common.utils.PxUtils; +import com.wss.common.utils.ValidUtils; +import com.wss.common.view.browser.mvp.BrowserPresenter; +import com.wss.common.view.browser.mvp.contract.BrowserContract; +import com.wss.common.widget.dialog.AppDialog; + +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import butterknife.BindView; +import butterknife.OnClick; + +/** + * Describe:浏览器页面-WebView + * Created by 吴天强 on 2020/5/18. + */ +public class BrowserActivity extends BaseMvpActivity implements BrowserContract.View { + + @BindView(R2.id.tv_title) + TextView tvTitle; + + @BindView(R2.id.progress_bar) + ProgressBar progressBar; + + @BindView(R2.id.web_view) + WebView webView; + + @BindView(R2.id.iv_empty) + ImageView ivEmpty; + + @BindView(R2.id.tv_empty) + TextView tvEmpty; + + @BindView(R2.id.ll_empty_view) + LinearLayout llEmptyView; + + @BindView(R2.id.img_back) + ImageView ivBack; + @BindView(R2.id.tv_back) + + TextView tvBack; + @BindView(R2.id.tv_close_right) + TextView tvCloseRight; + + @BindView(R2.id.rl_browser_header) + RelativeLayout relHeader; + /** + * 本地缓存目录 + */ + private String appCacheDir = Constants.WebView.CACHE_DIR; + private boolean isFullScreen = false; + private String url; + private String title; + + + @Override + protected int getLayoutId() { + return R.layout.activity_browser; + } + + public void hiddenHeader() { + relHeader.setVisibility(View.GONE); + } + + @Override + protected void initView() { + //沉浸式状态栏 + setImmersionBarColor(R.color.white); + url = getIntent().getStringExtra(Dic.URL); + title = getIntent().getStringExtra(Dic.TITLE_TEXT); + tvCloseRight.setVisibility(View.GONE); + tvBack.setVisibility(View.GONE); + tvTitle.setText(title); + initWebView(); + refreshPage(); + } + + @OnClick({ + R2.id.img_back, + R2.id.tv_back, + R2.id.tv_close_right, + }) + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.img_back) { + finish(); + } else if (id == R.id.tv_back) { + finish(); + } else if (id == R.id.tv_close_right) { + finish(); + } + } + + /** + * 获取一个WebView实例 + * + * @return + */ + public WebView getWebView() { + return webView; + } + + @SuppressLint("SetJavaScriptEnabled") + private void initWebView() { + WebSettings webSettings = webView.getSettings(); + webSettings.setJavaScriptEnabled(true); + webSettings.setDomStorageEnabled(true); + webSettings.setPluginState(WebSettings.PluginState.ON); + webSettings.setAppCacheEnabled(true); + webSettings.setAppCachePath(appCacheDir); + webSettings.setDatabasePath(appCacheDir); + webSettings.setAppCacheMaxSize(100 * 1024 * 1024); + webSettings.setCacheMode(WebSettings.LOAD_DEFAULT); + webSettings.setAllowFileAccess(true); + webSettings.setRenderPriority(WebSettings.RenderPriority.HIGH); + webSettings.setSupportZoom(true); + webSettings.setBuiltInZoomControls(true); + // 添加新参数 + webSettings.setUseWideViewPort(true); + webSettings.setLoadWithOverviewMode(true); + + setPageCacheCapacity(webSettings); + webSettings.enableSmoothTransition(); + // 是否显示缩放按钮 + webSettings.setDisplayZoomControls(false); + + //设置HTTP HTTPS 混合模式加载页面 + webSettings.setMixedContentMode(2); + webView.setWebViewClient(webViewClient); + webView.setWebChromeClient(chromeClient); + } + + + private class JavaScriptApi { + + } + + @Override + protected BrowserPresenter createPresenter() { + return new BrowserPresenter(); + } + + + /** + * WebView调用JS + * + * @param method 方法名 + * @param data 参数多参已逗号分隔 + */ + private void loadJsMethod(String method, String data) { + if (ValidUtils.isValid(data)) { + // 传递参数调用 + String format = String.format("javascript:%s('%s')", method, data); + webView.loadUrl(format); + } else { + // 无参数调用 + webView.loadUrl(String.format("javascript:%s()", method)); + } + } + + + /** + * 刷新页面 显示网页 + */ + private void refreshPage() { + webView.clearCache(true); + if (NetworkUtil.isNetworkEnabled(context)) { + webView.setVisibility(View.VISIBLE); + progressBar.setVisibility(View.VISIBLE); + webView.loadUrl(url); +// webView.loadUrl("file:///android_asset/demo.html"); + } else { + shoeErrorPage(true); + } + } + + /** + * WebView client + */ + private WebViewClient webViewClient = new WebViewClient() { + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + if (url.startsWith("http:") || url.startsWith("https:")) { + return false; + } + + Logger.e("shouldOverrideUrlLoading: " + url); + //拦截tel:拨打电话。 + if (url.startsWith("tel:")) { + try { + startActivity(new Intent(Intent.ACTION_DIAL, Uri.parse(url))); + } catch (Exception e) { + e.printStackTrace(); + } + return true; + } + return false; + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + if (request.getUrl().toString().startsWith("http:") || request.getUrl().toString().startsWith("https:")) { + return false; + } + return true; + } + + @Override + public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) { + super.doUpdateVisitedHistory(view, url, isReload); + } + + + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + super.onPageStarted(view, url, favicon); + Logger.e("onPageStarted: " + url); + if (progressBar != null) { + progressBar.setVisibility(View.VISIBLE); + } + } + + + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + Logger.e("onPageFinished: " + url); + if (progressBar != null) { + progressBar.setVisibility(View.GONE); + } + } + + @Override + public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { + super.onReceivedError(view, errorCode, description, failingUrl); + if (progressBar != null) { + progressBar.setVisibility(View.GONE); + } + } + + @Override + public void onLoadResource(WebView view, String url) { + super.onLoadResource(view, url); + } + }; + /** + * 显示到选择进度条的进度,根据返回的title获取到当前的标题 + * 如果传过来的参数中带有标题,则显示该标题,不再根据WebChromeClient返回的title获取到当前的标题 + */ + private WebChromeClient chromeClient = new WebChromeClient() { + private View myView = null; + private int mTempProgress = 0; + + @Override + public boolean onConsoleMessage(ConsoleMessage consoleMessage) { + return super.onConsoleMessage(consoleMessage); + } + + @Override + public boolean onJsAlert(WebView view, String url, String message, @NotNull JsResult result) { + showDialog(message); + result.confirm(); + return true; + } + + @Override + public void onProgressChanged(WebView view, int newProgress) { + // 进度加载到100时,就不再重新进行加载,防止页面嵌套页面时,进度条反复加载 + if (progressBar == null || mTempProgress == 100) { + return; + } + mTempProgress = newProgress > 50 ? 100 : newProgress; + if (progressBar.getVisibility() == View.GONE) { + showProgressView(); + } + progressBar.setProgress(mTempProgress); + if (newProgress >= 80 && progressBar.getVisibility() == View.VISIBLE) { + dismissProgressView(); + } + } + + @Override + public void onReceivedTitle(WebView view, String title) { + super.onReceivedTitle(view, title); + if (tvTitle != null && !ValidUtils.isValid(title)) { + tvTitle.setText(title); + } + } + + @Override + public void onShowCustomView(View view, CustomViewCallback callback) { + super.onShowCustomView(view, callback); + isFullScreen = true; + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + ViewGroup parent = (ViewGroup) webView.getParent().getParent(); + parent.setVisibility(View.GONE); + ((ViewGroup) parent.getParent()).addView(view, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT, Gravity.CENTER)); + myView = view; + chromeClient = this; + } + + @Override + public void onHideCustomView() { + isFullScreen = false; + if (myView != null) { + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + if (myView != null && myView.getParent() != null) { + ViewGroup parent = (ViewGroup) myView.getParent(); + parent.removeView(myView); + + if (webView.getParent().getParent() != null) { + ViewGroup parent2 = (ViewGroup) webView.getParent().getParent(); + parent2.setVisibility(View.VISIBLE); + } + } + myView = null; + } + } + }; + + @OnClick({R2.id.img_back, + R2.id.tv_back, + R2.id.tv_close_right, + R2.id.ll_empty_view}) + public void onViewClicked(@NotNull View view) { + int id = view.getId(); + if (id == R.id.img_back || id == R.id.tv_back) { + //返回 + goBack(); + } else if (id == R.id.tv_close_right) { + //关闭 + finish(); + } else if (id == R.id.ll_empty_view) { + //点击错误页 + } + } + + /** + * 显示进度条 + */ + private void showProgressView() { + AlphaAnimation anim = new AlphaAnimation(0, 1.0f); + anim.setDuration(200); + progressBar.startAnimation(anim); + progressBar.setVisibility(View.VISIBLE); + } + + /** + * 隐藏进度条 + */ + protected void dismissProgressView() { + AlphaAnimation anim = new AlphaAnimation(1.0f, 0); + anim.setDuration(200); + anim.setAnimationListener(new Animation.AnimationListener() { + + @Override + public void onAnimationStart(Animation animation) { + } + + @Override + public void onAnimationRepeat(Animation animation) { + } + + // 动画结束后再隐藏进度条 + @Override + public void onAnimationEnd(Animation animation) { + progressBar.setVisibility(View.GONE); + } + }); + progressBar.startAnimation(anim); + // 动画结束前显示进度条 + progressBar.setVisibility(View.VISIBLE); + } + + /** + * 显示错误页面 + * + * @param showError 显示 + */ + private void shoeErrorPage(boolean showError) { + if (showError) { + llEmptyView.setVisibility(View.VISIBLE); + webView.setVisibility(View.GONE); + } else { + llEmptyView.setVisibility(View.GONE); + webView.setVisibility(View.VISIBLE); + } + } + + /** + * 设置WebView缓存容量 + * + * @param webSettings settings + */ + public void setPageCacheCapacity(WebSettings webSettings) { + try { + @SuppressLint("PrivateApi") + Class c = Class.forName("android.webkit.WebSettingsClassic"); + Method tt = c.getMethod("setPageCacheCapacity", int.class); + tt.invoke(webSettings, 5); + } catch (ClassNotFoundException e) { + System.out.println("No such class: " + e); + } catch (NoSuchMethodException | IllegalArgumentException | + IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + } + + /** + * 弹出对话框 + * + * @param message 提示信息 + */ + private void showDialog(String message) { + new AppDialog.Builder(context) + .setContent(message) + .create() + .show(); + } + + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + goBack(); + return true; + } + return super.onKeyDown(keyCode, event); + } + + /** + * 返回上一步 + */ + private void goBack() { + if (webView.canGoBack()) { + webView.goBack(); + } else { + finish(); + } + } + + @OnClick(R2.id.tv_title) + public void test() { + + int height = PxUtils.getScreenHeight(context); + int width = PxUtils.getScreenWidth(context); + + new AppDialog.Builder(context) + .setContent(height+"x"+width) + .setSingleButton("YES") + .create() + .show(); + } +} diff --git a/common_base/src/main/java/com/wss/common/view/browser/mvp/BrowserPresenter.java b/common_base/src/main/java/com/wss/common/view/browser/mvp/BrowserPresenter.java new file mode 100644 index 0000000..a42a522 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/view/browser/mvp/BrowserPresenter.java @@ -0,0 +1,22 @@ +package com.wss.common.view.browser.mvp; + +import com.wss.common.base.mvp.BasePresenter; +import com.wss.common.view.browser.mvp.contract.BrowserContract; +import com.wss.common.view.browser.mvp.model.BrowserModel; + +/** + * Describe:浏览器控制器 + * Created by 吴天强 on 2020/5/18. + */ +public class BrowserPresenter extends BasePresenter + implements BrowserContract.Presenter { + @Override + protected BrowserModel createModule() { + return new BrowserModel(getLifecycleOwner()); + } + + @Override + public void start() { + + } +} diff --git a/common_base/src/main/java/com/wss/common/view/browser/mvp/contract/BrowserContract.java b/common_base/src/main/java/com/wss/common/view/browser/mvp/contract/BrowserContract.java new file mode 100644 index 0000000..002567e --- /dev/null +++ b/common_base/src/main/java/com/wss/common/view/browser/mvp/contract/BrowserContract.java @@ -0,0 +1,23 @@ +package com.wss.common.view.browser.mvp.contract; + + +import com.wss.common.base.mvp.IBaseView; + +/** + * Describe:浏览器页面契约类 + * Created by 吴天强 on 2020/5/18. + */ +public interface BrowserContract { + + interface Model { + + } + + interface View extends IBaseView { + + } + + interface Presenter { + + } +} diff --git a/common_base/src/main/java/com/wss/common/view/browser/mvp/model/BrowserModel.java b/common_base/src/main/java/com/wss/common/view/browser/mvp/model/BrowserModel.java new file mode 100644 index 0000000..83d333f --- /dev/null +++ b/common_base/src/main/java/com/wss/common/view/browser/mvp/model/BrowserModel.java @@ -0,0 +1,17 @@ +package com.wss.common.view.browser.mvp.model; + +import com.wss.common.base.mvp.BaseModel; +import com.wss.common.view.browser.mvp.contract.BrowserContract; + +import androidx.lifecycle.LifecycleOwner; + +/** + * Describe:浏览器Model + * Created by 吴天强 on 2020/5/18. + */ +public class BrowserModel extends BaseModel implements BrowserContract.Presenter { + + public BrowserModel(LifecycleOwner lifecycleOwner) { + super(lifecycleOwner); + } +} diff --git a/common_base/src/main/java/com/wss/common/view/file/SelectFileActivity.java b/common_base/src/main/java/com/wss/common/view/file/SelectFileActivity.java new file mode 100644 index 0000000..86024eb --- /dev/null +++ b/common_base/src/main/java/com/wss/common/view/file/SelectFileActivity.java @@ -0,0 +1,135 @@ +package com.wss.common.view.file; + +import android.content.Intent; + +import com.wss.common.base.BaseActionBarActivity; +import com.wss.common.base.R; +import com.wss.common.base.R2; +import com.wss.common.constants.Constants; +import com.wss.common.constants.Dic; +import com.wss.common.utils.JsonUtils; +import com.wss.common.utils.ToastUtils; +import com.wss.common.view.file.adapter.SelectFileAdapter; +import com.wss.common.view.file.bean.FileInfo; +import com.wss.common.view.file.mvp.SelectFilePresenter; +import com.wss.common.view.file.mvp.contract.SelectFileContract; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import butterknife.BindView; + +/** + * Describe:选择手机文件 + * Created by 吴天强 on 2020/6/20. + */ +public class SelectFileActivity extends BaseActionBarActivity implements SelectFileContract.View { + + @BindView(R2.id.recycle_view) + RecyclerView recyclerView; + + private SelectFileAdapter adapter; + private List fileList = new ArrayList<>(); + + /** + * 最大可选文件数 + */ + private int max = 9; + + @Override + protected SelectFilePresenter createPresenter() { + return new SelectFilePresenter(); + } + + @Override + protected int getLayoutId() { + return R.layout.activity_select_file; + } + + @Override + protected void initView() { + if (getType() == Constants.FileType.IMAGE) { + setCenterText(getString(R.string.slelect_image)); + recyclerView.setLayoutManager(new GridLayoutManager(context, 3)); + + } else { + setCenterText(getString(R.string.select_file)); + recyclerView.setLayoutManager(new LinearLayoutManager(context)); + + } + max = getIntent().getIntExtra(Dic.MAX_SELECT_FILE, max); + adapter = new SelectFileAdapter(context, fileList, (fileInfo, position) -> { + if (!fileInfo.isChecked()) { + List allSelect = getAllSelect(); + if (allSelect.size() >= max) { + if (getType() == Constants.FileType.IMAGE) { + ToastUtils.show(context, getString(R.string.max_select_image, max)); + } else { + ToastUtils.show(context, getString(R.string.max_select_file, max)); + } + return; + } + } + fileList.get(position).setChecked(!fileList.get(position).isChecked()); + adapter.notifyItemChanged(position); + }); + recyclerView.setAdapter(adapter); + setRightText(R.string.confirm, v -> { + ArrayList allSelect = getAllSelect(); + if (allSelect.size() < 1) { + ToastUtils.show(context, getString(R.string.no_select)); + return; + } + Intent intent = new Intent(); + intent.putExtra(Dic.SELECT_FILE_PATHS, JsonUtils.toJson(allSelect)); + setResult(RESULT_OK, intent); + finish(); + }); + getPresenter().start(); + } + + @Override + public int getType() { + return getIntent().getIntExtra(Dic.FROM_TYPE, Constants.FileType.IMAGE); + } + + @Override + public void refreshFileList(List fileList) { + this.fileList.clear(); + this.fileList.addAll(fileList); + adapter.notifyDataSetChanged(); + } + + @Override + public void onError(Object tag, String errorMsg) { + super.onError(tag, errorMsg); + showErrorView(errorMsg); + } + + @Override + public void onEmpty(Object tag) { + super.onEmpty(tag); + showEmptyView(); + } + + /** + * 获取全部已选中文件 + * + * @return 所有已选中的文件的路径 + */ + @NotNull + private ArrayList getAllSelect() { + ArrayList pathList = new ArrayList<>(); + for (FileInfo info : fileList) { + if (info.isChecked()) { + pathList.add(info.getFilePath()); + } + } + return pathList; + } +} diff --git a/common_base/src/main/java/com/wss/common/view/file/adapter/SelectFileAdapter.java b/common_base/src/main/java/com/wss/common/view/file/adapter/SelectFileAdapter.java new file mode 100644 index 0000000..8d8cea3 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/view/file/adapter/SelectFileAdapter.java @@ -0,0 +1,53 @@ +package com.wss.common.view.file.adapter; + +import android.content.Context; + +import com.wss.common.base.R; +import com.wss.common.base.adapter.BaseListAdapter; +import com.wss.common.constants.Constants; +import com.wss.common.utils.ImageUtils; +import com.wss.common.view.file.adapter.holder.SelectFileViewHolder; +import com.wss.common.view.file.bean.FileInfo; + +import org.byteam.superadapter.SuperViewHolder; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * Describe:选择文件适配器 + * Created by 吴天强 on 2020/6/20. + */ +public class SelectFileAdapter extends BaseListAdapter { + + private OnItemClickListener onItemClickListener; + + public SelectFileAdapter(Context context, List mData, OnItemClickListener listener) { + super(context, mData, new SelectFileViewHolder()); + this.onItemClickListener = listener; + } + + @Override + public void onBindData(@NotNull SuperViewHolder holder, int viewType, int layoutPosition, @NotNull FileInfo data) { + holder.findViewById(R.id.iftv_checked).setSelected(data.isChecked()); + if (onItemClickListener != null) { + holder.itemView.setOnClickListener(v -> onItemClickListener.onItemClick(data, layoutPosition)); + } + if (viewType == Constants.FileType.IMAGE) { + //图片 + ImageUtils.loadImageCircleBead(holder.findViewById(R.id.iv_image), data.getFilePath(), 4); + } else { + holder.setText(R.id.tv_name, data.getFileName()); + } + } + + public interface OnItemClickListener { + /** + * Item选择点击事件 + * + * @param fileInfo 文件 + * @param position 下标 + */ + void onItemClick(FileInfo fileInfo, int position); + } +} diff --git a/common_base/src/main/java/com/wss/common/view/file/adapter/holder/SelectFileViewHolder.java b/common_base/src/main/java/com/wss/common/view/file/adapter/holder/SelectFileViewHolder.java new file mode 100644 index 0000000..de7743d --- /dev/null +++ b/common_base/src/main/java/com/wss/common/view/file/adapter/holder/SelectFileViewHolder.java @@ -0,0 +1,33 @@ +package com.wss.common.view.file.adapter.holder; + +import com.wss.common.base.R; +import com.wss.common.constants.Constants; +import com.wss.common.view.file.bean.FileInfo; + +import org.byteam.superadapter.IMulItemViewType; +import org.jetbrains.annotations.NotNull; + +/** + * Describe:选择文件多View + * Created by 吴天强 on 2020/6/20. + */ +public class SelectFileViewHolder implements IMulItemViewType { + + @Override + public int getViewTypeCount() { + return 2; + } + + @Override + public int getItemViewType(int position, @NotNull FileInfo fileInfo) { + return fileInfo.getType(); + } + + @Override + public int getLayoutId(int viewType) { + if (viewType == Constants.FileType.IMAGE) { + return R.layout.item_of_select_image; + } + return R.layout.item_of_select_file; + } +} diff --git a/common_base/src/main/java/com/wss/common/view/file/bean/FileInfo.java b/common_base/src/main/java/com/wss/common/view/file/bean/FileInfo.java new file mode 100644 index 0000000..0a30f85 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/view/file/bean/FileInfo.java @@ -0,0 +1,28 @@ +package com.wss.common.view.file.bean; + + +import com.wss.common.base.bean.BaseBean; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + + +/** + * Describe:选择文件 + * Created by 吴天强 on 2019/11/12. + */ +@Getter +@Setter +@ToString +public class FileInfo extends BaseBean { + private String fileName; + private String filePath; + private long fileSize; + private String time; + private boolean checked; + /** + * 文件类型 Constants.FileType + */ + private int type; +} diff --git a/common_base/src/main/java/com/wss/common/view/file/mvp/SelectFilePresenter.java b/common_base/src/main/java/com/wss/common/view/file/mvp/SelectFilePresenter.java new file mode 100644 index 0000000..b62f236 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/view/file/mvp/SelectFilePresenter.java @@ -0,0 +1,36 @@ +package com.wss.common.view.file.mvp; + + +import com.wss.common.base.mvp.BasePresenter; +import com.wss.common.utils.ValidUtils; +import com.wss.common.view.file.mvp.contract.SelectFileContract; +import com.wss.common.view.file.mvp.model.SelectFileModel; + +/** + * Describe:选择文件控制器 + * Created by 吴天强 on 2020/6/20. + */ +public class SelectFilePresenter extends BasePresenter + implements SelectFileContract.Presenter { + @Override + protected SelectFileModel createModule() { + return new SelectFileModel(getLifecycleOwner()); + } + + @Override + public void start() { + showLoading(); + getModel().queryFile(getView().getType()).subscribe( + fileInfoList -> { + dismissLoading(); + if (ValidUtils.isValid(fileInfoList)) { + getView().refreshFileList(fileInfoList); + } else { + getView().onEmpty(""); + } + }, t -> { + dismissLoading(); + getView().onError("", t.getMessage()); + }); + } +} diff --git a/common_base/src/main/java/com/wss/common/view/file/mvp/contract/SelectFileContract.java b/common_base/src/main/java/com/wss/common/view/file/mvp/contract/SelectFileContract.java new file mode 100644 index 0000000..0225ee3 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/view/file/mvp/contract/SelectFileContract.java @@ -0,0 +1,48 @@ +package com.wss.common.view.file.mvp.contract; + +import com.wss.common.base.mvp.IBaseView; +import com.wss.common.view.file.bean.FileInfo; + +import java.util.List; + +import io.reactivex.Observable; + +/** + * Describe:选择文件契约类 + * Created by 吴天强 on 2020/6/20. + */ +public interface SelectFileContract { + + interface Model { + /** + * 查询文件 + * + * @param type 类型 + * @return 文件列表 + */ + Observable> queryFile(int type); + } + + interface View extends IBaseView { + + /** + * 选择文件的类型 + * + * @return 类型 + */ + int getType(); + + /** + * 刷新文件列表 + * + * @param fileList 文件列表 + */ + void refreshFileList(List fileList); + + } + + interface Presenter { + + + } +} diff --git a/common_base/src/main/java/com/wss/common/view/file/mvp/model/SelectFileModel.java b/common_base/src/main/java/com/wss/common/view/file/mvp/model/SelectFileModel.java new file mode 100644 index 0000000..f1a8319 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/view/file/mvp/model/SelectFileModel.java @@ -0,0 +1,202 @@ +package com.wss.common.view.file.mvp.model; + +import android.content.ContentResolver; +import android.database.Cursor; +import android.provider.MediaStore; + +import com.wss.common.base.BaseApplication; +import com.wss.common.base.mvp.BaseModel; +import com.wss.common.constants.Constants; +import com.wss.common.utils.FileUtils; +import com.wss.common.view.file.bean.FileInfo; +import com.wss.common.view.file.mvp.contract.SelectFileContract; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import androidx.lifecycle.LifecycleOwner; +import io.reactivex.Observable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; + +/** + * Describe:选择文件Model + * Created by 吴天强 on 2020/6/20. + */ +public class SelectFileModel extends BaseModel implements SelectFileContract.Model { + /** + * 视频后缀 + */ + private static final String[] VIDEO_SUFFIX = {".mp4", ".rmvb", ".avi", ".flv"}; + /** + * 语音后缀 + */ + private static final String[] VOICE_SUFFIX = {".mp3", ".wav", ".ogg", ".midi"}; + /** + * 文档后缀 + */ + private static final String[] DOCUMENT_SUFFIX = {".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf"}; + /** + * 压缩包后缀 + */ + private static final String[] PACKAGE_SUFFIX = {".jar", ".zip", ".rar", ".gz", ".apk", ".img"}; + /** + * 其他文件后缀 + */ + private static final String[] OTHER_SUFFIX = {".htm", ".html", ".php", ".jsp", ".txt", ".java", ".c", ".cpp", ".py", ".xml", ".json", ".log"}; + + public SelectFileModel(LifecycleOwner lifecycleOwner) { + super(lifecycleOwner); + } + + + @Override + public Observable> queryFile(int type) { + return Observable.>create( + subscriber -> { + switch (type) { + case Constants.FileType.IMAGE: + //读取手机图片 + subscriber.onNext(queryImages()); + break; + case Constants.FileType.VIDEO: + //视频 + subscriber.onNext(readSdCardFile(getQuerySql(VIDEO_SUFFIX))); + break; + case Constants.FileType.AUDIO: + //音频 + subscriber.onNext(readSdCardFile(getQuerySql(VOICE_SUFFIX))); + break; + case Constants.FileType.DOC: + //文档 + subscriber.onNext(readSdCardFile(getQuerySql(DOCUMENT_SUFFIX))); + break; + case Constants.FileType.PACKAGE: + //压缩包 + subscriber.onNext(readSdCardFile(getQuerySql(PACKAGE_SUFFIX))); + break; + case Constants.FileType.OTHER: + default: + //其他 + subscriber.onNext(readSdCardFile(getQuerySql(OTHER_SUFFIX))); + break; + } + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + + /** + * 读取手机里的图片 + * + * @return 图片列表 + */ + @NotNull + private List queryImages() { + List imageList = new ArrayList<>(); + ContentResolver mContentResolver = BaseApplication.i().getApplicationContext().getContentResolver(); + String[] projection = { + "_id", + MediaStore.Images.Media.DATA, + MediaStore.Images.Media.BUCKET_DISPLAY_NAME, + MediaStore.Images.Media.DISPLAY_NAME, + MediaStore.Images.Media.DATE_TAKEN, + MediaStore.Images.Media.SIZE}; + + Cursor mCursor = mContentResolver.query( + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + projection, "(" + + MediaStore.Images.Media.MIME_TYPE + "=? or " + + MediaStore.Images.Media.MIME_TYPE + "=? or " + + MediaStore.Images.Media.MIME_TYPE + "=? or " + + MediaStore.Images.Media.MIME_TYPE + "=? ) and _size > 0", + new String[]{"image/jpg", "image/png", "image/jpeg"}, + MediaStore.Images.Media.DATE_TAKEN + " desc"); + + if (mCursor != null) { + while (mCursor.moveToNext()) { + FileInfo fileInfo = new FileInfo(); + String path = mCursor.getString(mCursor.getColumnIndex(MediaStore.Images.Media.DATA)); + String displayName = mCursor.getString(mCursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)); + int size = mCursor.getInt(mCursor.getColumnIndex(MediaStore.Images.Media.SIZE)); + fileInfo.setFilePath(path); + fileInfo.setFileSize(size); + fileInfo.setFileName(displayName); + imageList.add(fileInfo); + } + mCursor.close(); + } + return imageList; + } + + + /** + * 生成读手机影音SQL + * + * @param suffixList 文件后缀 + * @return 查询SQL + */ + @NotNull + private String getQuerySql(@NotNull String[] suffixList) { + StringBuilder sb = new StringBuilder(); + sb.append("("); + for (String suffix : suffixList) { + sb.append(MediaStore.Files.FileColumns.DATA); + sb.append(" LIKE '%").append(suffix).append("' OR "); + } + return sb.substring(0, sb.length() - 3) + ")"; + } + + + /** + * 读取手机中的文件 + * + * @param sql 查询SQL + * @return 文件列表 + */ + @NotNull + private List readSdCardFile(String sql) { + List result = new ArrayList<>(); + String[] columns = new String[]{ + MediaStore.Files.FileColumns._ID, + MediaStore.Files.FileColumns.MIME_TYPE, + MediaStore.Files.FileColumns.SIZE, + MediaStore.Files.FileColumns.DATE_MODIFIED, + MediaStore.Files.FileColumns.DATA}; + ContentResolver contentResolver = BaseApplication.i().getContentResolver(); + Cursor cursor = contentResolver.query(MediaStore.Files.getContentUri("external"), + columns, sql, null, null); + if (cursor != null) { + int columnIndexOrThrowData = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA); + while (cursor.moveToNext()) { + String path = cursor.getString(columnIndexOrThrowData); + FileInfo document = formatFile(new File(path)); + //去除空文件 + if (document.getFileSize() > 0) { + result.add(document); + } + } + cursor.close(); + } + return result; + } + + /** + * 格式化读取的文件 + * + * @param file 源文件 + * @return 格式化以后的文件 + */ + @NotNull + private FileInfo formatFile(@NotNull File file) { + FileInfo fileInfo = new FileInfo(); + fileInfo.setFileName(file.getName()); + fileInfo.setFilePath(file.getPath()); + fileInfo.setFileSize(file.length()); + fileInfo.setTime(FileUtils.getFileLastModifiedTime(file)); + return fileInfo; + } +} diff --git a/common_base/src/main/java/com/wss/common/widget/scaleImg/IOThread.java b/common_base/src/main/java/com/wss/common/view/gallery/IOThread.java similarity index 92% rename from common_base/src/main/java/com/wss/common/widget/scaleImg/IOThread.java rename to common_base/src/main/java/com/wss/common/view/gallery/IOThread.java index 5fa78fe..6fc9f96 100644 --- a/common_base/src/main/java/com/wss/common/widget/scaleImg/IOThread.java +++ b/common_base/src/main/java/com/wss/common/view/gallery/IOThread.java @@ -1,4 +1,4 @@ -package com.wss.common.widget.scaleImg; +package com.wss.common.view.gallery; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; diff --git a/common_base/src/main/java/com/wss/common/widget/scaleImg/ImageDownloader.java b/common_base/src/main/java/com/wss/common/view/gallery/ImageDownloader.java similarity index 61% rename from common_base/src/main/java/com/wss/common/widget/scaleImg/ImageDownloader.java rename to common_base/src/main/java/com/wss/common/view/gallery/ImageDownloader.java index 71235e7..4fb1625 100644 --- a/common_base/src/main/java/com/wss/common/widget/scaleImg/ImageDownloader.java +++ b/common_base/src/main/java/com/wss/common/view/gallery/ImageDownloader.java @@ -1,4 +1,4 @@ -package com.wss.common.widget.scaleImg; +package com.wss.common.view.gallery; import android.app.Activity; @@ -9,5 +9,13 @@ * Created by 吴天强 on 2018年11月16日 */ public interface ImageDownloader { + + /** + * 下载 + * + * @param url URL + * @param activity activity + * @return File + */ File downLoad(String url, Activity activity); } \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/view/gallery/ImageGallery.java b/common_base/src/main/java/com/wss/common/view/gallery/ImageGallery.java new file mode 100644 index 0000000..60c257a --- /dev/null +++ b/common_base/src/main/java/com/wss/common/view/gallery/ImageGallery.java @@ -0,0 +1,36 @@ +package com.wss.common.view.gallery; + + +import com.wss.common.base.bean.BaseBean; + +import lombok.Getter; +import lombok.Setter; + +/** + * Describe:缩放图片Bean + * Created by 吴天强 on 2019/7/31. + */ +@Getter +@Setter +public class ImageGallery extends BaseBean { + /** + * 图片描述 + */ + private String describe; + /** + * 图片地址 如果是本地图片 则是图片文件的绝对路径 + */ + private String url; + + public ImageGallery() { + } + + public ImageGallery(String url) { + this.url = url; + } + + public ImageGallery(String describe, String url) { + this.describe = describe; + this.url = url; + } +} diff --git a/common_base/src/main/java/com/wss/common/view/gallery/ImageGalleryActivity.java b/common_base/src/main/java/com/wss/common/view/gallery/ImageGalleryActivity.java new file mode 100644 index 0000000..73a9d6b --- /dev/null +++ b/common_base/src/main/java/com/wss/common/view/gallery/ImageGalleryActivity.java @@ -0,0 +1,230 @@ +package com.wss.common.view.gallery; + +import android.app.Activity; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.target.Target; +import com.davemorrissey.labs.subscaleview.ImageSource; +import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView; +import com.orhanobut.logger.Logger; +import com.wss.common.base.BaseFullScreenActivity; +import com.wss.common.base.R; +import com.wss.common.base.R2; +import com.wss.common.base.mvp.BasePresenter; +import com.wss.common.bean.Event; +import com.wss.common.constants.Dic; +import com.wss.common.constants.EventAction; +import com.wss.common.utils.EventBusUtils; +import com.wss.common.utils.ToastUtils; +import com.wss.common.utils.ValidUtils; +import com.wss.common.widget.ActionBar; +import com.wss.common.widget.IconFontTextView; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ExecutionException; + +import androidx.annotation.Nullable; +import androidx.viewpager.widget.ViewPager; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; + +/** + * Describe:图片画廊 + * Created by 吴天强 on 2020/4/29. + */ +@SuppressWarnings("unchecked") +public class ImageGalleryActivity extends BaseFullScreenActivity { + + @BindView(R2.id.rl_title_bar) + View titleBarLayout; + + @BindView(R2.id.actionbar) + ActionBar actionBar; + + @BindView(R2.id.view_pager) + ViewPager mViewPager; + + @BindView(R2.id.tv_img_count) + TextView tvImgCount; + + @BindView(R2.id.tv_describe) + TextView tvDescribe; + + private Unbinder butterKnifeBind; + private Activity activity; + + /*** + * 图片集合 + */ + private List imageList = new ArrayList<>(); + private List mViews = new ArrayList<>(); + + private int currentPosition; + + private ImageViewerAdapter mAdapter; + /** + * 是否是本地图片 + */ + private boolean isLocalImage; + /** + * 是否全屏显示 + */ + private boolean isFullScreen; + + @Override + protected BasePresenter createPresenter() { + return null; + } + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + isFullScreen = getIntent().getBooleanExtra(Dic.FULL_SCREEN, false); + if (isFullScreen) { + requestWindowFeature(Window.FEATURE_NO_TITLE); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_image_gallery); + activity = this; + butterKnifeBind = ButterKnife.bind(this); + Collection serializableExtra = (Collection) getIntent().getSerializableExtra(Dic.IMAGE_LIST); + if (serializableExtra != null) { + imageList.addAll(serializableExtra); + } else { + ToastUtils.show(context, getString(R.string.please_setting_image)); + finish(); + } + isLocalImage = getIntent().getBooleanExtra(Dic.IMAGE_LOCAL, false); + currentPosition = getIntent().getIntExtra(Dic.IMAGE_POSITION, 0); + loadImage(); + mAdapter = new ImageViewerAdapter(mViews); + mViewPager.setAdapter(mAdapter); + mViewPager.setCurrentItem(currentPosition); + mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + + } + + @Override + public void onPageSelected(int position) { + currentPosition = position; + setImageChangeText(); + } + + @Override + public void onPageScrollStateChanged(int state) { + + } + }); + if (!isFullScreen) { + titleBarLayout.setVisibility(View.VISIBLE); + tvImgCount.setVisibility(View.GONE); + IconFontTextView rightIcon = new IconFontTextView(context); + rightIcon.setTextColor(getResources().getColor(R.color.color_333333)); + rightIcon.setTextSize(14); + rightIcon.setValue(getString(R.string.icon_delete)); + rightIcon.setOnClickListener(v -> { + //删除照片发个通知出去 带上删除的position + ToastUtils.show(context, getString(R.string.delete_success)); + EventBusUtils.sendEvent(new Event(EventAction.IMAGE_GALLERY_DELETE, currentPosition)); + imageList.remove(currentPosition); + int size = imageList.size(); + if (size < 1) { + finish(); + return; + } + mViewPager.removeView(mViews.remove(currentPosition)); + mAdapter.notifyDataSetChanged(); + setImageChangeText(); + }); + actionBar.setRightView(rightIcon); + actionBar.setLeftIcon(R.drawable.ic_back_black, v -> { + + }); + actionBar.setCenterTextColor(R.color.color_333333); + //加粗 + actionBar.setCenterTextBold(true); + actionBar.showBackImg(true); + } + setImageChangeText(); + } + + private void setImageChangeText() { + if (isFullScreen) { + tvImgCount.setText(String.format("%s/%s", currentPosition + 1, imageList.size())); + } else { + actionBar.setCenterText(String.format("%s/%s", currentPosition + 1, imageList.size())); + } + tvDescribe.setText(imageList.get(currentPosition).getDescribe()); + } + + private void loadImage() { + for (ImageGallery imageGallery : imageList) { + SubsamplingScaleImageView scaleImageView = new SubsamplingScaleImageView(context); + scaleImageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + if (isFullScreen) { + scaleImageView.setOnClickListener(v -> finish()); + } + + if (isLocalImage) { + scaleImageView.setImage(ImageSource.uri(Uri.fromFile(new File(imageGallery.getUrl())))); + } else { + if (!ValidUtils.isValid(imageGallery.getUrl())) { + return; + } + IOThread.getSingleThread().execute(() -> { + File downLoadFile; + try { + downLoadFile = mImageDownloader.downLoad(imageGallery.getUrl(), activity); + //如果图片路径不为空则开始执行 + if (ValidUtils.isValid(downLoadFile)) { + activity.runOnUiThread(() -> scaleImageView.setImage(ImageSource.uri(Uri.fromFile(downLoadFile)))); + } + } catch (Exception e) { + e.printStackTrace(); + Logger.e("加载图片异常" + e.getMessage()); + } + }); + } + mViews.add(scaleImageView); + } + + } + + /** + * 图片下载器 + */ + private ImageDownloader mImageDownloader = (url, activity) -> { + File file = null; + try { + file = Glide.with(activity) + .load(url) + .downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) + .get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + Logger.e("下载图片异常" + e.getMessage()); + } + return file; + }; + + @Override + protected void onDestroy() { + super.onDestroy(); + if (butterKnifeBind != null) { + butterKnifeBind.unbind(); + } + } +} diff --git a/common_base/src/main/java/com/wss/common/widget/scaleImg/ImageViewerAdapter.java b/common_base/src/main/java/com/wss/common/view/gallery/ImageViewerAdapter.java similarity index 78% rename from common_base/src/main/java/com/wss/common/widget/scaleImg/ImageViewerAdapter.java rename to common_base/src/main/java/com/wss/common/view/gallery/ImageViewerAdapter.java index d82d370..149a774 100644 --- a/common_base/src/main/java/com/wss/common/widget/scaleImg/ImageViewerAdapter.java +++ b/common_base/src/main/java/com/wss/common/view/gallery/ImageViewerAdapter.java @@ -1,25 +1,24 @@ -package com.wss.common.widget.scaleImg; +package com.wss.common.view.gallery; -import android.app.Dialog; -import android.support.annotation.NonNull; -import android.support.v4.view.PagerAdapter; import android.view.View; import android.view.ViewGroup; +import org.jetbrains.annotations.NotNull; + import java.util.List; +import androidx.annotation.NonNull; +import androidx.viewpager.widget.PagerAdapter; + /** * Describe:图片查看器适配器 * Created by 吴天强 on 2018年11月16日 */ class ImageViewerAdapter extends PagerAdapter { - private List views; - private Dialog dialog; - ImageViewerAdapter(List views, Dialog dialog) { + ImageViewerAdapter(List views) { this.views = views; - this.dialog = dialog; } @NonNull @@ -30,9 +29,8 @@ public Object instantiateItem(@NonNull ViewGroup container, int position) { } @Override - public void destroyItem(@NonNull ViewGroup container, int position, Object object) { + public void destroyItem(@NonNull ViewGroup container, int position, @NotNull Object object) { if (position == 0 && views.size() == 0) { - dialog.dismiss(); return; } if (position == views.size()) { diff --git a/common_base/src/main/java/com/wss/common/view/scan/ScanActivity.java b/common_base/src/main/java/com/wss/common/view/scan/ScanActivity.java new file mode 100644 index 0000000..b071433 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/view/scan/ScanActivity.java @@ -0,0 +1,106 @@ +package com.wss.common.view.scan; + +import android.view.View; + +import com.orhanobut.logger.Logger; +import com.wss.common.base.BaseActivity; +import com.wss.common.base.R; +import com.wss.common.base.R2; +import com.wss.common.bean.Event; +import com.wss.common.constants.EventAction; +import com.wss.common.utils.EventBusUtils; +import com.wss.common.utils.PermissionsUtils; +import com.wss.common.utils.ToastUtils; + +import java.util.Arrays; + +import butterknife.BindView; +import butterknife.OnClick; +import me.devilsen.czxing.code.BarcodeFormat; +import me.devilsen.czxing.view.ScanBoxView; +import me.devilsen.czxing.view.ScanListener; +import me.devilsen.czxing.view.ScanView; + + +/** + * Describe:扫一扫首页 + * Created by 吴天强 on 2019/12/27. + */ +public class ScanActivity extends BaseActivity { + + @BindView(R2.id.qr_code_view) + ScanView qrCodeView; + + @Override + protected void initView() { + PermissionsUtils.checkCamera(this).subscribe( + aBoolean -> { + if (aBoolean) { + qrCodeView.setScanListener(new ScanListener() { + @Override + public void onScanSuccess(String result, BarcodeFormat format) { + Logger.e("二维码扫描结果:" + result); + ToastUtils.show(result); + EventBusUtils.sendEvent(new Event<>(EventAction.SCAN_QR_CODE_RESULT, result)); + finish(); + } + + @Override + public void onOpenCameraError() { + ToastUtils.show(context, "打开相机出错"); + } + }); + ScanBoxView scanBox = qrCodeView.getScanBox(); + scanBox.setCornerColor(getResources().getColor(R.color.theme));//扫描四角颜色 + scanBox.setScanLineColor(Arrays.asList(getResources().getColor(R.color.theme), + getResources().getColor(R.color.theme), getResources().getColor(R.color.theme)));//扫描线条颜色 + + } else { + finish(); + } + } + ); + } + + + @OnClick(R2.id.iv_back) + public void onClick(View v) { + finish(); + } + + @Override + protected void onResume() { + super.onResume(); + if (qrCodeView != null) { + // 打开后置摄像头开始预览,但是并未开始识别 + qrCodeView.openCamera(); + // 显示扫描框,并开始识别 + qrCodeView.startScan(); + } + } + + @Override + protected void onPause() { + super.onPause(); + if (qrCodeView != null) { + qrCodeView.stopScan(); + //关闭摄像头预览,并且隐藏扫描框 + qrCodeView.closeCamera(); + } + } + + + @Override + protected void onDestroy() { + super.onDestroy(); + if (qrCodeView != null) { + qrCodeView.onDestroy(); + } + } + + @Override + protected int getLayoutId() { + return R.layout.activity_scan; + } + +} diff --git a/common_base/src/main/java/com/wss/common/widget/ActionBar.java b/common_base/src/main/java/com/wss/common/widget/ActionBar.java index e49f9f1..3e6d4be 100644 --- a/common_base/src/main/java/com/wss/common/widget/ActionBar.java +++ b/common_base/src/main/java/com/wss/common/widget/ActionBar.java @@ -2,7 +2,7 @@ import android.app.Activity; import android.content.Context; -import android.support.v4.content.ContextCompat; +import android.graphics.Typeface; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; @@ -14,12 +14,13 @@ import com.wss.common.base.R; import com.wss.common.utils.PxUtils; +import androidx.core.content.ContextCompat; + /** * Describe:自定义的ActionBar * Created by 吴天强 on 2017/8/22. */ - public class ActionBar extends RelativeLayout { private LinearLayout llActionbar; @@ -35,16 +36,20 @@ public class ActionBar extends RelativeLayout { /** * 字体颜色 */ - private int leftTextColor = R.color.white; - private int centerTextColor = R.color.white; - private int rightTextColor = R.color.white; + private int leftTextColor = R.color.black; + private int centerTextColor = R.color.black; + private int rightTextColor = R.color.black; /** * 字体大小 */ private int lefTextSize = 16; - private int centerTextSize = 16; + private int centerTextSize = 18; private int rightTextSize = 16; + /** + * 中间显示字体是否加粗 + */ + private boolean isCenterTextBold; public ActionBar(Context context) { this(context, null); @@ -81,10 +86,19 @@ public void setRightTextSize(int rightTextSize) { this.rightTextSize = rightTextSize; } + /** + * 是否加粗中间显示的字体 + * + * @param centerTextBold 是否加粗 + */ + public void setCenterTextBold(boolean centerTextBold) { + isCenterTextBold = centerTextBold; + } + /** * 获取跟布局 */ - public View getRootView() { + public View getActionBarRootView() { return rootView; } @@ -110,10 +124,12 @@ public void setLeftIcon(int res, OnClickListener l) { llLeft.setVisibility(VISIBLE); llLeft.setVisibility(VISIBLE); llLeft.removeAllViews(); - ImageView ivLeft = new ImageView(getContext()); + ImageView ivLeft = getImageView(); ivLeft.setImageResource(res); llLeft.addView(ivLeft); - llLeft.setOnClickListener(l); + if (l != null) { + llLeft.setOnClickListener(l); + } } /** @@ -125,7 +141,7 @@ public void setLeftIcon(int res, OnClickListener l) { public void setCenterIcon(int res, OnClickListener l) { llCenter.setVisibility(VISIBLE); llCenter.removeAllViews(); - ImageView center = new ImageView(getContext()); + ImageView center = getImageView(); center.setImageResource(res); llCenter.addView(center); llCenter.setOnClickListener(l); @@ -140,7 +156,7 @@ public void setCenterIcon(int res, OnClickListener l) { public void setRightIcon(int res, OnClickListener l) { llRight.setVisibility(VISIBLE); llRight.removeAllViews(); - ImageView right = new ImageView(getContext()); + ImageView right = getImageView(); right.setImageResource(res); llRight.addView(right); if (l != null) { @@ -192,6 +208,9 @@ public void setCenterText(CharSequence text, OnClickListener l) { center.setEllipsize(TextUtils.TruncateAt.END); center.setMaxLines(1); center.setTextColor(getResources().getColor(centerTextColor)); + if (isCenterTextBold) { + center.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); + } llCenter.addView(center); if (l != null) { llCenter.setOnClickListener(l); @@ -309,13 +328,10 @@ public void setRightView(View v, OnClickListener listener) { */ public void showBackImg(boolean show) { if (show) { - setLeftIcon(R.drawable.ic_back, new OnClickListener() { - @Override - public void onClick(View v) { - Context ctx = ActionBar.this.getContext(); - if (ctx instanceof Activity) { - ((Activity) ctx).onBackPressed(); - } + setLeftIcon(R.drawable.ic_back_black, v -> { + Context ctx = ActionBar.this.getContext(); + if (ctx instanceof Activity) { + ((Activity) ctx).onBackPressed(); } }); } else { @@ -349,7 +365,7 @@ public TextView getTextView() { */ public ImageView getImageView() { ImageView iv = new ImageView(getContext()); - iv.setLayoutParams(new LayoutParams(PxUtils.dp2px(getContext(), 25), PxUtils.dp2px(getContext(), 25))); + iv.setLayoutParams(new LayoutParams(PxUtils.dp2px(24), PxUtils.dp2px(24))); return iv; } diff --git a/common_base/src/main/java/com/wss/common/widget/AutoTextView.java b/common_base/src/main/java/com/wss/common/widget/AutoTextView.java new file mode 100644 index 0000000..f12011e --- /dev/null +++ b/common_base/src/main/java/com/wss/common/widget/AutoTextView.java @@ -0,0 +1,65 @@ +package com.wss.common.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.ViewTreeObserver; + +/** + * 自动改变其显示行数的TextView + * create by yangwei + * on 2020/6/8 17:12 + */ +public class AutoTextView extends androidx.appcompat.widget.AppCompatTextView { + public AutoTextView(Context context) { + super(context); + } + + public AutoTextView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + // 标记当前TextView的展开/收缩状态 + // true,已经展开 + // false,以及收缩 + private boolean expandableStatus = false; + private final int MAX_LINES = 2;//默认最多显示多少行 + private int lines;//如果textview内容完全神展开需要显示多少 + + private void init() { + final ViewTreeObserver mViewTreeObserver = this.getViewTreeObserver(); + + mViewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + + @Override + public boolean onPreDraw() { + // 避免重复监听 + AutoTextView.this.getViewTreeObserver().removeOnPreDrawListener(this); + lines = getLineCount(); + return true; + } + }); + this.setMaxLines(MAX_LINES); + } + + /** + * 是否展开 + * + * @param isExpand + */ + public void setExpandable(boolean isExpand) { + if (isExpand) { + + setMaxLines(lines + 1); + } else { + + setMaxLines(MAX_LINES); + } + + expandableStatus = isExpand; + } + + public boolean getExpandableStatus() { + return expandableStatus; + } +} diff --git a/common_base/src/main/java/com/wss/common/widget/CountClickView.java b/common_base/src/main/java/com/wss/common/widget/CountClickView.java index d65b611..97a0b87 100644 --- a/common_base/src/main/java/com/wss/common/widget/CountClickView.java +++ b/common_base/src/main/java/com/wss/common/widget/CountClickView.java @@ -1,6 +1,9 @@ package com.wss.common.widget; import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.text.InputType; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; @@ -11,16 +14,22 @@ import com.wss.common.base.R; import com.wss.common.base.R2; import com.wss.common.utils.PxUtils; +import com.wss.common.utils.ToastUtils; +import com.wss.common.utils.Utils; import com.wss.common.widget.dialog.AppDialog; import com.wss.common.widget.dialog.DialogType; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import androidx.core.content.ContextCompat; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; /** - * Describe:加减Viw + * Describe:加减Viw,最大支持10000,最小支持 0 * Created by 吴天强 on 2018年9月27日18:13:09 */ public class CountClickView extends LinearLayout { @@ -39,21 +48,29 @@ public class CountClickView extends LinearLayout { @BindView(R2.id.iv_minus) ImageView ivMinus; + /** + * 减 控件父类 + */ @BindView(R2.id.ll_minus) - LinearLayout llMinus;//减 控件父类 - + LinearLayout llMinus; + /** + * 加 控件父类 + */ @BindView(R2.id.ll_plus) - LinearLayout llPlus;//加 控件父类 - private Context mContext; + LinearLayout llPlus; + private int maxCount = MAX_COUNT; private int minCount = MIN_COUNT; + private int currentCount = INIT_COUNT; + private int textColor = Color.BLACK; + private int textSize = 14; + + /** + * 是否支持如输入 默认不支持 + */ + private boolean input = false; - //控件资源 - private int minusCan = R.drawable.input_minus_default; - private int minusNot = R.drawable.input_minus_disabled; - private int addCan = R.drawable.input_add_default; - private int addNot = R.drawable.input_add_disabled; - private boolean input = false;//是否支持如输入 默认不支持 + private OnClickAfterListener afterClickListener = null; public CountClickView(Context context) { this(context, null); @@ -62,174 +79,169 @@ public CountClickView(Context context) { public CountClickView(Context context, AttributeSet attrs) { super(context, attrs); - init(context); - } - - - private OnClickAfterListener afterClickListener = null; + TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CountClickView); + maxCount = a.getInt(R.styleable.CountClickView_ccvMax, maxCount); + minCount = a.getInt(R.styleable.CountClickView_ccvMin, minCount); + currentCount = a.getInt(R.styleable.CountClickView_ccvCurrent, currentCount); + input = a.getBoolean(R.styleable.CountClickView_ccvInput, input); + textColor = a.getColor(R.styleable.CountClickView_ccvTextColor, textColor); + textSize = a.getDimensionPixelSize(R.styleable.EnhanceEditText_eTextSize, textSize); + a.recycle(); + init(); + } - private void init(Context context) { - this.mContext = context; + private void init() { this.setBackgroundResource(android.R.color.transparent); - ButterKnife.bind(this, View.inflate(context, R.layout.layout_count_click_view, this)); - - tvCount.setOnClickListener(new OnClickListener() { - @Override - public void onClick(final View v) { - if (input) { - new AppDialog(mContext, DialogType.COUNT) - .setTitle("修改数量") - .setRightButton(new AppDialog.OnButtonClickListener() { - @Override - public void onClick(String val) { - tvCount.setText(val); - if (afterClickListener != null) { - afterClickListener.onAfter(getCount()); - if (getCount() == getMinCount()) { - afterClickListener.onMin(); - } - } - judgeTheViews(Integer.valueOf(val)); - } - }) - .setNumber(minCount, maxCount, getCount()) - .show(); - } - } - }); - + ButterKnife.bind(this, View.inflate(getContext(), R.layout.layout_count_click_view, this)); + setTextColor(textColor); + setTextSize(textSize); + setCurrCount(currentCount); judgeTheViews(getCount()); } - public int getCount() { - String text = tvCount.getText().toString().trim(); - if (TextUtils.isEmpty(text)) { - return INIT_COUNT; - } - return Integer.valueOf(text); - } - - @OnClick({R2.id.iv_plus, R2.id.iv_minus}) - public void onClick(View v) { - int count = Integer.valueOf(tvCount.getText().toString().trim()); - - if (R.id.iv_plus == v.getId()) { - if (count < getMaxCount()) + @OnClick({R2.id.ll_minus, R2.id.ll_plus}) + public void onClick(@NotNull View v) { + int count = getCount(); + if (R.id.ll_plus == v.getId()) { + if (count < getMaxCount()) { tvCount.setText(String.valueOf(++count)); - } - if (R.id.iv_minus == v.getId()) { - if (count > getMinCount()) + } + } else if (R.id.ll_minus == v.getId()) { + if (count > getMinCount()) { tvCount.setText(String.valueOf(--count)); + } + } else if (R.id.tv_count == v.getId()) { } - judgeTheViews(count); - if (afterClickListener != null) { - afterClickListener.onAfter(getCount()); - if (getCount() == getMinCount()) { - afterClickListener.onMin(); - } + afterClickListener.onAfter(this, getCount()); } } - private void judgeTheViews(int count) { - if (count <= getMinCount()) { - ivMinus.setImageResource(minusNot); - } else { - ivMinus.setImageResource(minusCan); - } - if (count >= getMaxCount()) { - ivPlus.setImageResource(addNot); - } else { - ivPlus.setImageResource(addCan); + @OnClick({R2.id.tv_count}) + public void onCountClick() { + if (input) { + new AppDialog.Builder(getContext()) + .setDialogType(DialogType.INPUT) + .setInputType(InputType.TYPE_CLASS_NUMBER) + .setInputDefaultText(String.valueOf(getCount())) + .setTitle("输入数量") + .setRightButton(getContext().getString(R.string.confirm), val -> { + if (Utils.isNumber(val)) { + int count = Integer.parseInt(val); + if (count > MAX_COUNT) { + count = maxCount; + ToastUtils.show("超过了设置的最大值"); + } else if (count < MIN_COUNT) { + count = MIN_COUNT; + ToastUtils.show("超过了设置的最小值"); + } + setCurrCount(count); + } + }) + .create() + .show(); } } + /** - * 设置 按钮父类的大小 + * 根据加减 设置显示的控件View + * + * @param count 数量 */ - public void setBtnParentSize(int width, int height) { - llMinus.setLayoutParams(new LinearLayout.LayoutParams(PxUtils.dp2px(mContext, width), - PxUtils.dp2px(mContext, height))); - llPlus.setLayoutParams(new LinearLayout.LayoutParams(PxUtils.dp2px(mContext, width), - PxUtils.dp2px(mContext, height))); - //如果设置了该处大小 则需要更新中间View的高度 - LinearLayout.LayoutParams layoutParams = (LayoutParams) tvCount.getLayoutParams(); - layoutParams.height = PxUtils.dp2px(mContext, height); + private void judgeTheViews(int count) { + ivMinus.setEnabled(count > getMinCount()); + ivPlus.setEnabled(count < getMaxCount()); } /** - * 设置 按钮父类背景 + * 判断最大值 + * + * @return 返回最大值 */ - public void setBtnParentBg(int bgColor) { - llMinus.setBackgroundColor(getResources().getColor(bgColor)); - llPlus.setBackgroundColor(getResources().getColor(bgColor)); + @Contract(pure = true) + private int getMaxCount() { + return Math.min(maxCount, MAX_COUNT); } - /** - * 设置加减按钮大小 + * 判断最小值 + * + * @return 返回最小值 */ - public void setBtnSize(int width, int height) { - ivPlus.setLayoutParams(new LinearLayout.LayoutParams(PxUtils.dp2px(mContext, width), - PxUtils.dp2px(mContext, height))); - ivMinus.setLayoutParams(new LinearLayout.LayoutParams(PxUtils.dp2px(mContext, width), - PxUtils.dp2px(mContext, height))); + @Contract(pure = true) + private int getMinCount() { + return Math.max(minCount, MIN_COUNT); } /** - * 设置加减控件的资源文件 + * 设置监听 + * + * @param afterClickListener l */ - public void setButtonRes(int minusCan, int minusNot, int addCan, int addNot) { - this.minusCan = minusCan; - this.minusNot = minusNot; - this.addCan = addCan; - this.addNot = addNot; - //给按钮设置默认值 - ivMinus.setImageResource(minusCan); - ivPlus.setImageResource(addCan); + public void setAfterClickListener(OnClickAfterListener afterClickListener) { + this.afterClickListener = afterClickListener; } - /*** - * 设置中间View一些属性 - * @param bgColor 背景色 - * @param textColor 字体颜色 使用默认颜色 给0 即可 - * @param marginLeft marginLeft - * @param marginRight marginRight + /** + * 设置是否支出输入 默认不支持 + * + * @param input 输入 */ - public void setCountViewAttr(int bgColor, int textColor, int marginLeft, int marginRight) { - LinearLayout.LayoutParams layoutParams = (LayoutParams) tvCount.getLayoutParams(); - layoutParams.setMargins(PxUtils.dp2px(mContext, marginLeft), 0, PxUtils.dp2px(mContext, marginRight), 0); - tvCount.setBackgroundColor(getResources().getColor(bgColor)); - if (textColor != 0) { - tvCount.setTextColor(getResources().getColor(textColor)); - } + public void setInput(boolean input) { + this.input = input; } - /** - * 是否支出输入 + * 设置文字颜色 + * + * @param textColor 颜色 */ - public void setInput(boolean input) { - this.input = input; + public void setTextColor(int textColor) { + this.textColor = textColor; + tvCount.setTextColor(textColor); } + /** + * 设置文字大小 + * + * @param textSize 大小 + */ + public void setTextSize(int textSize) { + this.textSize = textSize; + tvCount.setTextSize(this.textSize); + } + /** + * 设置默认显示的数量 + * + * @param count 数量 + */ public void setCurrCount(int count) { tvCount.setText(String.valueOf(count)); judgeTheViews(count); } + /** + * 设置最大值 + * + * @param maxCount 最大值 + */ public void setMaxCount(int maxCount) { if (maxCount < getMinCount()) { maxCount = INIT_COUNT; } - this.maxCount = maxCount; judgeTheViews(getCount()); } + /** + * 设置最小值 + * + * @param minCount 最小值 + */ public void setMinCount(int minCount) { if (minCount > getMaxCount()) { minCount = INIT_COUNT; @@ -239,23 +251,88 @@ public void setMinCount(int minCount) { } - private int getMaxCount() { - return maxCount < MAX_COUNT ? maxCount : MAX_COUNT; + /** + * 返回操作后的数量 + * + * @return 数量 + */ + public int getCount() { + String text = tvCount.getText().toString().trim(); + if (TextUtils.isEmpty(text)) { + return INIT_COUNT; + } + return Integer.parseInt(text); } - private int getMinCount() { - return minCount > MIN_COUNT ? minCount : MIN_COUNT; + + /** + * 设置 按钮父类的大小 + */ + public void setBtnParentSize(int width, int height) { + llMinus.setLayoutParams(new LinearLayout.LayoutParams(PxUtils.dp2px(width), PxUtils.dp2px(height))); + llPlus.setLayoutParams(new LinearLayout.LayoutParams(PxUtils.dp2px(width), PxUtils.dp2px(height))); + //如果设置了该处大小 则需要更新中间View的高度 + LinearLayout.LayoutParams layoutParams = (LayoutParams) tvCount.getLayoutParams(); + layoutParams.height = PxUtils.dp2px(height); } - public interface OnClickAfterListener { + /** + * 设置 按钮父类背景 + */ + public void setBtnParentBg(int bgColor) { + llMinus.setBackgroundColor(ContextCompat.getColor(getContext(), bgColor)); + llPlus.setBackgroundColor(ContextCompat.getColor(getContext(), bgColor)); + } - void onAfter(int value); - void onMin(); + /** + * 设置加减按钮大小 + */ + public void setBtnSize(int width, int height) { + ivPlus.setLayoutParams(new LinearLayout.LayoutParams(PxUtils.dp2px(width), + PxUtils.dp2px(height))); + ivMinus.setLayoutParams(new LinearLayout.LayoutParams(PxUtils.dp2px(width), + PxUtils.dp2px(height))); } - public void setAfterClickListener(OnClickAfterListener afterClickListener) { - this.afterClickListener = afterClickListener; + /** + * 设置加减控件的资源文件 + */ + public void setButtonRes(int addDrawable, int minusDrawable) { + ivPlus.setBackgroundResource(addDrawable); + ivMinus.setBackgroundResource(minusDrawable); + } + + + /*** + * 设置中间View一些属性 + * @param bgColor 背景色 + * @param textColor 字体颜色 使用默认颜色 给0 即可 + * @param marginLeft marginLeft + * @param marginRight marginRight + */ + public void setCountViewAttr(int bgColor, int textColor, int marginLeft, int marginRight) { + LinearLayout.LayoutParams layoutParams = (LayoutParams) tvCount.getLayoutParams(); + layoutParams.setMargins(PxUtils.dp2px(marginLeft), 0, PxUtils.dp2px(marginRight), 0); + tvCount.setBackgroundColor(ContextCompat.getColor(getContext(), bgColor)); + if (textColor != 0) { + tvCount.setTextColor(ContextCompat.getColor(getContext(), textColor)); + } + } + + /** + * 操作之后监听回调 + */ + public interface OnClickAfterListener { + + /** + * 操作之后 + * + * @param view CountClickView + * @param value 值 + */ + void onAfter(CountClickView view, int value); } + } diff --git a/common_base/src/main/java/com/wss/common/widget/EnhanceEditText.java b/common_base/src/main/java/com/wss/common/widget/EnhanceEditText.java new file mode 100644 index 0000000..d34cb5a --- /dev/null +++ b/common_base/src/main/java/com/wss/common/widget/EnhanceEditText.java @@ -0,0 +1,388 @@ +package com.wss.common.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.text.Editable; +import android.text.InputFilter; +import android.text.InputType; +import android.text.TextWatcher; +import android.text.method.PasswordTransformationMethod; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.widget.EditText; +import android.widget.LinearLayout; + +import com.wss.common.base.R; +import com.wss.common.base.R2; +import com.wss.common.utils.KeyboardUtils; +import com.wss.common.utils.ValidUtils; + +import androidx.annotation.Nullable; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; + +/** + * Describe 增强版输入框,左右带图标 + * Created by 吴天强 on 2020/4/20. + */ +public class EnhanceEditText extends LinearLayout { + /** + * 无操作 + */ + public static final int ACTION_NONE = 0; + /** + * 搜索事件 + */ + public static final int ACTION_SEARCH = 1; + /** + * 下一步 + */ + public static final int ACTION_NEXT = 2; + /** + * 完成 + */ + public static final int ACTION_DONE = 3; + + /** + * 输入文本 + */ + public static final int INPUT_TEXT = 0; + /** + * 输入密码 + */ + public static final int INPUT_PASSWORD = 1; + + /** + * 输入手机 + */ + public static final int INPUT_PHONE = 2; + /** + * 输入数字 + */ + public static final int INPUT_NUMBER = 3; + + + @BindView(R2.id.ll_edt_view) + LinearLayout llEdtView; + + @BindView(R2.id.iftv_left) + IconFontTextView iftvLeft; + + @BindView(R2.id.edt_text) + EditText editText; + + @BindView(R2.id.iftv_clean) + IconFontTextView iftvClean; + + @BindView(R2.id.ll_clean_view) + View cleanView; + + private int textColor = 0xFF333333; + private int hintColor = 0XFF999999; + private int leftIconColor = 0XFF999999; + private int cleanIconColor = 0XFF999999; + private String leftIcon; + private String cleanIcon; + private String hintText; + private int textSize = 14; + /** + * 背景资源 + */ + private int bgResource = R.drawable.bg_of_color_f5_4radius; + /** + * 是否显示清除按钮 默认true + */ + private boolean showCleanIcon = true; + /** + * 是否现在左侧icon 默认true + */ + private boolean showLeftIcon = true; + /** + * 是否显示背景 默认true + */ + private boolean showBackground = true; + /** + * 键盘最后执行的Action + */ + private int action = ACTION_NONE; + /** + * 输入框类型 + */ + private int inputType = INPUT_TEXT; + private int maxLength; + private int maxLines; + + private OnTextChangeListener onTextChangeListener; + private OnActionClickListener onActionClickListener; + + + public EnhanceEditText(Context context) { + this(context, null); + } + + public EnhanceEditText(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public EnhanceEditText(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + ButterKnife.bind(this, View.inflate(getContext(), R.layout.layout_search, this)); + TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.EnhanceEditText); + textColor = a.getColor(R.styleable.EnhanceEditText_eTextColor, textColor); + hintColor = a.getColor(R.styleable.EnhanceEditText_eHintTextColor, hintColor); + leftIcon = a.getString(R.styleable.EnhanceEditText_eLeftIconFont); + leftIconColor = a.getColor(R.styleable.EnhanceEditText_eLeftIconColor, leftIconColor); + cleanIcon = a.getString(R.styleable.EnhanceEditText_eCleanIconFont); + cleanIconColor = a.getColor(R.styleable.EnhanceEditText_eCleanIconColor, cleanIconColor); + hintText = a.getString(R.styleable.EnhanceEditText_eHintText); + textSize = a.getDimensionPixelSize(R.styleable.EnhanceEditText_eTextSize, textSize); + showCleanIcon = a.getBoolean(R.styleable.EnhanceEditText_eShowClean, showCleanIcon); + bgResource = a.getResourceId(R.styleable.EnhanceEditText_eBg, bgResource); + showLeftIcon = a.getBoolean(R.styleable.EnhanceEditText_eShowLeft, showLeftIcon); + showBackground = a.getBoolean(R.styleable.EnhanceEditText_eShowBg, showBackground); + action = a.getInt(R.styleable.EnhanceEditText_eAction, action); + inputType = a.getInt(R.styleable.EnhanceEditText_eInputType, inputType); + maxLength = a.getInt(R.styleable.EnhanceEditText_eMaxLength, maxLength); + maxLines = a.getInt(R.styleable.EnhanceEditText_eMaxLines, maxLines); + a.recycle(); + initView(); + } + + private void initView() { + setGravity(Gravity.CENTER_VERTICAL); + if (showBackground) { + setBackgroundResource(bgResource); + } + if (showLeftIcon && ValidUtils.isValid(leftIcon)) { + iftvLeft.setValue(leftIcon); + iftvLeft.setTextColor(leftIconColor); + } else { + iftvLeft.setVisibility(VISIBLE); + } + if (showCleanIcon && ValidUtils.isValid(cleanIcon)) { + iftvClean.setValue(cleanIcon); + iftvClean.setTextColor(cleanIconColor); + } + editText.setHint(hintText); + editText.setTextSize(textSize); + editText.setTextColor(textColor); + editText.setHintTextColor(hintColor); + editText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + if (onTextChangeListener != null) { + onTextChangeListener.beforeTextChanged(s, start, count, after); + } + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + if (onTextChangeListener != null) { + onTextChangeListener.onTextChanged(s, start, before, count); + } + } + + @Override + public void afterTextChanged(Editable s) { + if (onTextChangeListener != null) { + onTextChangeListener.afterTextChanged(s); + } + if (showCleanIcon) { + cleanView.setVisibility(s.toString().length() > 0 ? VISIBLE : GONE); + } + } + }); + setInputFiller(); + setOnEditorAction(); + } + + /** + * 设置输入框的一些属性 + */ + private void setInputFiller() { + switch (inputType) { + case INPUT_PASSWORD: + editText.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD); + editText.setTransformationMethod(PasswordTransformationMethod.getInstance()); + break; + case INPUT_PHONE: + editText.setInputType(InputType.TYPE_CLASS_PHONE); + break; + case INPUT_NUMBER: + editText.setInputType(InputType.TYPE_CLASS_NUMBER); + break; + case INPUT_TEXT: + default: + editText.setInputType(InputType.TYPE_CLASS_TEXT); + break; + } + if (maxLength > 0) { + editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)}); + } + if (maxLines > 0) { + editText.setMaxLines(maxLines); + } + } + + /** + * 设置输入框的执行事件 + */ + private void setOnEditorAction() { + switch (action) { + case ACTION_SEARCH: + editText.setImeOptions(EditorInfo.IME_ACTION_SEARCH); + break; + case ACTION_NEXT: + editText.setImeOptions(EditorInfo.IME_ACTION_NEXT); + break; + case ACTION_DONE: + editText.setImeOptions(EditorInfo.IME_ACTION_DONE); + break; + case ACTION_NONE: + default: + editText.setImeOptions(EditorInfo.IME_ACTION_NONE); + break; + } + + editText.setOnEditorActionListener((v, actionId, event) -> { + KeyboardUtils.hideKeyboard(v); + if (onActionClickListener == null) { + return false; + } + switch (actionId) { + case EditorInfo.IME_ACTION_SEARCH: + //搜索 + onActionClickListener.onEditorAction(ACTION_SEARCH); + break; + case EditorInfo.IME_ACTION_NEXT: + //下一步 + onActionClickListener.onEditorAction(ACTION_NEXT); + break; + case EditorInfo.IME_ACTION_DONE: + //完成 + onActionClickListener.onEditorAction(ACTION_DONE); + break; + case EditorInfo.IME_ACTION_NONE: + default: + //无操作 + onActionClickListener.onEditorAction(ACTION_NONE); + break; + } + return true; + }); + } + + @OnClick(R2.id.ll_clean_view) + public void onClean() { + getEditText().setText(""); + } + + + /** + * 返回输入框字符 + * + * @return String + */ + public String getText() { + return getEditText().getText().toString().trim(); + } + + /** + * 清除搜索框内容 + */ + public void clearSearchText() { + onClean(); + } + + /** + * 返回输入框View + * + * @return EditText + */ + public EditText getEditText() { + return editText; + } + + /** + * 设置搜索按钮点击回调 + * + * @param onActionClickListener OnEditActionCallback + */ + public void setOnActionClickListener(OnActionClickListener onActionClickListener) { + this.onActionClickListener = onActionClickListener; + } + + /** + * 设置文本输入变化监听 + * + * @param textChangeListener listener + */ + public void setTextChangeListener(OnTextChangeListener textChangeListener) { + this.onTextChangeListener = textChangeListener; + } + + /** + * 设置文本 + * + * @param text 文本 + */ + public void setText(CharSequence text) { + editText.setText(text); + } + + /** + * 设置输入框光标位置 + * + * @param position 位置 + */ + public void setSelection(int position) { + editText.setSelection(position); + } + + /** + * 文本输入变化监听 + */ + public interface OnTextChangeListener { + /** + * 输入前 + * + * @param s s + * @param start start + * @param count count + * @param after after + */ + void beforeTextChanged(CharSequence s, int start, int count, int after); + + /** + * 变化 + * + * @param s s + * @param start start + * @param before before + * @param count count + */ + void onTextChanged(CharSequence s, int start, int before, int count); + + /** + * 变化后 + * + * @param s 文本 + */ + void afterTextChanged(Editable s); + } + + /** + * 键盘搜索按钮点击 + */ + public interface OnActionClickListener { + /** + * 按钮被点击 + * + * @param action 事件ID + */ + void onEditorAction(int action); + } +} diff --git a/common_base/src/main/java/com/wss/common/widget/FlowLayout.java b/common_base/src/main/java/com/wss/common/widget/FlowLayout.java index f7b8e8f..40ca2e3 100644 --- a/common_base/src/main/java/com/wss/common/widget/FlowLayout.java +++ b/common_base/src/main/java/com/wss/common/widget/FlowLayout.java @@ -2,7 +2,6 @@ import android.content.Context; import android.content.res.TypedArray; -import android.support.v4.text.TextUtilsCompat; import android.util.AttributeSet; import android.util.LayoutDirection; import android.view.View; @@ -13,12 +12,13 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; - import java.util.Locale; +import androidx.core.text.TextUtilsCompat; + /** * 流式布局 - * Created by wtq on 2016/12/15. + * Created by lss on 2016/12/15. */ public class FlowLayout extends ViewGroup { private static final String TAG = "FlowLayout"; @@ -128,7 +128,7 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { for (int i = 0; i < cCount; i++) { View child = getChildAt(i); - if (child.getVisibility() == View.GONE) continue; + if (child.getVisibility() == View.GONE){ continue;} MarginLayoutParams lp = (MarginLayoutParams) child .getLayoutParams(); @@ -179,6 +179,8 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { // 适配了rtl,需要把lineViews里面的数组倒序排 Collections.reverse(lineViews); break; + default: + break; } for (int j = 0; j < lineViews.size(); j++) { diff --git a/common_base/src/main/java/com/wss/common/widget/GradientTextView.java b/common_base/src/main/java/com/wss/common/widget/GradientTextView.java new file mode 100644 index 0000000..d218b20 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/widget/GradientTextView.java @@ -0,0 +1,56 @@ +package com.wss.common.widget; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.Shader; +import android.util.AttributeSet; + +import androidx.appcompat.widget.AppCompatTextView; + +/** + * Describe:带渐变颜色的TextView + * Created by 吴天强 on 2019/7/1. + */ +public class GradientTextView extends AppCompatTextView { + + private Rect mTextBound = new Rect(); + private boolean gradient; + + public GradientTextView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @SuppressLint("DrawAllocation") + @Override + protected void onDraw(Canvas canvas) { + int mViewWidth = getMeasuredWidth(); + Paint mPaint = getPaint(); + String mTipText = getText().toString(); + mPaint.getTextBounds(mTipText, 0, mTipText.length(), mTextBound); + LinearGradient mLinearGradient; + if (gradient) { + mLinearGradient = new LinearGradient(0, 0, mViewWidth, 0, + new int[]{0xFF1A3AFF, 0xFF10E17D}, null, Shader.TileMode.REPEAT); + mPaint.setFakeBoldText(true); + } else { + mLinearGradient = new LinearGradient(0, 0, mViewWidth, 0, + new int[]{0xFF000000, 0xFF000000}, null, Shader.TileMode.REPEAT); + mPaint.setFakeBoldText(false); + } + mPaint.setShader(mLinearGradient); + canvas.drawText(mTipText, (getMeasuredWidth() >> 1) - (mTextBound.width() >> 1), (getMeasuredHeight() >> 1) + (mTextBound.height() >> 1), mPaint); + invalidate(); + } + + /** + * 设置是否渐变 + */ + public void setGradient(boolean gradient) { + this.gradient = gradient; + postInvalidate(); + } +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/widget/HinderWebView.java b/common_base/src/main/java/com/wss/common/widget/HinderWebView.java index 46bc9a9..fff0b94 100644 --- a/common_base/src/main/java/com/wss/common/widget/HinderWebView.java +++ b/common_base/src/main/java/com/wss/common/widget/HinderWebView.java @@ -34,7 +34,6 @@ public boolean onTouchEvent(MotionEvent ev) { case MotionEvent.ACTION_MOVE: float Y = ev.getY(); float Ys = Y - oldY; - //滑动到顶部让父控件重新获得触摸事件 if (Ys > 0 && t == 0) { getParent().getParent().requestDisallowInterceptTouchEvent(false); diff --git a/common_base/src/main/java/com/wss/common/widget/IconFontTextView.java b/common_base/src/main/java/com/wss/common/widget/IconFontTextView.java new file mode 100644 index 0000000..887a699 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/widget/IconFontTextView.java @@ -0,0 +1,94 @@ +package com.wss.common.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Typeface; +import android.util.AttributeSet; + +import com.wss.common.base.R; +import com.wss.common.utils.ValidUtils; + +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatTextView; + +/** + * Describe:使用ali IconFont的TextView + * Created by 吴天强 on 2019/7/9. + */ +public class IconFontTextView extends AppCompatTextView { + + private Context context; + private String fontFile = "iconfont/iconfont.ttf"; + private String defaultText;//默认文字 + private String checkedText;//选择之后文字 + + public IconFontTextView(Context context) { + this(context, null); + } + + public IconFontTextView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + this.context = context; + if (attrs != null) { + TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.IconFontTextView); + defaultText = a.getString(R.styleable.IconFontTextView_value); + checkedText = a.getString(R.styleable.IconFontTextView_valueChecked); + setFontFile(a.getString(R.styleable.IconFontTextView_fontFile)); + a.recycle(); + } + setTextState(); + setTypeFace(); + } + + @Override + public void setSelected(boolean selected) { + super.setSelected(selected); + setTextState(); + } + + /*** + * 设置显示Value + */ + public void setValue(String defaultText) { + this.defaultText = defaultText; + setTextState(); + } + + /*** + * 设置显示Value + * @param defaultText 默认显示 + * @param checkedText 选中显示 + */ + public void setValue(String defaultText, String checkedText) { + this.defaultText = defaultText; + this.checkedText = checkedText; + setTextState(); + } + + + /** + * 设置字体库 + */ + public void setFontFile(String typeFacePath) { + if (ValidUtils.isValid(typeFacePath)) { + fontFile = typeFacePath; + } + setTypeFace(); + } + + private void setTextState() { + if (ValidUtils.isValid(checkedText)) { + setText(isSelected() ? checkedText : defaultText); + } else { + setText(defaultText); + } + } + + private void setTypeFace() { + try { + Typeface typeface = Typeface.createFromAsset(context.getAssets(), fontFile); + setTypeface(typeface); + } catch (Throwable ignored) { + } + } +} diff --git a/common_base/src/main/java/com/wss/common/widget/LVCircularRing.java b/common_base/src/main/java/com/wss/common/widget/LVCircularRing.java index 41c84d3..f3184f2 100644 --- a/common_base/src/main/java/com/wss/common/widget/LVCircularRing.java +++ b/common_base/src/main/java/com/wss/common/widget/LVCircularRing.java @@ -16,11 +16,11 @@ import com.wss.common.base.R; + /** * 自定义加载框View - * Created by wtq on 2016/12/15. + * Created by 吴天强 on 2016/12/15. */ - public class LVCircularRing extends View { private float mWidth = 0f; private float mPadding = 0f; diff --git a/common_base/src/main/java/com/wss/common/widget/MultipleItemView.java b/common_base/src/main/java/com/wss/common/widget/MultipleItemView.java index e8adc19..1105b14 100644 --- a/common_base/src/main/java/com/wss/common/widget/MultipleItemView.java +++ b/common_base/src/main/java/com/wss/common/widget/MultipleItemView.java @@ -4,7 +4,6 @@ import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.drawable.Drawable; -import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.View; import android.widget.EditText; @@ -17,8 +16,12 @@ import com.wss.common.base.R2; import com.wss.common.utils.PxUtils; +import org.jetbrains.annotations.NotNull; + +import androidx.annotation.Nullable; import butterknife.BindView; import butterknife.ButterKnife; +import butterknife.OnClick; /** * Describe:多功能Item 支持左右文字显示 最右边图片显示 @@ -69,6 +72,8 @@ public class MultipleItemView extends LinearLayout { private boolean showRightIcon = true; private boolean showEditText = false; + private OnIconCheckChangedListener leftIconChangedListener, rightIconChangedListener; + public MultipleItemView(Context context) { this(context, null); } @@ -237,8 +242,7 @@ public MultipleItemView setRightTextSize(int size) { */ public MultipleItemView setLeftIconMargin(int left, int top, int right, int bottom) { LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) ivLeft.getLayoutParams(); - layoutParams.setMargins(PxUtils.dp2px(getContext(), left), PxUtils.dp2px(getContext(), top), - PxUtils.dp2px(getContext(), right), PxUtils.dp2px(getContext(), bottom)); + layoutParams.setMargins(PxUtils.dp2px(left), PxUtils.dp2px(top), PxUtils.dp2px(right), PxUtils.dp2px(bottom)); return this; } @@ -253,8 +257,8 @@ public MultipleItemView setLeftIconMargin(int left, int top, int right, int bott */ public MultipleItemView setRightIconMargin(int left, int top, int right, int bottom) { LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) ivRight.getLayoutParams(); - layoutParams.setMargins(PxUtils.dp2px(getContext(), left), PxUtils.dp2px(getContext(), top), - PxUtils.dp2px(getContext(), right), PxUtils.dp2px(getContext(), bottom)); + layoutParams.setMargins(PxUtils.dp2px(left), PxUtils.dp2px(top), + PxUtils.dp2px(right), PxUtils.dp2px(bottom)); return this; } @@ -289,8 +293,8 @@ public MultipleItemView setLeftIconResource(int resId) { * @return MultifunctionalItemView */ public MultipleItemView setLeftIconSize(int width, int height) { - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(PxUtils.dp2px(getContext(), width), - PxUtils.dp2px(getContext(), height)); + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(PxUtils.dp2px(width), + PxUtils.dp2px(height)); lp.setMargins(0, 0, 4, 0); ivLeft.setLayoutParams(lp); return this; @@ -327,8 +331,8 @@ public MultipleItemView setRightIconResource(int resId) { * @return MultifunctionalItemView */ public MultipleItemView setRightIconSize(int width, int height) { - ivRight.setLayoutParams(new LinearLayout.LayoutParams(PxUtils.dp2px(getContext(), width), - PxUtils.dp2px(getContext(), height))); + ivRight.setLayoutParams(new LinearLayout.LayoutParams(PxUtils.dp2px(width), + PxUtils.dp2px(height))); return this; } @@ -342,8 +346,58 @@ public MultipleItemView setRightIconSize(int width, int height) { * @return MultifunctionalItemView */ public MultipleItemView setContentPadding(int left, int top, int right, int bottom) { - content.setPadding(PxUtils.dp2px(getContext(), left), PxUtils.dp2px(getContext(), top), - PxUtils.dp2px(getContext(), right), PxUtils.dp2px(getContext(), bottom)); + content.setPadding(PxUtils.dp2px(left), PxUtils.dp2px(top), + PxUtils.dp2px(right), PxUtils.dp2px(bottom)); + return this; + } + + /** + * 设置右icon选择 + * + * @param checked 选择 + * @return this + */ + public MultipleItemView setRightIconChecked(boolean checked) { + ivRight.setSelected(checked); + if (leftIconChangedListener != null) { + leftIconChangedListener.onIconChanged(checked); + } + return this; + } + + /** + * 设置左icon选择 + * + * @param checked 选择 + * @return this + */ + public MultipleItemView setLeftIconChecked(boolean checked) { + ivRight.setSelected(checked); + if (rightIconChangedListener != null) { + rightIconChangedListener.onIconChanged(checked); + } + return this; + } + + /** + * 左侧按钮变化监听 + * + * @param iconChangedListener 监听器 + * @return this + */ + public MultipleItemView setLeftIconChangedListener(OnIconCheckChangedListener iconChangedListener) { + this.leftIconChangedListener = iconChangedListener; + return this; + } + + /** + * 右侧按钮变化监听 + * + * @param iconChangedListener 监听器 + * @return this + */ + public MultipleItemView setRightIconChangedListener(OnIconCheckChangedListener iconChangedListener) { + this.rightIconChangedListener = iconChangedListener; return this; } @@ -377,4 +431,32 @@ public MultipleItemView setRightView(View view) { public String getRightTex() { return edtText.getText().toString().trim(); } + + + @OnClick({R2.id.iv_left, R2.id.iv_right}) + public void onIconClick(@NotNull View view) { + view.setSelected(!view.isSelected()); + if (view.getId() == R.id.iv_left) { + if (leftIconChangedListener != null) { + leftIconChangedListener.onIconChanged(view.isSelected()); + } + } else if (view.getId() == R.id.iv_right) { + if (rightIconChangedListener != null) { + rightIconChangedListener.onIconChanged(view.isSelected()); + } + } + } + + + /** + * 左右按钮 选择状态变化 + */ + public interface OnIconCheckChangedListener { + /** + * 按钮选择状态变化 + * + * @param checked 选择状态 + */ + void onIconChanged(boolean checked); + } } diff --git a/common_base/src/main/java/com/wss/common/widget/NoScrollGridView.java b/common_base/src/main/java/com/wss/common/widget/NoScrollGridView.java new file mode 100644 index 0000000..4e64493 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/widget/NoScrollGridView.java @@ -0,0 +1,47 @@ +package com.wss.common.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.AdapterView; +import android.widget.GridView; + +import androidx.annotation.Nullable; + +/** + * 不可滑动的GridView + * + * @author 杨伟 + * create by 2020-4-27 + */ +public class NoScrollGridView extends GridView { + + public NoScrollGridView(Context context) { + super(context); + } + + public NoScrollGridView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public NoScrollGridView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * 设置GridView不可滑动 + * + * @param widthMeasureSpec + * @param heightMeasureSpec + */ + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, + MeasureSpec.AT_MOST); + super.onMeasure(widthMeasureSpec, expandSpec); + } + + @Override + public void setOnItemClickListener(@Nullable AdapterView.OnItemClickListener listener) { + super.setOnItemClickListener(listener); + } +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/widget/NoScrollListView.java b/common_base/src/main/java/com/wss/common/widget/NoScrollListView.java new file mode 100644 index 0000000..d695c64 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/widget/NoScrollListView.java @@ -0,0 +1,38 @@ +package com.wss.common.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.ListView; + +/** + * 不可滑动的ListView + * @author 杨伟 + * create by 2020-4-17 + */ +public class NoScrollListView extends ListView { + + public NoScrollListView(Context context) { + super(context); + } + + public NoScrollListView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public NoScrollListView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * 设置listView不可滑动 + * + * @param widthMeasureSpec + * @param heightMeasureSpec + */ + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, + MeasureSpec.AT_MOST); + super.onMeasure(widthMeasureSpec, expandSpec); + } +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/widget/NoScrollViewPager.java b/common_base/src/main/java/com/wss/common/widget/NoScrollViewPager.java index 7a36879..b1074c9 100644 --- a/common_base/src/main/java/com/wss/common/widget/NoScrollViewPager.java +++ b/common_base/src/main/java/com/wss/common/widget/NoScrollViewPager.java @@ -2,10 +2,11 @@ import android.annotation.SuppressLint; import android.content.Context; -import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.view.MotionEvent; +import androidx.viewpager.widget.ViewPager; + /** * Describe:可禁止滚动的ViewPager * Created by 吴天强 on 2018/11/1. diff --git a/common_base/src/main/java/com/wss/common/widget/NumberProgressBar.java b/common_base/src/main/java/com/wss/common/widget/NumberProgressBar.java index 89a56f3..2b1b74a 100644 --- a/common_base/src/main/java/com/wss/common/widget/NumberProgressBar.java +++ b/common_base/src/main/java/com/wss/common/widget/NumberProgressBar.java @@ -10,26 +10,31 @@ import android.graphics.RectF; import android.graphics.Typeface; import android.util.AttributeSet; -import android.util.TypedValue; import android.view.View; import com.wss.common.base.R; +import com.wss.common.utils.PxUtils; +/** + * Describe:数字进度条 + * Created by 吴天强 on 2018/11/1. + */ public class NumberProgressBar extends View { /** * 右侧未完成进度条的颜色 */ - private int paintStartColor = 0xffe5e5e5; + private static final int PAINT_START_COLOR = 0xffe5e5e5; /** - * Contxt + * context */ private Context context; /** + * l * 主线程传过来进程 0 - 100 */ private int progress; @@ -99,10 +104,10 @@ public NumberProgressBar(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; // 构造器中初始化数据 - smallR = dip2px(context, 4);//小圆半径 - bigR = dip2px(context, 8);//大圆半径 - radius = dip2px(context, 10) / 2;//进度条高度 - jR = dip2px(context, 6);//矩形 + smallR = PxUtils.dp2px(4);//小圆半径 + bigR = PxUtils.dp2px(8);//大圆半径 + radius = PxUtils.dp2px(10) / 2;//进度条高度 + jR = PxUtils.dp2px(6);//矩形 initData(); } @@ -113,15 +118,15 @@ public NumberProgressBar(Context context, AttributeSet attrs) { private void initData() { // 未完成进度条画笔的属性 - paintStart.setColor(paintStartColor); - paintStart.setStrokeWidth(dip2px(context, 1)); + paintStart.setColor(PAINT_START_COLOR); + paintStart.setStrokeWidth(PxUtils.dp2px(1)); paintStart.setDither(true); paintStart.setAntiAlias(true); paintStart.setStyle(Paint.Style.FILL); // 已完成进度条画笔的属性 - paintInit.setColor(context.getResources().getColor(R.color.blue)); - paintInit.setStrokeWidth(dip2px(context, 1)); + paintInit.setColor(context.getResources().getColor(R.color.theme)); + paintInit.setStrokeWidth(PxUtils.dp2px(1)); paintInit.setAntiAlias(true); paintInit.setDither(true); paintInit.setStyle(Paint.Style.FILL); @@ -133,14 +138,14 @@ private void initData() { paintSmall.setStyle(Paint.Style.FILL); // 大圆画笔 - paintEndBig.setColor(context.getResources().getColor(R.color.blue)); + paintEndBig.setColor(context.getResources().getColor(R.color.theme)); paintEndBig.setAntiAlias(true); paintEndBig.setStyle(Paint.Style.FILL); // 百分比文字画笔的属性 - int paintTextSizePx = sp2px(context, 11); //设置百分比文字的尺寸 - paintText.setColor(context.getResources().getColor(R.color.blue)); + int paintTextSizePx = PxUtils.sp2px(11); //设置百分比文字的尺寸 + paintText.setColor(context.getResources().getColor(R.color.theme)); paintText.setTextSize(paintTextSizePx); paintText.setAntiAlias(true); paintText.setTypeface(Typeface.DEFAULT_BOLD); @@ -212,14 +217,4 @@ public void setProgress(int progress) { this.progress = progress; invalidate(); } - - public static int dip2px(Context ctx, float dp) { - float density = ctx.getResources().getDisplayMetrics().density; - int px = (int) (dp * density + 0.5f); - return px; - } - - public static int sp2px(Context context, float spValue) { - return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spValue, context.getResources().getDisplayMetrics()); - } } \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/widget/ObserverButton.java b/common_base/src/main/java/com/wss/common/widget/ObserverButton.java index 64b9f47..34b165a 100644 --- a/common_base/src/main/java/com/wss/common/widget/ObserverButton.java +++ b/common_base/src/main/java/com/wss/common/widget/ObserverButton.java @@ -11,20 +11,21 @@ import com.wss.common.base.R; +import org.jetbrains.annotations.NotNull; + import java.util.ArrayList; import java.util.List; +import androidx.appcompat.widget.AppCompatTextView; + /** * Describe:观察多个输入框的Button * Created by 吴天强 on 2018/10/26. */ - -public class ObserverButton extends android.support.v7.widget.AppCompatTextView { - +public class ObserverButton extends AppCompatTextView { private List editTextList = new ArrayList<>(); - private boolean canPress; private int defaultBg = Color.GRAY; private int pressBg = Color.BLUE; @@ -55,7 +56,7 @@ public ObserverButton(Context context, AttributeSet attrs, int defStyleAttr) { } - public void observer(EditText... editTexts) { + public void observer(@NotNull EditText... editTexts) { for (EditText editText : editTexts) { editText.addTextChangedListener(textWatcher); editTextList.add(editText); diff --git a/common_base/src/main/java/com/wss/common/widget/PagerSlidingTabStrip.java b/common_base/src/main/java/com/wss/common/widget/PagerSlidingTabStrip.java index 96a6528..fcb9632 100644 --- a/common_base/src/main/java/com/wss/common/widget/PagerSlidingTabStrip.java +++ b/common_base/src/main/java/com/wss/common/widget/PagerSlidingTabStrip.java @@ -1,17 +1,13 @@ package com.wss.common.widget; -import android.annotation.SuppressLint; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Typeface; -import android.os.Build; import android.os.Parcel; import android.os.Parcelable; -import android.support.v4.view.ViewPager; -import android.support.v4.view.ViewPager.OnPageChangeListener; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.TypedValue; @@ -25,23 +21,22 @@ import android.widget.TextView; import com.wss.common.base.R; +import com.wss.common.utils.PxUtils; + +import org.jetbrains.annotations.NotNull; import java.util.Locale; +import androidx.viewpager.widget.ViewPager; + /** * 水平滑动TabView * wtq 2016年6月28日14:09:46 */ public class PagerSlidingTabStrip extends HorizontalScrollView { - private static final String TAG = PagerSlidingTabStrip.class.getSimpleName(); - - public interface IconTabProvider { - int getPageIconResId(int position); - } - private final PageListener pageListener = new PageListener(); - public OnPageChangeListener delegatePageListener; + public ViewPager.OnPageChangeListener delegatePageListener; private LinearLayout tabsContainer; private ViewPager pager; @@ -54,23 +49,57 @@ public interface IconTabProvider { private Paint rectPaint; private Paint dividerPaint; - private int indicatorColor = 0XFFFF7F00;//指示器颜色 - private int underlineColor = 0XFFB9B9B9;//上下横向颜色 - private int dividerColor = 0X00FF7F00;//水平分割线颜色 - private int textDefaultColor = 0XFF999999;//标题默认颜色 - private int textSelectColor = indicatorColor;//标题选中颜色 + /** + * 指示器颜色 + */ + private int indicatorColor = 0XFFFF7F00; + /** + * 上下横向颜色 + */ + private int underlineColor = 0XFFB9B9B9; + /** + * 水平分割线颜色 + */ + private int dividerColor = 0X00FF7F00; + /** + * 标题默认颜色 + */ + private int textDefaultColor = 0XFF999999; + /** + * 标题选中颜色 + */ + private int textSelectColor = indicatorColor; - private boolean shouldExpand = true;//tab是否平均分配在屏幕上 + /** + * tab是否平均分配在屏幕上 + */ + private boolean shouldExpand = true; + /** + * 文字是否大写 + */ private boolean textAllCaps = true; - private boolean bold = false;//是否加粗 - private boolean topLine = true;//是否显示顶部横向 - private boolean bottomLine = true;//是否显示底部横向 + /** + * 文字是否加粗 + */ + private boolean bold = false; + /** + * 是否显示顶部横向 + */ + private boolean topLine = true; + /** + * 是否显示底部横向 + */ + private boolean bottomLine = true; private int scrollOffset = 52; private int indicatorHeight = 4; private float underlineHeight = 0.5f; private int dividerPadding = 12; - private int tabPadding = 17; + /** + * Tab左右边距 + */ + private int tabPaddingLeft = 0; + private int tabPaddingRight = 0; private int dividerWidth = 1; private int redDotTop = 15; private int redDotWidth = 20; @@ -87,8 +116,7 @@ public PagerSlidingTabStrip(Context context, AttributeSet attrs) { this(context, attrs, 0); } - public PagerSlidingTabStrip(Context context, AttributeSet attrs, - int defStyle) { + public PagerSlidingTabStrip(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); setFillViewport(true); @@ -96,77 +124,42 @@ public PagerSlidingTabStrip(Context context, AttributeSet attrs, tabsContainer = new LinearLayout(context); tabsContainer.setOrientation(LinearLayout.HORIZONTAL); - tabsContainer.setLayoutParams(new LayoutParams( - LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + tabsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); addView(tabsContainer); + //把一些DP SP的值做一个转换 DisplayMetrics dm = getResources().getDisplayMetrics(); - - scrollOffset = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, scrollOffset, dm); - indicatorHeight = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, indicatorHeight, dm); - underlineHeight = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, underlineHeight, dm); - dividerPadding = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, dividerPadding, dm); - tabPadding = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, tabPadding, dm); - dividerWidth = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, dividerWidth, dm); - tabTextSize = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_SP, tabTextSize, dm); - redDotTop = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, redDotTop, dm); - redDotWidth = (int) TypedValue.applyDimension( - TypedValue.COMPLEX_UNIT_DIP, redDotWidth, dm); + scrollOffset = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, scrollOffset, dm); + indicatorHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, indicatorHeight, dm); + underlineHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, underlineHeight, dm); + dividerPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dividerPadding, dm); + dividerWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dividerWidth, dm); + tabTextSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, tabTextSize, dm); + redDotTop = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, redDotTop, dm); + redDotWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, redDotWidth, dm); + tabPaddingLeft = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, tabPaddingLeft, dm); + tabPaddingRight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, tabPaddingRight, dm); + + //获取自定义属性值 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PagerSlidingTabStrip); - - indicatorColor = a.getColor( - R.styleable.PagerSlidingTabStrip_pstsIndicatorColor, - indicatorColor); - textSelectColor = a.getColor( - R.styleable.PagerSlidingTabStrip_pstsTextSelectedColor, - textSelectColor); - textDefaultColor = a.getColor( - R.styleable.PagerSlidingTabStrip_pstsTextDefaultColor, - textDefaultColor); - underlineColor = a.getColor( - R.styleable.PagerSlidingTabStrip_pstsUnderlineColor, - underlineColor); - tabTextSize = a.getDimensionPixelSize( - R.styleable.PagerSlidingTabStrip_pstsTextSize, tabTextSize); - - dividerColor = a - .getColor(R.styleable.PagerSlidingTabStrip_pstsDividerColor, - dividerColor); - indicatorHeight = a.getDimensionPixelSize( - R.styleable.PagerSlidingTabStrip_pstsIndicatorHeight, - indicatorHeight); - bold = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsBold, - bold); - topLine = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsHasTopLine, - topLine); - bottomLine = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsHasBottomLine, - bottomLine); - dividerPadding = a.getDimensionPixelSize( - R.styleable.PagerSlidingTabStrip_pstsDividerPadding, - dividerPadding); - tabPadding = a.getDimensionPixelSize( - R.styleable.PagerSlidingTabStrip_pstsTabPaddingLeftRight, - tabPadding); - tabPadding = a.getDimensionPixelSize( - R.styleable.PagerSlidingTabStrip_pstsTextSize, tabPadding); - - shouldExpand = a - .getBoolean(R.styleable.PagerSlidingTabStrip_pstsShouldExpand, - shouldExpand); - scrollOffset = a - .getDimensionPixelSize( - R.styleable.PagerSlidingTabStrip_pstsScrollOffset, - scrollOffset); - textAllCaps = a.getBoolean( - R.styleable.PagerSlidingTabStrip_pstsTextAllCaps, textAllCaps); + indicatorColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsIndicatorColor, indicatorColor); + textSelectColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsTextSelectedColor, textSelectColor); + textDefaultColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsTextDefaultColor, textDefaultColor); + underlineColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsUnderlineColor, underlineColor); + tabTextSize = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsTextSize, tabTextSize); + + dividerColor = a.getColor(R.styleable.PagerSlidingTabStrip_pstsDividerColor, dividerColor); + indicatorHeight = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsIndicatorHeight, indicatorHeight); + bold = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsBold, bold); + topLine = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsHasTopLine, topLine); + bottomLine = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsHasBottomLine, bottomLine); + dividerPadding = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsDividerPadding, dividerPadding); + tabPaddingLeft = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsTabPaddingLeft, tabPaddingLeft); + tabPaddingRight = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsTabPaddingRight, tabPaddingRight); + + shouldExpand = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsShouldExpand, shouldExpand); + scrollOffset = a.getDimensionPixelSize(R.styleable.PagerSlidingTabStrip_pstsScrollOffset, scrollOffset); + textAllCaps = a.getBoolean(R.styleable.PagerSlidingTabStrip_pstsTextAllCaps, textAllCaps); a.recycle(); @@ -183,60 +176,29 @@ public PagerSlidingTabStrip(Context context, AttributeSet attrs, } } - - public void setViewPager(ViewPager pager) { - this.pager = pager; - + /** + * 更新页面 + */ + private void notifyDataSetChanged() { if (pager.getAdapter() == null) { - throw new IllegalStateException( - "ViewPager does not have adapter instance."); + throw new IllegalStateException("ViewPager does not have adapter instance."); } - - pager.addOnPageChangeListener(pageListener); - notifyDataSetChanged(); - } - - public void setOnPageChangeListener(OnPageChangeListener listener) { - this.delegatePageListener = listener; - } - - public void notifyDataSetChanged() { - tabsContainer.removeAllViews(); - tabCount = pager.getAdapter().getCount(); - for (int i = 0; i < tabCount; i++) { - if (pager.getAdapter() instanceof IconTabProvider) { - addIconTab(i, - ((IconTabProvider) pager.getAdapter()) - .getPageIconResId(i)); + addIconTab(i, ((IconTabProvider) pager.getAdapter()).getPageIconResId(i)); } else { - String title = pager.getAdapter().getPageTitle(i).toString(); + String title = String.valueOf(pager.getAdapter().getPageTitle(i)); addTextTab(i, title); } - } - updateTabStyles(); - getViewTreeObserver().addOnGlobalLayoutListener( new OnGlobalLayoutListener() { - - @SuppressWarnings("deprecation") - @SuppressLint("NewApi") @Override public void onGlobalLayout() { - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { - getViewTreeObserver().removeGlobalOnLayoutListener( - this); - } else { - getViewTreeObserver().removeOnGlobalLayoutListener( - this); - } - + getViewTreeObserver().removeOnGlobalLayoutListener(this); currentPosition = pager.getCurrentItem(); scrollToChild(currentPosition, 0); } @@ -244,79 +206,76 @@ public void onGlobalLayout() { } + /** + * 添加文本Tab + * + * @param position 位置 + * @param title tab显示文字 + */ private void addTextTab(final int position, String title) { - - TextView tab = new TextView(getContext()); - tab.setText(title); - tab.setGravity(Gravity.CENTER); - tab.setSingleLine(); + TextView tvTab = new TextView(getContext()); + tvTab.setText(title); + tvTab.setGravity(Gravity.CENTER); + tvTab.setSingleLine(); if (position != 0) { - tab.setTextColor(textDefaultColor); - tab.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL)); + tvTab.setTextColor(textDefaultColor); + tvTab.setTypeface(Typeface.defaultFromStyle(Typeface.NORMAL)); } else { if (bold) { - tab.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); + tvTab.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); } - tab.setTextColor(textSelectColor); + tvTab.setTextColor(textSelectColor); } - - addTab(position, tab); + addTab(position, tvTab); } + /** + * 添加IconTab + * + * @param position position + * @param resId icon资源 + */ private void addIconTab(final int position, int resId) { - ImageButton tab = new ImageButton(getContext()); tab.setImageResource(resId); - addTab(position, tab); } - private void addTab(final int position, View tab) { - tab.setFocusable(true); - tab.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (onPagerTabClick != null) { - onPagerTabClick.onClick(position); - } - pager.setCurrentItem(position); + /** + * 添加Tab + * + * @param position 位置 + * @param tabView tab + */ + private void addTab(int position, @NotNull View tabView) { + tabView.setFocusable(true); + tabView.setOnClickListener(v -> { + if (onPagerTabClick != null) { + onPagerTabClick.onClick(position); } + pager.setCurrentItem(position); }); - tab.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, - LayoutParams.MATCH_PARENT)); - + tabView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); LinearLayout linearLayout = new LinearLayout(getContext()); if (shouldExpand) { - linearLayout.setLayoutParams(new LinearLayout.LayoutParams(0, - LayoutParams.MATCH_PARENT, 1.0f)); + linearLayout.setLayoutParams(new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f)); } else { - linearLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, - LayoutParams.MATCH_PARENT)); + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); + lp.setMargins(0, 0, PxUtils.dp2px(20), 0); + linearLayout.setLayoutParams(lp); } - - linearLayout.setLayoutParams(new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1.0f)); - linearLayout.setPadding(tabPadding, 0, tabPadding, 0); + linearLayout.setPadding(tabPaddingLeft, 0, tabPaddingRight, 0); linearLayout.setGravity(Gravity.CENTER); -// ImageView view = new ImageView(getContext()); -// view.setLayoutParams(new LayoutParams(redDotWidth, redDotWidth)); -// view.setPadding(0, redDotTop, 0, 0); -// view.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.red)); -// view.setVisibility(View.GONE); - linearLayout.addView(tab); -// linearLayout.addView(view); + linearLayout.addView(tabView); tabsContainer.addView(linearLayout); } private void updateTabStyles() { - for (int i = 0; i < tabCount; i++) { - View v = ((ViewGroup) tabsContainer.getChildAt(i)).getChildAt(0); - if (v instanceof TextView) { - TextView tab = (TextView) v; if (i != 0) { tab.setTextColor(textDefaultColor); @@ -328,7 +287,6 @@ private void updateTabStyles() { tab.setTextColor(textSelectColor); } tab.setTextSize(TypedValue.COMPLEX_UNIT_PX, tabTextSize); - tab.setAllCaps(textAllCaps); } } @@ -414,18 +372,17 @@ protected void onDraw(Canvas canvas) { } } - private class PageListener implements OnPageChangeListener { + private class PageListener implements ViewPager.OnPageChangeListener { @Override - public void onPageScrolled(int position, float positionOffset, - int positionOffsetPixels) { + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { currentPosition = position; currentPositionOffset = positionOffset; - if (tabsContainer.getChildAt(position) != null) - scrollToChild(position, (int) (positionOffset * tabsContainer - .getChildAt(position).getWidth())); + if (tabsContainer.getChildAt(position) != null) { + scrollToChild(position, (int) (positionOffset * tabsContainer.getChildAt(position).getWidth())); + } invalidate(); @@ -507,7 +464,7 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeInt(currentPosition); } - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public static final Creator CREATOR = new Creator() { @Override public SavedState createFromParcel(Parcel in) { return new SavedState(in); @@ -547,6 +504,25 @@ public void showPosition(int position) { viewGroup.getChildAt(1).setVisibility(View.VISIBLE); } } + /** + * 添加ViewPager + * + * @param pager ViewPager + */ + public void setViewPager(@NotNull ViewPager pager) { + this.pager = pager; + pager.addOnPageChangeListener(pageListener); + notifyDataSetChanged(); + } + + /** + * 设置ViewPager滑动监听 + * + * @param listener 监听器 + */ + public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) { + this.delegatePageListener = listener; + } /** * 下方滑动指示器颜色 @@ -687,9 +663,13 @@ public void setTextSelectColorResource(int resId) { /** * 设置item左右padding + * + * @param leftPadding 左边距 + * @param rightPadding 右边距 */ - public void setTabPaddingLeftRight(int paddingPx) { - this.tabPadding = paddingPx; + public void setTabPadding(int leftPadding, int rightPadding) { + this.tabPaddingLeft = leftPadding; + this.tabPaddingRight = rightPadding; updateTabStyles(); } @@ -709,5 +689,17 @@ public void setShowTopLine(boolean show) { invalidate(); } + /** + * IconTab 提供则 + */ + public interface IconTabProvider { + /** + * 返回Icon资源ID + * + * @param position position + * @return icon资源图片 + */ + int getPageIconResId(int position); + } } diff --git a/common_base/src/main/java/com/wss/common/widget/ProgressWebView.java b/common_base/src/main/java/com/wss/common/widget/ProgressWebView.java deleted file mode 100644 index f2bf3f6..0000000 --- a/common_base/src/main/java/com/wss/common/widget/ProgressWebView.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.wss.common.widget; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.os.Build; -import android.os.Handler; -import android.support.annotation.RequiresApi; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.view.View; -import android.view.ViewGroup; -import android.webkit.WebChromeClient; -import android.webkit.WebSettings; -import android.webkit.WebView; - -import com.wss.common.widget.dialog.LoadingDialog; - - -/** - * 带进度条的WebView - * wtq 2016年6月28日14:09:46 - */ -public class ProgressWebView extends WebView { - private WebViewProgressBar progressBar; - private Handler handler; - private WebView _this; - private LoadingDialog loadingDialog; - - @SuppressLint("SetJavaScriptEnabled") - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - public ProgressWebView(Context context, AttributeSet attrs) { - super(context, attrs); - progressBar = new WebViewProgressBar(context); - progressBar.setLayoutParams(new ViewGroup.LayoutParams - (ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - progressBar.setVisibility(GONE); - addView(progressBar); - handler = new Handler(); - _this = this; - loadingDialog = new LoadingDialog(context); - loadingDialog.setCancelable(true); - - setWebChromeClient(new MyWebChromeClient()); -// setWebViewClient(new MyWebClient()); - - /** - * Webview在安卓5.0之前默认允许其加载混合网络协议内容 - * 在安卓5.0之后,默认不允许加载http与https混合内容,需要设置webview允许其加载混合网络协议内容 - */ - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); - - } - - /** 设置webView不显示图片问题 */ - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { - getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); - } - getSettings().setJavaScriptEnabled(true); - getSettings().setBlockNetworkImage(false); - - } - - public void showDialog(String text) { - if (!TextUtils.isEmpty(text)) { - loadingDialog.setTitleText("正在加载···"); - } - loadingDialog.show(); - } - - private class MyWebChromeClient extends WebChromeClient { - @Override - public void onProgressChanged(WebView view, int newProgress) { - if (newProgress == 100) { - progressBar.setProgress(100); - handler.postDelayed(runnable, 200); - } else if (progressBar.getVisibility() == GONE) { - progressBar.setVisibility(VISIBLE); - } - if (newProgress < 5) { - newProgress = 5; - } - progressBar.setProgress(newProgress); - super.onProgressChanged(view, newProgress); - } - } - - - - - private Runnable runnable = new Runnable() { - @Override - public void run() { - dismissDialog(); - } - }; - - /** - * 关闭加载框 - */ - public void dismissDialog() { - if (loadingDialog.isShowing()) { - loadingDialog.dismiss(); - } - progressBar.setVisibility(View.GONE); - } - -} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/widget/SlideBarView.java b/common_base/src/main/java/com/wss/common/widget/SlideBarView.java new file mode 100644 index 0000000..93c3385 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/widget/SlideBarView.java @@ -0,0 +1,128 @@ +package com.wss.common.widget; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +import com.wss.common.utils.PxUtils; + +/** + * Describe:选择城市右边的字母栏,可以滚动选择开头字母 + * Created by 吴天强 on 2018/11/1. + */ +public class SlideBarView extends View { + + + public static final char[] SPECIAL_CHAR_INDEX = {'#', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; + + private char[] indexs = SPECIAL_CHAR_INDEX; + + Paint mPaint = null; + + public interface OnSlideBarBaseViewFlipListener { + + void onFlip(int index, String mChar); + + void onFlipUp(); + } + + private OnSlideBarBaseViewFlipListener flipListener = null; + + /** + * Set SlideBar OnFlip Listener + */ + public void setFlipListener(OnSlideBarBaseViewFlipListener mListener) { + this.flipListener = mListener; + } + + public SlideBarView(Context context) { + super(context); + init(); + } + + public SlideBarView(Context context, AttributeSet attrs, + int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + public SlideBarView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + mPaint = new Paint(); + mPaint.setTextSize(PxUtils.dp2px(14)); + mPaint.setTextAlign(Paint.Align.CENTER); + mPaint.setColor(Color.parseColor("#FF333333")); + mPaint.setTypeface(Typeface.DEFAULT_BOLD); + mPaint.setAntiAlias(true); + } + + /** + * 設置索引 + */ + public void setIndexs(char[] wantedIndexs) { + this.indexs = wantedIndexs; + invalidate(); + } + + public void setTextColor(int color) { + mPaint.setColor(color); + } + + @Override + protected void onDraw(Canvas canvas) { + //均分 + int itemHeight = getHeight() / SPECIAL_CHAR_INDEX.length; + //计算从哪一个开始 + float startHeight = 0.0f; + if (indexs.length <= SPECIAL_CHAR_INDEX.length) { + startHeight = ((SPECIAL_CHAR_INDEX.length - indexs.length) >> 1) * itemHeight; + } + for (int i = 0; i < indexs.length; i++) { + float xPos = getWidth() >> 1; + float yPos; + if (startHeight == 0) { + //数目超过既定最大数 使用另一种算法 + yPos = (getHeight() >> indexs.length) * i + getHeight() >> indexs.length; + } else { + yPos = startHeight + itemHeight * i; + } + canvas.drawText(String.valueOf(indexs[i]), xPos, yPos, mPaint); + } + super.onDraw(canvas); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + float touchY = event.getY(); + float everyHeight = ((float) getHeight() / indexs.length); + int touchId = (int) (touchY / everyHeight); + if (touchId < 0) { + touchId = 0; + } + if (touchId > indexs.length - 1) { + touchId = indexs.length - 1; + } + if (event.getAction() == MotionEvent.ACTION_DOWN + || event.getAction() == MotionEvent.ACTION_MOVE) { + if (this.flipListener != null) { + this.flipListener.onFlip(touchId, String.valueOf(indexs[touchId])); + } + } else { + if (this.flipListener != null) { + this.flipListener.onFlipUp(); + } + } + return true; + } +} diff --git a/common_base/src/main/java/com/wss/common/widget/SlideLayout.java b/common_base/src/main/java/com/wss/common/widget/SlideLayout.java index aa61dee..7f8fefe 100644 --- a/common_base/src/main/java/com/wss/common/widget/SlideLayout.java +++ b/common_base/src/main/java/com/wss/common/widget/SlideLayout.java @@ -7,8 +7,6 @@ import android.content.res.TypedArray; import android.os.Parcel; import android.os.Parcelable; -import android.support.v4.view.MotionEventCompat; -import android.support.v4.view.ViewCompat; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; @@ -21,6 +19,9 @@ import com.wss.common.base.R; +import androidx.core.view.MotionEventCompat; +import androidx.core.view.ViewCompat; + /** * Describe:分页滑动Layout 如:商品详情页 滑动查看图文详情 @@ -580,10 +581,13 @@ public void writeToParcel(Parcel out, int flags) { public static final Creator CREATOR = new Creator() { + + @Override public SavedState createFromParcel(Parcel in) { return new SavedState(in); } + @Override public SavedState[] newArray(int size) { return new SavedState[size]; } diff --git a/common_base/src/main/java/com/wss/common/widget/StickyNavLayout.java b/common_base/src/main/java/com/wss/common/widget/StickyNavLayout.java new file mode 100644 index 0000000..257c526 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/widget/StickyNavLayout.java @@ -0,0 +1,394 @@ +package com.wss.common.widget; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; + +import java.util.ArrayList; +import java.util.List; + +import androidx.core.widget.NestedScrollView; + +/** + * Describe:滑动粘性ScrollView,设置View的tag = sticky 滑动可吸顶 + * Created by 吴天强 on 2020/05/13. + * Copy from: https://github.com/LidongWen/MultiTypeAdapter + */ +public class StickyNavLayout extends NestedScrollView { + + public interface OnViewStickyListener { + + void onSticky(View view); + + void onUnSticky(View view); + } + + /** + * Tag for views that should stick and have constant drawing. e.g. TextViews, ImageViews etc + */ + public static final String STICKY_TAG = "sticky"; + /** + * Flag for views that should stick and have non-constant drawing. e.g. Buttons, ProgressBars etc + */ + public static final String FLAG_NONCONSTANT = "-nonconstant"; + /** + * Flag for views that have aren't fully opaque + */ + public static final String FLAG_HASTRANSPARENCY = "-hastransparency"; + /** + * Default height of the shadow peeking out below the stuck view. + */ + private static final int DEFAULT_SHADOW_HEIGHT = 10; // dp; + private ArrayList stickyViews; + private View currentlyStickingView; + private float stickyViewTopOffset; + private final Runnable invalidateRunnable = new Runnable() { + @Override + public void run() { + if (currentlyStickingView != null) { + int l = getLeftForViewRelativeOnlyChild(currentlyStickingView); + int t = getBottomForViewRelativeOnlyChild(currentlyStickingView); + int r = getRightForViewRelativeOnlyChild(currentlyStickingView); + int b = (int) (getScrollY() + (currentlyStickingView.getHeight() + stickyViewTopOffset)); + invalidate(l, t, r, b); + } + postDelayed(this, 16); + } + }; + private int stickyViewLeftOffset; + private boolean redirectTouchesToStickyView; + private boolean clippingToPadding; + private boolean clipToPaddingHasBeenSet; + private int mShadowHeight = DEFAULT_SHADOW_HEIGHT; + private Drawable mShadowDrawable; + private boolean hasNotDoneActionDown = true; + + private List mOnViewStickyListeners; + + public StickyNavLayout(Context context) { + this(context, null); + } + + public StickyNavLayout(Context context, AttributeSet attrs) { + this(context, attrs, android.R.attr.scrollViewStyle); + } + + public StickyNavLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + setup(); + } + + public void addOnViewStickyListener(OnViewStickyListener stickyListener) { + if (mOnViewStickyListeners == null) + mOnViewStickyListeners = new ArrayList<>(); + mOnViewStickyListeners.add(stickyListener); + } + + public void removeOnViewStickyListener(OnViewStickyListener stickyListener) { + if (mOnViewStickyListeners != null) + mOnViewStickyListeners.remove(stickyListener); + } + + public void clearOnViewStickyListener() { + if (mOnViewStickyListeners != null) + mOnViewStickyListeners.clear(); + } + + public void setShadowHeight(int height) { + mShadowHeight = height; + } + + public void setShadowDrawable(Drawable shadowDrawable) { + mShadowDrawable = shadowDrawable; + } + + public void setup() { + stickyViews = new ArrayList<>(); + } + + private int getLeftForViewRelativeOnlyChild(View v) { + int left = v.getLeft(); + while (v.getParent() != null && v.getParent() != getChildAt(0)) { + v = (View) v.getParent(); + left += v.getLeft(); + } + return left; + } + + private int getTopForViewRelativeOnlyChild(View v) { + int top = v.getTop(); + while (v.getParent() != null && v.getParent() != getChildAt(0)) { + v = (View) v.getParent(); + top += v.getTop(); + } + return top; + } + + private int getRightForViewRelativeOnlyChild(View v) { + int right = v.getRight(); + while (v.getParent() != null && v.getParent() != getChildAt(0)) { + v = (View) v.getParent(); + right += v.getRight(); + } + return right; + } + + private int getBottomForViewRelativeOnlyChild(View v) { + int bottom = v.getBottom(); + while (v.getParent() != null && v.getParent() != getChildAt(0)) { + v = (View) v.getParent(); + bottom += v.getBottom(); + } + return bottom; + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + if (!clipToPaddingHasBeenSet) { + clippingToPadding = true; + } + notifyHierarchyChanged(); + } + + @Override + public void setClipToPadding(boolean clipToPadding) { + super.setClipToPadding(clipToPadding); + clippingToPadding = clipToPadding; + clipToPaddingHasBeenSet = true; + } + + @Override + public void addView(View child) { + super.addView(child); + findStickyViews(child); + } + + @Override + public void addView(View child, int index) { + super.addView(child, index); + findStickyViews(child); + } + + @Override + public void addView(View child, int index, ViewGroup.LayoutParams params) { + super.addView(child, index, params); + findStickyViews(child); + } + + @Override + public void addView(View child, int width, int height) { + super.addView(child, width, height); + findStickyViews(child); + } + + @Override + public void addView(View child, ViewGroup.LayoutParams params) { + super.addView(child, params); + findStickyViews(child); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + if (currentlyStickingView != null) { + canvas.save(); + canvas.translate(getPaddingLeft() + stickyViewLeftOffset, getScrollY() + + stickyViewTopOffset + (clippingToPadding ? getPaddingTop() : 0)); + canvas.clipRect(0, (clippingToPadding ? -stickyViewTopOffset : 0), + getWidth() - stickyViewLeftOffset, + currentlyStickingView.getHeight() + mShadowHeight + 1); + if (mShadowDrawable != null) { + int left = 0; + int top = currentlyStickingView.getHeight(); + int right = currentlyStickingView.getWidth(); + int bottom = currentlyStickingView.getHeight() + mShadowHeight; + mShadowDrawable.setBounds(left, top, right, bottom); + mShadowDrawable.draw(canvas); + } + canvas.clipRect(0, (clippingToPadding ? -stickyViewTopOffset : 0), getWidth(), + currentlyStickingView.getHeight()); + if (getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARENCY)) { + showView(currentlyStickingView); + currentlyStickingView.draw(canvas); + hideView(currentlyStickingView); + } else { + currentlyStickingView.draw(canvas); + } + canvas.restore(); + } + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + redirectTouchesToStickyView = true; + } + if (redirectTouchesToStickyView) { + redirectTouchesToStickyView = currentlyStickingView != null; + if (redirectTouchesToStickyView) { + redirectTouchesToStickyView = + ev.getY() <= (currentlyStickingView.getHeight() + stickyViewTopOffset) && + ev.getX() >= getLeftForViewRelativeOnlyChild(currentlyStickingView) && + ev.getX() <= getRightForViewRelativeOnlyChild(currentlyStickingView); + } + } else if (currentlyStickingView == null) { + redirectTouchesToStickyView = false; + } + if (redirectTouchesToStickyView) { + ev.offsetLocation(0, -1 * ((getScrollY() + stickyViewTopOffset) + - getTopForViewRelativeOnlyChild(currentlyStickingView))); + } + return super.dispatchTouchEvent(ev); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (redirectTouchesToStickyView) { + ev.offsetLocation(0, ((getScrollY() + stickyViewTopOffset) + - getTopForViewRelativeOnlyChild(currentlyStickingView))); + } + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + hasNotDoneActionDown = false; + } + if (hasNotDoneActionDown) { + MotionEvent down = MotionEvent.obtain(ev); + down.setAction(MotionEvent.ACTION_DOWN); + super.onTouchEvent(down); + hasNotDoneActionDown = false; + } + if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) { + hasNotDoneActionDown = true; + } + return super.onTouchEvent(ev); + } + + @Override + protected void onScrollChanged(int l, int t, int oldl, int oldt) { + super.onScrollChanged(l, t, oldl, oldt); + doTheStickyThing(); + } + + private void doTheStickyThing() { + View viewThatShouldStick = null; + View approachingView = null; + for (View v : stickyViews) { + int viewTop = getTopForViewRelativeOnlyChild(v) - getScrollY() + + (clippingToPadding ? 0 : getPaddingTop()); + if (viewTop <= 0) { + if (viewThatShouldStick == null || viewTop > + (getTopForViewRelativeOnlyChild(viewThatShouldStick) + - getScrollY() + (clippingToPadding ? 0 : getPaddingTop()))) { + viewThatShouldStick = v; + } + } else { + if (approachingView == null || viewTop < (getTopForViewRelativeOnlyChild(approachingView) + - getScrollY() + (clippingToPadding ? 0 : getPaddingTop()))) { + approachingView = v; + } + } + } + if (viewThatShouldStick != null) { + stickyViewTopOffset = approachingView == null ? 0 : + Math.min(0, getTopForViewRelativeOnlyChild(approachingView) - getScrollY() + + (clippingToPadding ? 0 : getPaddingTop()) - viewThatShouldStick.getHeight()); + if (viewThatShouldStick != currentlyStickingView) { + if (currentlyStickingView != null) { + if (mOnViewStickyListeners != null) + for (OnViewStickyListener onViewStickyListener : mOnViewStickyListeners) + onViewStickyListener.onUnSticky(currentlyStickingView); + stopStickingCurrentlyStickingView(); + } + // only compute the x offset when we start sticking. + stickyViewLeftOffset = getLeftForViewRelativeOnlyChild(viewThatShouldStick); + startStickingView(viewThatShouldStick); + if (mOnViewStickyListeners != null) + for (OnViewStickyListener onViewStickyListener : mOnViewStickyListeners) + onViewStickyListener.onSticky(currentlyStickingView); + } + } else if (currentlyStickingView != null) { + if (mOnViewStickyListeners != null) + for (OnViewStickyListener onViewStickyListener : mOnViewStickyListeners) + onViewStickyListener.onUnSticky(currentlyStickingView); + stopStickingCurrentlyStickingView(); + } + } + + private void startStickingView(View viewThatShouldStick) { + currentlyStickingView = viewThatShouldStick; + if (currentlyStickingView != null) { + if (getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARENCY)) { + hideView(currentlyStickingView); + } + if (getStringTagForView(currentlyStickingView).contains(FLAG_NONCONSTANT)) { + post(invalidateRunnable); + } + } + } + + private void stopStickingCurrentlyStickingView() { + if (getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARENCY)) { + showView(currentlyStickingView); + } + currentlyStickingView = null; + removeCallbacks(invalidateRunnable); + } + + @Override + protected void onDetachedFromWindow() { + removeCallbacks(invalidateRunnable); + super.onDetachedFromWindow(); + } + + /** + * Notify that the sticky attribute has been added or removed from one or more views in the View hierarchy + */ + public void notifyStickyAttributeChanged() { + notifyHierarchyChanged(); + } + + private void notifyHierarchyChanged() { + if (currentlyStickingView != null) { + stopStickingCurrentlyStickingView(); + } + stickyViews.clear(); + findStickyViews(getChildAt(0)); + doTheStickyThing(); + invalidate(); + } + + private void findStickyViews(View v) { + if (!detainStickyView(v) && (v instanceof ViewGroup)) { + ViewGroup vg = (ViewGroup) v; + for (int i = 0; i < vg.getChildCount(); i++) + findStickyViews(vg.getChildAt(i)); + } + } + + private boolean detainStickyView(View view) { + String tag = getStringTagForView(view); + if (tag.contains(STICKY_TAG)) { + stickyViews.add(view); + return true; + } + return false; + } + + private String getStringTagForView(View v) { + Object tagObject = v.getTag(); + return String.valueOf(tagObject); + } + + private void hideView(View v) { + v.setAlpha(0); + } + + private void showView(View v) { + v.setAlpha(1); + } + +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/widget/StrongRadioGroup.java b/common_base/src/main/java/com/wss/common/widget/StrongRadioGroup.java new file mode 100644 index 0000000..226a45f --- /dev/null +++ b/common_base/src/main/java/com/wss/common/widget/StrongRadioGroup.java @@ -0,0 +1,377 @@ +package com.wss.common.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CompoundButton; +import android.widget.LinearLayout; +import android.widget.RadioButton; + + +/** + * Describe:可添加任意ViewGroup的RadioGroup + * Created by 吴天强 on 2019/3/18. + */ +public class StrongRadioGroup extends LinearLayout { + private int mCheckedId = -1; + private CompoundButton.OnCheckedChangeListener mChildOnCheckedChangeListener; + private boolean mProtectFromCheckedChange = false; + private OnCheckedChangeListener mOnCheckedChangeListener; + private PassThroughHierarchyChangeListener mPassThroughListener; + + public StrongRadioGroup(Context context) { + super(context); + setOrientation(VERTICAL); + init(); + } + + public StrongRadioGroup(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + mChildOnCheckedChangeListener = new CheckedStateTracker(); + mPassThroughListener = new PassThroughHierarchyChangeListener(); + super.setOnHierarchyChangeListener(mPassThroughListener); + } + + @Override + public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) { + // the user listener is delegated to our pass-through listener + mPassThroughListener.mOnHierarchyChangeListener = listener; + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + // checks the appropriate radio button as requested in the XML file + if (mCheckedId != -1) { + mProtectFromCheckedChange = true; + setCheckedStateForView(mCheckedId, true); + mProtectFromCheckedChange = false; + setCheckedId(mCheckedId); + } + } + + @Override + public void addView(View child, int index, ViewGroup.LayoutParams params) { + if (child instanceof RadioButton) { + final RadioButton button = (RadioButton) child; + if (button.isChecked()) { + mProtectFromCheckedChange = true; + if (mCheckedId != -1) { + setCheckedStateForView(mCheckedId, false); + } + mProtectFromCheckedChange = false; + setCheckedId(button.getId()); + } + } else if (child instanceof ViewGroup) { + //添加部分 + final RadioButton button = findRadioButton((ViewGroup) child); + if (button.isChecked()) { + mProtectFromCheckedChange = true; + if (mCheckedId != -1) { + setCheckedStateForView(mCheckedId, false); + } + mProtectFromCheckedChange = false; + setCheckedId(button.getId()); + } + } + + super.addView(child, index, params); + } + + /** + * 查找radioButton控件 + */ + public RadioButton findRadioButton(ViewGroup group) { + RadioButton resBtn = null; + int len = group.getChildCount(); + for (int i = 0; i < len; i++) { + if (group.getChildAt(i) instanceof RadioButton) { + resBtn = (RadioButton) group.getChildAt(i); + } else if (group.getChildAt(i) instanceof ViewGroup) { + findRadioButton((ViewGroup) group.getChildAt(i)); + } + } + return resBtn; + } + + /** + *

+ * Sets the selection to the radio button whose identifier is passed in + * parameter. Using -1 as the selection identifier clears the selection; + * such an operation is equivalent to invoking {@link #clearCheck()}. + *

+ * + * @param id the unique id of the radio button to select in this group + * @see #getCheckedRadioButtonId() + * @see #clearCheck() + */ + public void check(int id) { + // don't even bother + if (id != -1 && (id == mCheckedId)) { + return; + } + + if (mCheckedId != -1) { + setCheckedStateForView(mCheckedId, false); + } + + if (id != -1) { + setCheckedStateForView(id, true); + } + + setCheckedId(id); + } + + private void setCheckedId(int id) { + mCheckedId = id; + if (mOnCheckedChangeListener != null) { + mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId); + } + } + + private void setCheckedStateForView(int viewId, boolean checked) { + View checkedView = findViewById(viewId); + if (checkedView != null && checkedView instanceof RadioButton) { + ((RadioButton) checkedView).setChecked(checked); + } + } + + /** + *

+ * Returns the identifier of the selected radio button in this group. Upon + * empty selection, the returned value is -1. + *

+ * + * @return the unique id of the selected radio button in this group + * @see #check(int) + * @see #clearCheck() + */ + public int getCheckedRadioButtonId() { + return mCheckedId; + } + + /** + *

+ * Clears the selection. When the selection is cleared, no radio button in + * this group is selected and {@link #getCheckedRadioButtonId()} returns + * null. + *

+ * + * @see #check(int) + * @see #getCheckedRadioButtonId() + */ + public void clearCheck() { + check(-1); + } + + /** + *

+ * Register a callback to be invoked when the checked radio button changes + * in this group. + *

+ * + * @param listener the callback to call on checked state change + */ + public void setOnCheckedChangeListener(OnCheckedChangeListener listener) { + mOnCheckedChangeListener = listener; + } + + /** + * {@inheritDoc} + */ + @Override + public LayoutParams generateLayoutParams(AttributeSet attrs) { + return new LayoutParams(getContext(), attrs); + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof LayoutParams; + } + + @Override + protected LinearLayout.LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT); + } + + /** + *

+ * This set of layout parameters defaults the width and the height of the + * children to {@link #WRAP_CONTENT} when they are not specified in the XML + * file. Otherwise, this class ussed the value read from the XML file. + *

+ *

+ *

+ * Attributes} for a list of all child view attributes that this class + * supports. + *

+ */ + public static class LayoutParams extends LinearLayout.LayoutParams { + /** + * {@inheritDoc} + */ + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + } + + /** + * {@inheritDoc} + */ + public LayoutParams(int w, int h) { + super(w, h); + } + + /** + * {@inheritDoc} + */ + public LayoutParams(int w, int h, float initWeight) { + super(w, h, initWeight); + } + + /** + * {@inheritDoc} + */ + public LayoutParams(ViewGroup.LayoutParams p) { + super(p); + } + + /** + * {@inheritDoc} + */ + public LayoutParams(MarginLayoutParams source) { + super(source); + } + + /** + *

+ * Fixes the child's width to + * {@link ViewGroup.LayoutParams#WRAP_CONTENT} and the + * child's height to + * {@link ViewGroup.LayoutParams#WRAP_CONTENT} when not + * specified in the XML file. + *

+ * + * @param a the styled attributes set + * @param widthAttr the width attribute to fetch + * @param heightAttr the height attribute to fetch + */ + @Override + protected void setBaseAttributes(TypedArray a, int widthAttr, + int heightAttr) { + + if (a.hasValue(widthAttr)) { + width = a.getLayoutDimension(widthAttr, "layout_width"); + } else { + width = WRAP_CONTENT; + } + + if (a.hasValue(heightAttr)) { + height = a.getLayoutDimension(heightAttr, "layout_height"); + } else { + height = WRAP_CONTENT; + } + } + } + + /** + *

+ * Interface definition for a callback to be invoked when the checked radio + * button changed in this group. + *

+ */ + public interface OnCheckedChangeListener { + /** + *

+ * Called when the checked radio button has changed. When the selection + * is cleared, checkedId is -1. + *

+ * + * @param group the group in which the checked radio button has changed + * @param checkedId the unique identifier of the newly checked radio button + */ + public void onCheckedChanged(StrongRadioGroup group, int checkedId); + } + + private class CheckedStateTracker implements + CompoundButton.OnCheckedChangeListener { + public void onCheckedChanged(CompoundButton buttonView, + boolean isChecked) { + // prevents from infinite recursion + if (mProtectFromCheckedChange) { + return; + } + + mProtectFromCheckedChange = true; + if (mCheckedId != -1) { + setCheckedStateForView(mCheckedId, false); + } + mProtectFromCheckedChange = false; + + int id = buttonView.getId(); + setCheckedId(id); + } + } + + /** + *

+ * A pass-through listener acts upon the events and dispatches them to + * another listener. This allows the table layout to set its own internal + * hierarchy change listener without preventing the user to setup his. + *

+ */ + private class PassThroughHierarchyChangeListener implements + OnHierarchyChangeListener { + private OnHierarchyChangeListener mOnHierarchyChangeListener; + + public void onChildViewAdded(View parent, View child) { + if (parent == StrongRadioGroup.this && child instanceof RadioButton) { + int id = child.getId(); + // generates an id if it's missing + if (id == View.NO_ID) { + id = child.hashCode(); + child.setId(id); + } + ((RadioButton) child) + .setOnCheckedChangeListener(mChildOnCheckedChangeListener); + } else if (parent == StrongRadioGroup.this && child instanceof ViewGroup) { + //添加部分 + RadioButton btn = findRadioButton((ViewGroup) child); + int id = btn.getId(); + // generates an id if it's missing + if (id == View.NO_ID) { + id = btn.hashCode(); + btn.setId(id); + } + btn.setOnCheckedChangeListener(mChildOnCheckedChangeListener); + } + + if (mOnHierarchyChangeListener != null) { + mOnHierarchyChangeListener.onChildViewAdded(parent, child); + } + } + + public void onChildViewRemoved(View parent, View child) { + if (parent == StrongRadioGroup.this && child instanceof RadioButton) { + ((RadioButton) child).setOnCheckedChangeListener(null); + } else if (parent == StrongRadioGroup.this && child instanceof ViewGroup) { + //添加部分 + findRadioButton((ViewGroup) child).setOnCheckedChangeListener( + null); + } + if (mOnHierarchyChangeListener != null) { + mOnHierarchyChangeListener.onChildViewRemoved(parent, child); + } + } + } +} diff --git a/common_base/src/main/java/com/wss/common/widget/SwipeItemLayout.java b/common_base/src/main/java/com/wss/common/widget/SwipeItemLayout.java new file mode 100644 index 0000000..dada519 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/widget/SwipeItemLayout.java @@ -0,0 +1,795 @@ +package com.wss.common.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.view.animation.Interpolator; +import android.widget.Scroller; + +import androidx.core.view.ViewCompat; +import androidx.recyclerview.widget.RecyclerView; + +/** + * Describe:可侧滑ViewGroup,其中子ViewGroup有且只能有2个 + * Created by 吴天强 on 2020/4/20. + * Copy from: https://github.com/fornana/swipeitemlayout + */ +public class SwipeItemLayout extends ViewGroup { + enum Mode { + RESET, DRAG, FLING, TAP + } + + private Mode mTouchMode; + + private ViewGroup mMainView; + private ViewGroup mSideView; + + private ScrollRunnable mScrollRunnable; + private int mScrollOffset; + private int mMaxScrollOffset; + + private boolean mInLayout; + private boolean mIsLaidOut; + private OnItemSwipeListener onItemSwipeListener; + + public SwipeItemLayout(Context context) { + this(context, null); + } + + public SwipeItemLayout(Context context, AttributeSet attrs) { + super(context, attrs); + + mTouchMode = Mode.RESET; + mScrollOffset = 0; + mIsLaidOut = false; + + mScrollRunnable = new ScrollRunnable(context); + } + + public boolean isOpen() { + return mScrollOffset != 0; + } + + Mode getTouchMode() { + return mTouchMode; + } + + void setTouchMode(Mode mode) { + switch (mTouchMode) { + case FLING: + mScrollRunnable.abort(); + break; + case RESET: + break; + } + + mTouchMode = mode; + } + + public void open() { + if (mScrollOffset != -mMaxScrollOffset) { + //正在open,不需要处理 + if (mTouchMode == Mode.FLING && mScrollRunnable.isScrollToLeft()) + return; + + //当前正在向右滑,abort + if (mTouchMode == Mode.FLING /*&& !mScrollRunnable.mScrollToLeft*/) + mScrollRunnable.abort(); + + mScrollRunnable.startScroll(mScrollOffset, -mMaxScrollOffset); + } + } + + public void close() { + if (mScrollOffset != 0) { + //正在close,不需要处理 + if (mTouchMode == Mode.FLING && !mScrollRunnable.isScrollToLeft()) + return; + + //当前正向左滑,abort + if (mTouchMode == Mode.FLING /*&& mScrollRunnable.mScrollToLeft*/) + mScrollRunnable.abort(); + + mScrollRunnable.startScroll(mScrollOffset, 0); + } + } + + public void setOnItemSwipeListener(OnItemSwipeListener listener) { + this.onItemSwipeListener = listener; + } + + void fling(int xVel) { + mScrollRunnable.startFling(mScrollOffset, xVel); + } + + void revise() { + if (mScrollOffset < -mMaxScrollOffset / 2) + open(); + else + close(); + } + + boolean trackMotionScroll(int deltaX) { + if (deltaX == 0) + return false; + + boolean over = false; + int newLeft = mScrollOffset + deltaX; + if ((deltaX > 0 && newLeft > 0) || (deltaX < 0 && newLeft < -mMaxScrollOffset)) { + over = true; + newLeft = Math.min(newLeft, 0); + newLeft = Math.max(newLeft, -mMaxScrollOffset); + } + + offsetChildrenLeftAndRight(newLeft - mScrollOffset); + mScrollOffset = newLeft; + return over; + } + + private boolean ensureChildren() { + int childCount = getChildCount(); + + if (childCount != 2) + return false; + + View childView = getChildAt(0); + if (!(childView instanceof ViewGroup)) + return false; + mMainView = (ViewGroup) childView; + + childView = getChildAt(1); + if (!(childView instanceof ViewGroup)) + return false; + mSideView = (ViewGroup) childView; + return true; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (!ensureChildren()) + throw new RuntimeException("SwipeItemLayout的子视图不符合规定"); + + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + + MarginLayoutParams lp = null; + int horizontalMargin, verticalMargin; + int horizontalPadding = getPaddingLeft() + getPaddingRight(); + int verticalPadding = getPaddingTop() + getPaddingBottom(); + + lp = (MarginLayoutParams) mMainView.getLayoutParams(); + horizontalMargin = lp.leftMargin + lp.rightMargin; + verticalMargin = lp.topMargin + lp.bottomMargin; + measureChildWithMargins(mMainView, + widthMeasureSpec, horizontalMargin + horizontalPadding, + heightMeasureSpec, verticalMargin + verticalPadding); + + if (widthMode == MeasureSpec.AT_MOST) + widthSize = Math.min(widthSize, mMainView.getMeasuredWidth() + horizontalMargin + horizontalPadding); + else if (widthMode == MeasureSpec.UNSPECIFIED) + widthSize = mMainView.getMeasuredWidth() + horizontalMargin + horizontalPadding; + + if (heightMode == MeasureSpec.AT_MOST) + heightSize = Math.min(heightSize, mMainView.getMeasuredHeight() + verticalMargin + verticalPadding); + else if (heightMode == MeasureSpec.UNSPECIFIED) + heightSize = mMainView.getMeasuredHeight() + verticalMargin + verticalPadding; + + setMeasuredDimension(widthSize, heightSize); + + //side layout大小为自身实际大小 + lp = (MarginLayoutParams) mSideView.getLayoutParams(); + verticalMargin = lp.topMargin + lp.bottomMargin; + mSideView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), + MeasureSpec.makeMeasureSpec(getMeasuredHeight() - verticalMargin - verticalPadding, MeasureSpec.EXACTLY)); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + if (!ensureChildren()) + throw new RuntimeException("SwipeItemLayout的子视图不符合规定"); + + mInLayout = true; + + int pl = getPaddingLeft(); + int pt = getPaddingTop(); + int pr = getPaddingRight(); + int pb = getPaddingBottom(); + + MarginLayoutParams mainLp = (MarginLayoutParams) mMainView.getLayoutParams(); + MarginLayoutParams sideParams = (MarginLayoutParams) mSideView.getLayoutParams(); + + int childLeft = pl + mainLp.leftMargin; + int childTop = pt + mainLp.topMargin; + int childRight = getWidth() - (pr + mainLp.rightMargin); + int childBottom = getHeight() - (mainLp.bottomMargin + pb); + mMainView.layout(childLeft, childTop, childRight, childBottom); + + childLeft = childRight + sideParams.leftMargin; + childTop = pt + sideParams.topMargin; + childRight = childLeft + sideParams.leftMargin + sideParams.rightMargin + mSideView.getMeasuredWidth(); + childBottom = getHeight() - (sideParams.bottomMargin + pb); + mSideView.layout(childLeft, childTop, childRight, childBottom); + + mMaxScrollOffset = mSideView.getWidth() + sideParams.leftMargin + sideParams.rightMargin; + mScrollOffset = mScrollOffset < -mMaxScrollOffset / 2 ? -mMaxScrollOffset : 0; + + offsetChildrenLeftAndRight(mScrollOffset); + mInLayout = false; + mIsLaidOut = true; + } + + void offsetChildrenLeftAndRight(int delta) { + ViewCompat.offsetLeftAndRight(mMainView, delta); + ViewCompat.offsetLeftAndRight(mSideView, delta); + } + + @Override + public void requestLayout() { + if (!mInLayout) { + super.requestLayout(); + } + } + + @Override + protected LayoutParams generateDefaultLayoutParams() { + return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + } + + @Override + protected LayoutParams generateLayoutParams(LayoutParams p) { + return p instanceof MarginLayoutParams ? p : new MarginLayoutParams(p); + } + + @Override + protected boolean checkLayoutParams(LayoutParams p) { + return p instanceof MarginLayoutParams && super.checkLayoutParams(p); + } + + @Override + public LayoutParams generateLayoutParams(AttributeSet attrs) { + return new MarginLayoutParams(getContext(), attrs); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + + if (mScrollOffset != 0 && mIsLaidOut) { + offsetChildrenLeftAndRight(-mScrollOffset); + mScrollOffset = 0; + } else + mScrollOffset = 0; + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + if (mScrollOffset != 0 && mIsLaidOut) { + offsetChildrenLeftAndRight(-mScrollOffset); + mScrollOffset = 0; + } else + mScrollOffset = 0; + removeCallbacks(mScrollRunnable); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + final int action = ev.getActionMasked(); + //click main view,但是它处于open状态,所以,不需要点击效果,直接拦截不调用click listener + switch (action) { + case MotionEvent.ACTION_DOWN: { + final int x = (int) ev.getX(); + final int y = (int) ev.getY(); + View pointView = findTopChildUnder(this, x, y); + if (pointView != null && pointView == mMainView && mScrollOffset != 0) + return true; + break; + } + + case MotionEvent.ACTION_MOVE: + case MotionEvent.ACTION_CANCEL: + break; + + case MotionEvent.ACTION_UP: { + final int x = (int) ev.getX(); + final int y = (int) ev.getY(); + View pointView = findTopChildUnder(this, x, y); + if (pointView != null && pointView == mMainView && mTouchMode == Mode.TAP && mScrollOffset != 0) + return true; + } + } + + return false; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + final int action = ev.getActionMasked(); + //click main view,但是它处于open状态,所以,不需要点击效果,直接拦截不调用click listener + switch (action) { + case MotionEvent.ACTION_DOWN: { + final int x = (int) ev.getX(); + final int y = (int) ev.getY(); + View pointView = findTopChildUnder(this, x, y); + if (pointView != null && pointView == mMainView && mScrollOffset != 0) + return true; + break; + } + + case MotionEvent.ACTION_MOVE: + case MotionEvent.ACTION_CANCEL: + break; + + case MotionEvent.ACTION_UP: { + final int x = (int) ev.getX(); + final int y = (int) ev.getY(); + View pointView = findTopChildUnder(this, x, y); + if (pointView != null && pointView == mMainView && mTouchMode == Mode.TAP && mScrollOffset != 0) { + close(); + return true; + } + } + } + + return false; + } + + @Override + protected void onVisibilityChanged(View changedView, int visibility) { + super.onVisibilityChanged(changedView, visibility); + if (getVisibility() != View.VISIBLE) { + mScrollOffset = 0; + invalidate(); + } + } + + private static final Interpolator sInterpolator = new Interpolator() { + @Override + public float getInterpolation(float t) { + t -= 1.0f; + return t * t * t * t * t + 1.0f; + } + }; + + class ScrollRunnable implements Runnable { + private static final int FLING_DURATION = 200; + private Scroller mScroller; + private boolean mAbort; + private int mMinVelocity; + private boolean mScrollToLeft; + + ScrollRunnable(Context context) { + mScroller = new Scroller(context, sInterpolator); + mAbort = false; + mScrollToLeft = false; + + ViewConfiguration configuration = ViewConfiguration.get(context); + mMinVelocity = configuration.getScaledMinimumFlingVelocity(); + } + + void startScroll(int startX, int endX) { + if (startX != endX) { + Log.e("scroll - startX - endX", "" + startX + " " + endX); + setTouchMode(Mode.FLING); + mAbort = false; + mScrollToLeft = endX < startX; + mScroller.startScroll(startX, 0, endX - startX, 0, 400); + ViewCompat.postOnAnimation(SwipeItemLayout.this, this); + if (onItemSwipeListener != null) { + onItemSwipeListener.onItemSwipe(mScrollToLeft); + } + } + } + + void startFling(int startX, int xVel) { + Log.e("fling - startX", "" + startX); + + if (xVel > mMinVelocity && startX != 0) { + startScroll(startX, 0); + return; + } + + if (xVel < -mMinVelocity && startX != -mMaxScrollOffset) { + startScroll(startX, -mMaxScrollOffset); + return; + } + + startScroll(startX, startX > -mMaxScrollOffset / 2 ? 0 : -mMaxScrollOffset); + } + + void abort() { + if (!mAbort) { + mAbort = true; + if (!mScroller.isFinished()) { + mScroller.abortAnimation(); + removeCallbacks(this); + } + } + } + + //是否正在滑动需要另外判断 + boolean isScrollToLeft() { + return mScrollToLeft; + } + + @Override + public void run() { + Log.e("abort", Boolean.toString(mAbort)); + if (!mAbort) { + boolean more = mScroller.computeScrollOffset(); + int curX = mScroller.getCurrX(); + Log.e("curX", "" + curX); + + boolean atEdge = trackMotionScroll(curX - mScrollOffset); + if (more && !atEdge) { + ViewCompat.postOnAnimation(SwipeItemLayout.this, this); + return; + } + + if (atEdge) { + removeCallbacks(this); + if (!mScroller.isFinished()) + mScroller.abortAnimation(); + setTouchMode(Mode.RESET); + } + + if (!more) { + setTouchMode(Mode.RESET); + //绝对不会出现这种意外的!!!可以注释掉 + if (mScrollOffset != 0) { + if (Math.abs(mScrollOffset) > mMaxScrollOffset / 2) + mScrollOffset = -mMaxScrollOffset; + else + mScrollOffset = 0; + ViewCompat.postOnAnimation(SwipeItemLayout.this, this); + } + } + } + } + } + + public static class OnSwipeItemTouchListener implements RecyclerView.OnItemTouchListener { + private SwipeItemLayout mCaptureItem; + private float mLastMotionX; + private float mLastMotionY; + private VelocityTracker mVelocityTracker; + + private int mActivePointerId; + + private int mTouchSlop; + private int mMaximumVelocity; + + private boolean mDealByParent; + private boolean mIsProbeParent; + + public OnSwipeItemTouchListener(Context context) { + ViewConfiguration configuration = ViewConfiguration.get(context); + mTouchSlop = configuration.getScaledTouchSlop(); + mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); + mActivePointerId = -1; + mDealByParent = false; + mIsProbeParent = false; + } + + @Override + public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent ev) { + if (mIsProbeParent) + return false; + + boolean intercept = false; + final int action = ev.getActionMasked(); + + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(ev); + + switch (action) { + case MotionEvent.ACTION_DOWN: { + mActivePointerId = ev.getPointerId(0); + final float x = ev.getX(); + final float y = ev.getY(); + mLastMotionX = x; + mLastMotionY = y; + + boolean pointOther = false; + SwipeItemLayout pointItem = null; + //首先知道ev针对的是哪个item + View pointView = findTopChildUnder(rv, (int) x, (int) y); + if (pointView == null || !(pointView instanceof SwipeItemLayout)) { + //可能是head view或bottom view + pointOther = true; + } else + pointItem = (SwipeItemLayout) pointView; + + //此时的pointOther=true,意味着点击的view为空或者点击的不是item + //还没有把点击的是item但是不是capture item给过滤出来 + if (!pointOther && (mCaptureItem == null || mCaptureItem != pointItem)) + pointOther = true; + + //点击的是capture item + if (!pointOther) { + Mode touchMode = mCaptureItem.getTouchMode(); + + //如果它在fling,就转为drag + //需要拦截,并且requestDisallowInterceptTouchEvent + boolean disallowIntercept = false; + if (touchMode == Mode.FLING) { + mCaptureItem.setTouchMode(Mode.DRAG); + disallowIntercept = true; + intercept = true; + } else {//如果是expand的,就不允许parent拦截 + mCaptureItem.setTouchMode(Mode.TAP); + if (mCaptureItem.isOpen()) + disallowIntercept = true; + } + + if (disallowIntercept) { + final ViewParent parent = rv.getParent(); + if (parent != null) + parent.requestDisallowInterceptTouchEvent(true); + } + } else {//capture item为null或者与point item不一样 + //直接将其close掉 + if (mCaptureItem != null && mCaptureItem.isOpen()) { + mCaptureItem.close(); + mCaptureItem = null; + intercept = true; + } + + if (pointItem != null) { + mCaptureItem = pointItem; + mCaptureItem.setTouchMode(Mode.TAP); + } else + mCaptureItem = null; + } + + //如果parent处于fling状态,此时,parent就会转为drag。此时,应该将后续move都交给parent处理 + mIsProbeParent = true; + mDealByParent = rv.onInterceptTouchEvent(ev); + mIsProbeParent = false; + if (mDealByParent) + intercept = false; + break; + } + + case MotionEvent.ACTION_POINTER_DOWN: { + final int actionIndex = ev.getActionIndex(); + mActivePointerId = ev.getPointerId(actionIndex); + + mLastMotionX = ev.getX(actionIndex); + mLastMotionY = ev.getY(actionIndex); + break; + } + + case MotionEvent.ACTION_POINTER_UP: { + final int actionIndex = ev.getActionIndex(); + final int pointerId = ev.getPointerId(actionIndex); + if (pointerId == mActivePointerId) { + final int newIndex = actionIndex == 0 ? 1 : 0; + mActivePointerId = ev.getPointerId(newIndex); + + mLastMotionX = ev.getX(newIndex); + mLastMotionY = ev.getY(newIndex); + } + break; + } + + //down时,已经将capture item定下来了。所以,后面可以安心考虑event处理 + case MotionEvent.ACTION_MOVE: { + final int activePointerIndex = ev.findPointerIndex(mActivePointerId); + if (activePointerIndex == -1) + break; + + //在down时,就被认定为parent的drag,所以,直接交给parent处理即可 + if (mDealByParent) { + if (mCaptureItem != null && mCaptureItem.isOpen()) + mCaptureItem.close(); + return false; + } + + final int x = (int) (ev.getX(activePointerIndex) + .5f); + final int y = (int) ((int) ev.getY(activePointerIndex) + .5f); + + int deltaX = (int) (x - mLastMotionX); + int deltaY = (int) (y - mLastMotionY); + final int xDiff = Math.abs(deltaX); + final int yDiff = Math.abs(deltaY); + + if (mCaptureItem != null && !mDealByParent) { + Mode touchMode = mCaptureItem.getTouchMode(); + + if (touchMode == Mode.TAP) { + //如果capture item是open的,下拉有两种处理方式: + // 1、下拉后,直接close item + // 2、只要是open的,就拦截所有它的消息,这样如果点击open的,就只能滑动该capture item + //网易邮箱,在open的情况下,下拉直接close + //QQ,在open的情况下,下拉也是close。但是,做的不够好,没有达到该效果。 + if (xDiff > mTouchSlop && xDiff > yDiff) { + mCaptureItem.setTouchMode(Mode.DRAG); + final ViewParent parent = rv.getParent(); + parent.requestDisallowInterceptTouchEvent(true); + + deltaX = deltaX > 0 ? deltaX - mTouchSlop : deltaX + mTouchSlop; + } else {// if(yDiff>mTouchSlop){ + mIsProbeParent = true; + boolean isParentConsume = rv.onInterceptTouchEvent(ev); + mIsProbeParent = false; + if (isParentConsume) { + //表明不是水平滑动,即不判定为SwipeItemLayout的滑动 + //但是,可能是下拉刷新SwipeRefreshLayout或者RecyclerView的滑动 + //一般的下拉判定,都是yDiff>mTouchSlop,所以,此处这么写不会出问题 + //这里这么做以后,如果判定为下拉,就直接close + mDealByParent = true; + mCaptureItem.close(); + } + } + } + + touchMode = mCaptureItem.getTouchMode(); + if (touchMode == Mode.DRAG) { + intercept = true; + mLastMotionX = x; + mLastMotionY = y; + + //对capture item进行拖拽 + mCaptureItem.trackMotionScroll(deltaX); + } + } + break; + } + + case MotionEvent.ACTION_UP: + if (mCaptureItem != null) { + Mode touchMode = mCaptureItem.getTouchMode(); + if (touchMode == Mode.DRAG) { + final VelocityTracker velocityTracker = mVelocityTracker; + velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); + int xVel = (int) velocityTracker.getXVelocity(mActivePointerId); + mCaptureItem.fling(xVel); + + intercept = true; + } + } + cancel(); + break; + + case MotionEvent.ACTION_CANCEL: + if (mCaptureItem != null) + mCaptureItem.revise(); + cancel(); + break; + } + + return intercept; + } + + @Override + public void onTouchEvent(RecyclerView rv, MotionEvent ev) { + final int action = ev.getActionMasked(); + final int actionIndex = ev.getActionIndex(); + + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(ev); + + switch (action) { + case MotionEvent.ACTION_POINTER_DOWN: + mActivePointerId = ev.getPointerId(actionIndex); + + mLastMotionX = ev.getX(actionIndex); + mLastMotionY = ev.getY(actionIndex); + break; + + case MotionEvent.ACTION_POINTER_UP: + final int pointerId = ev.getPointerId(actionIndex); + if (pointerId == mActivePointerId) { + final int newIndex = actionIndex == 0 ? 1 : 0; + mActivePointerId = ev.getPointerId(newIndex); + + mLastMotionX = ev.getX(newIndex); + mLastMotionY = ev.getY(newIndex); + } + break; + + //down时,已经将capture item定下来了。所以,后面可以安心考虑event处理 + case MotionEvent.ACTION_MOVE: { + final int activePointerIndex = ev.findPointerIndex(mActivePointerId); + if (activePointerIndex == -1) + break; + + final float x = ev.getX(activePointerIndex); + final float y = (int) ev.getY(activePointerIndex); + + int deltaX = (int) (x - mLastMotionX); + + if (mCaptureItem != null && mCaptureItem.getTouchMode() == Mode.DRAG) { + mLastMotionX = x; + mLastMotionY = y; + + //对capture item进行拖拽 + mCaptureItem.trackMotionScroll(deltaX); + } + break; + } + + case MotionEvent.ACTION_UP: + if (mCaptureItem != null) { + Mode touchMode = mCaptureItem.getTouchMode(); + if (touchMode == Mode.DRAG) { + final VelocityTracker velocityTracker = mVelocityTracker; + velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); + int xVel = (int) velocityTracker.getXVelocity(mActivePointerId); + mCaptureItem.fling(xVel); + } + } + cancel(); + break; + + case MotionEvent.ACTION_CANCEL: + if (mCaptureItem != null) + mCaptureItem.revise(); + + cancel(); + break; + + } + } + + @Override + public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { + } + + void cancel() { + mDealByParent = false; + mActivePointerId = -1; + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + } + + } + + + public interface OnItemSwipeListener { + + void onItemSwipe(boolean isOpen); + } + + + static View findTopChildUnder(ViewGroup parent, int x, int y) { + final int childCount = parent.getChildCount(); + for (int i = childCount - 1; i >= 0; i--) { + final View child = parent.getChildAt(i); + if (x >= child.getLeft() && x < child.getRight() + && y >= child.getTop() && y < child.getBottom()) { + return child; + } + } + return null; + } + + public static void closeAllItems(RecyclerView recyclerView) { + for (int i = 0; i < recyclerView.getChildCount(); i++) { + View child = recyclerView.getChildAt(i); + if (child instanceof SwipeItemLayout) { + SwipeItemLayout swipeItemLayout = (SwipeItemLayout) child; + if (swipeItemLayout.isOpen()) + swipeItemLayout.close(); + } + } + } + + +} diff --git a/common_base/src/main/java/com/wss/common/widget/ViewPagerForScrollView.java b/common_base/src/main/java/com/wss/common/widget/ViewPagerForScrollView.java new file mode 100644 index 0000000..56897e5 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/widget/ViewPagerForScrollView.java @@ -0,0 +1,126 @@ +package com.wss.common.widget; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; + +import com.wss.common.utils.PxUtils; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.LinkedHashMap; + +import androidx.viewpager.widget.ViewPager; + +/** + * ViewPager和ScrollView嵌套空白问题 + * + * @author 杨伟 + * create by 2020-4-17 + */ +public class ViewPagerForScrollView extends ViewPager implements Serializable { + + private static final long serialVersionUID = 1L; + + + private int current; + private int height = 0; + /** + * 保存position与对于的View + */ + private HashMap mChildrenViews = new LinkedHashMap<>(); + private boolean scroll = true; + /** + * 最小高度 + */ + private int minHeight; + + public ViewPagerForScrollView(Context context) { + super(context); + } + + public ViewPagerForScrollView(Context context, AttributeSet attrs) { + super(context, attrs); + minHeight = PxUtils.getScreenHeight(context); + } + + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + try { + if (mChildrenViews.size() > current) { + View child = mChildrenViews.get(current); + if (child != null) { + child.measure(widthMeasureSpec, View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); + height = child.getMeasuredHeight(); + //如果计算出ViewPager的高度小于最小高度,则使用最小高度作为ViewPager高度 + if (height < minHeight) { + height = minHeight; + } + } + } + heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 重置ViewPager的高度 + * + * @param current 第几页的 + */ + public void resetHeight(int current) { + this.current = current; + if (mChildrenViews.size() > current) { + ViewGroup.LayoutParams layoutParams = getLayoutParams(); + if (layoutParams == null) { + layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height); + } else { + layoutParams.height = height; + } + + setLayoutParams(layoutParams); + } + } + + /** + * 保存position与对于的View + */ + public void setObjectForPosition(View view, int position) { + mChildrenViews.put(position, view); + } + + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (!scroll) { + return true; + } + return super.onTouchEvent(ev); + } + + /** + * 设置ViewPager显示的最小高度 + * + * @param minHeight 最小高度 + */ + public void setMinHeight(int minHeight) { + this.minHeight = minHeight; + } + + /** + * 设置是否可滚动 + * + * @param scroll 滚动 + */ + public void setScroll(boolean scroll) { + this.scroll = scroll; + } + +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/widget/WebViewProgressBar.java b/common_base/src/main/java/com/wss/common/widget/WebViewProgressBar.java deleted file mode 100644 index f9e53c7..0000000 --- a/common_base/src/main/java/com/wss/common/widget/WebViewProgressBar.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.wss.common.widget; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.util.AttributeSet; -import android.view.View; - -import com.wss.common.base.R; - - -/** - * WebView进度条 - * Created by wtq on 2016/12/15. - */ -public class WebViewProgressBar extends View { - private int progress = 1; - private final static int HEIGHT = 5; - private Paint paint; - private final static int colors[] = new int[]{}; - - public WebViewProgressBar(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public WebViewProgressBar(Context context) { - super(context); - paint = new Paint(Paint.DITHER_FLAG); - paint.setStyle(Paint.Style.STROKE); - paint.setStrokeWidth(HEIGHT); - paint.setAntiAlias(true); - paint.setColor(context.getResources().getColor(R.color.theme)); - } - - public void setProgress(int progress) { - this.progress = progress; - invalidate(); - } - - @Override - protected void onDraw(Canvas canvas) { - canvas.drawRect(0, 0, getWidth() * progress / 100, HEIGHT, paint); - } -} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/widget/dialog/AppDialog.java b/common_base/src/main/java/com/wss/common/widget/dialog/AppDialog.java index b6903f0..33a883c 100644 --- a/common_base/src/main/java/com/wss/common/widget/dialog/AppDialog.java +++ b/common_base/src/main/java/com/wss/common/widget/dialog/AppDialog.java @@ -2,8 +2,9 @@ import android.app.Dialog; import android.content.Context; -import android.text.Editable; -import android.text.TextUtils; +import android.content.DialogInterface; +import android.graphics.Color; +import android.text.InputType; import android.text.TextWatcher; import android.view.Gravity; import android.view.View; @@ -11,7 +12,6 @@ import android.view.WindowManager; import android.widget.Button; import android.widget.EditText; -import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; @@ -20,14 +20,19 @@ import com.wss.common.base.R2; import com.wss.common.utils.KeyboardUtils; import com.wss.common.utils.PxUtils; -import com.wss.common.widget.CountClickView; +import com.wss.common.utils.ValidUtils; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; import java.util.List; +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; - +import butterknife.Unbinder; /** * Describe:自定义对话框 @@ -35,78 +40,105 @@ */ public class AppDialog { + private static final int MAX_ITEM = 7; + /** + * 对话框的顶级父类 + */ @BindView(R2.id.dialog_layout) - LinearLayout dialogLayout;//对话框的顶级父类 + LinearLayout dialogLayout; + /** + * 中间显示的Dialog 父View + */ @BindView(R2.id.ll_center) - LinearLayout llCenter;//中间显示的Dialog 父View + LinearLayout llCenter; @BindView(R2.id.tv_title) TextView tvTitle; @BindView(R2.id.tv_content) TextView tvContent; @BindView(R2.id.edt_input) EditText edtInput; - @BindView(R2.id.iv_minus) - ImageView ivMinus; - @BindView(R2.id.edt_count) - EditText edtCount; - @BindView(R2.id.iv_plus) - ImageView ivPlus; - @BindView(R2.id.ll_count_view) - LinearLayout llCountView; + @BindView(R2.id.btn_left) Button btnLeft; @BindView(R2.id.btn_right) Button btnRight; @BindView(R2.id.btn_line) View btnLine; - @BindView(R2.id.ll_content_layout) - LinearLayout contentLayout;//中间弹出对话框的View + /** + * 中间弹出对话框的Content View + */ + @BindView(R2.id.ll_content_layout) + LinearLayout contentLayout; + @BindView(R2.id.center_scroll_view) + ScrollView centerScrollView; + /** + * 底部弹出的Dialog 父View + */ @BindView(R2.id.ll_bottom) - LinearLayout llBottom;//底部弹出的Dialog 父View - @BindView(R2.id.tv_bottom_title) - TextView tvBottomTitle; + LinearLayout llBottom; @BindView(R2.id.ll_context) LinearLayout llContext; - @BindView(R2.id.sLayout_content) - ScrollView sLayoutContent; + @BindView(R2.id.bottom_scroll_view) + ScrollView bottomScrollView; @BindView(R2.id.tv_cancel) TextView tvCancel; - @DialogType.Type - private int type; - private int maxCount = CountClickView.MAX_COUNT; - private int minCount = CountClickView.MIN_COUNT; private Dialog dialog; - private Context mContext; + private Unbinder butterKnifeBinder; + private Builder builder; + + private AppDialog() { + + } + + private AppDialog(Builder builder) { + this.builder = builder; + } - private OnButtonClickListener leftListener; - private OnButtonClickListener rightListener; - private OnItemClickListener itemClickListener; - private String title;//标题 + /** + * 显示对话框 + */ + public void show() { + initView(); + dialog.show(); + } - public AppDialog(Context context) { - this(context, DialogType.DEFAULT); + public boolean isShowing() { + return dialog != null && dialog.isShowing(); } - public AppDialog(Context context, @DialogType.Type int type) { - this.mContext = context; - this.type = type; - View dialogView = View.inflate(mContext, R.layout.dialog_app, null); - ButterKnife.bind(this, dialogView); + /** + * 关闭对话框 + */ + public void dismiss() { + if (dialog != null) { + dialog.dismiss(); + } + if (butterKnifeBinder != null) { + butterKnifeBinder.unbind(); + } + } + + /** + * 初始化View + */ + private void initView() { + View dialogView = View.inflate(builder.context, R.layout.dialog_app, null); + butterKnifeBinder = ButterKnife.bind(this, dialogView); int themeResId = R.style.DialogStyle; - if (type == DialogType.BOTTOM_IN) { + if (builder.type == DialogType.BOTTOM_IN) { themeResId = R.style.ActionSheetDialogStyle; - dialogView.setMinimumWidth(PxUtils.getScreenWidth(mContext)); + dialogView.setMinimumWidth(PxUtils.getScreenWidth(builder.context)); } - dialog = new Dialog(mContext, themeResId); + dialog = new Dialog(builder.context, themeResId); dialog.setContentView(dialogView); Window window = dialog.getWindow(); if (window != null) { - if (type == DialogType.BOTTOM_IN) { + if (builder.type == DialogType.BOTTOM_IN) { window.getAttributes().gravity = Gravity.BOTTOM; WindowManager.LayoutParams lp = window.getAttributes(); lp.x = 0; @@ -116,499 +148,827 @@ public AppDialog(Context context, @DialogType.Type int type) { window.getAttributes().gravity = Gravity.CENTER; } } - dialog.setCanceledOnTouchOutside(false); - } - - private void initView() { - switch (type) { - case DialogType.DEFAULT: - setTitleText(); - break; + dialog.setCanceledOnTouchOutside(builder.canceledOnTouchOutside); + dialog.setCancelable(builder.cancelable); + dialog.setOnDismissListener(builder.dialogDismissListener); + switch (builder.type) { case DialogType.INPUT: - setTitleText(); - edtInput.setVisibility(View.VISIBLE); - tvContent.setVisibility(View.GONE); - llCountView.setVisibility(View.GONE); - dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); - break; - case DialogType.COUNT: - setTitleText(); - edtInput.setVisibility(View.GONE); - tvContent.setVisibility(View.GONE); - llCountView.setVisibility(View.VISIBLE); - dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); + //带文本框输入 + setInputSetting(); break; case DialogType.NO_TITLE: tvTitle.setVisibility(View.GONE); + setCommonSetting(); break; case DialogType.BOTTOM_IN: //底部弹出对话框 - tvBottomTitle.setText(title); - llCenter.setVisibility(View.GONE); + setBottomSetting(); + break; + case DialogType.REPLACE_ALL: + //替换全部View + dialogLayout.removeAllViews(); + dialogLayout.addView(builder.allDialogView); + break; + case DialogType.REPLACE_CONTENT: + //替换Content View + contentLayout.removeAllViews(); + contentLayout.addView(builder.contentView); + break; + case DialogType.REPLACE_BOTTOM: + //替换底部View llBottom.setVisibility(View.VISIBLE); + llBottom.removeAllViews(); + llBottom.addView(builder.bottomView); break; + case DialogType.DEFAULT: + //默认对话框 default: + setCommonSetting(); break; } } - private void setTitleText() { - if (!TextUtils.isEmpty(title)) { - tvTitle.setText(title); - } - } - /** - * 设置Title + * 常规对话框相关设置 */ - public AppDialog setTitle(String title) { - this.title = title; - return this; - } - - /** - * 设置显示内容 - */ - public AppDialog setContent(String content) { - tvContent.setText(content); - return this; + private void setCommonSetting() { + llCenter.setVisibility(View.VISIBLE); + tvContent.setTextSize(builder.contentTextSize); + btnLeft.setTextSize(builder.leftButtonTextSize); + btnRight.setTextSize(builder.rightButtonTextSize); + tvContent.setTextColor(builder.contentTextColor); + btnLeft.setTextColor(builder.leftButtonTextColor); + btnRight.setTextColor(builder.rightButtonTextColor); + if (ValidUtils.isValid(builder.title)) { + tvTitle.setText(builder.title); + } + if (ValidUtils.isValid(builder.letButtonText)) { + btnLeft.setText(builder.letButtonText); + } + if (ValidUtils.isValid(builder.rightButtonText)) { + btnRight.setText(builder.rightButtonText); + } + tvContent.setText(builder.content); + centerScrollView.post(() -> { + int height = centerScrollView.getHeight(); + int max = PxUtils.getScreenHeight(builder.context) * 3 / 5; + if (height > max) { + LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) bottomScrollView.getLayoutParams(); + params.height = max; + centerScrollView.setLayoutParams(params); + } + }); + if (builder.isSingleButton) { + //单按钮 + btnLeft.setVisibility(View.GONE); + btnLine.setVisibility(View.GONE); + btnRight.setBackgroundResource(R.drawable.corners_white_gray_selecter); + } } /** - * 加减输入模式下 设置的数字 - * - * @param minCount minCount - * @param maxCount maxCount - * @param current current + * 文本框输入类型相关设置 */ - public AppDialog setNumber(int minCount, int maxCount, int current) { - this.minCount = minCount; - this.maxCount = maxCount; - edtCount.setText(String.valueOf(current)); - edtCount.setSelection(edtCount.getText().length()); - edtCount.addTextChangedListener(textWatcher); - judgeTheViews(current); - return this; + private void setInputSetting() { + setCommonSetting(); + edtInput.setVisibility(View.VISIBLE); + tvContent.setVisibility(View.GONE); + if (dialog.getWindow() != null) { + dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); + } + edtInput.setTextSize(builder.inputTextSize); + edtInput.setTextColor(builder.inputTextColor); + edtInput.setHintTextColor(builder.inputHintTextColor); + edtInput.setInputType(builder.inputType); + if (builder.textWatcher != null) { + edtInput.addTextChangedListener(builder.textWatcher); + } + if (ValidUtils.isValid(builder.inputHintText)) { + edtInput.setHint(builder.inputHintText); + } + if (ValidUtils.isValid(builder.inputDefaultText)) { + edtInput.setText(builder.inputDefaultText); + edtInput.setSelection(builder.inputDefaultText.length()); + } } /** - * 显示对话框 + * 底部弹出类型相关设置 */ - public void show() { - initView(); - dialog.show(); + private void setBottomSetting() { + llBottom.setVisibility(View.VISIBLE); + tvCancel.setTextSize(builder.bottomCancelTextSize); + tvCancel.setTextColor(builder.bottomCancelTextColor); + if (ValidUtils.isValid(builder.bottomTitleText)) { + tvCancel.setText(builder.bottomCancelText); + } + int size = ValidUtils.isValid(builder.bottomItems) ? builder.bottomItems.size() : 0; + setItemScrollViewHeight(size); + llContext.removeAllViews(); + for (int i = 0; i < size; i++) { + View v = View.inflate(builder.context, R.layout.layout_item_of_dialog_bottom_in, null); + TextView item = v.findViewById(R.id.tv_text); + item.setText(builder.bottomItems.get(i)); + item.setTag(i); + item.setTextColor(builder.bottomItemTextColor); + item.setTextSize(builder.bottomItemTextSize); + item.setOnClickListener(v1 -> { + if (builder.itemClickListener != null) { + builder.itemClickListener.onItemClick((int) v1.getTag(), ((TextView) v1).getText().toString()); + } + dismiss(); + }); + llContext.addView(v); + } } - /** - * 关闭对话框 - */ - public void dismiss() { - if (dialog != null) { - dialog.dismiss(); + @OnClick({R2.id.btn_left, R2.id.btn_right, R2.id.tv_cancel}) + public void onClick(@NonNull View v) { + if (v.getId() == R.id.btn_left) { + onButtonClick(builder.letButtonListener); + } else if (v.getId() == R.id.btn_right) { + onButtonClick(builder.rightButtonListener); + } else if (v.getId() == R.id.tv_cancel) { + dismiss(); } } + /** - * 给左边按钮设置文字 事件 + * 给点击事件设置数据 * - * @param text 文字 - * @param listener 事件 - * @return AppDialog + * @param listener listener */ - public AppDialog setLeftButton(String text, OnButtonClickListener listener) { - this.leftListener = listener; - if (!TextUtils.isEmpty(text)) { - btnLeft.setText(text); + private void onButtonClick(OnButtonClickListener listener) { + if (builder.type == DialogType.INPUT) { + if (listener != null) { + listener.onClick(edtInput.getText().toString().trim()); + } + KeyboardUtils.hideKeyboard(edtInput); + } else { + if (listener != null) { + listener.onClick(tvContent.getText().toString()); + } } - return this; + dismiss(); } /** - * 给左边按钮设置文字 事件 + * 设置底部弹出带条目的ScrollView的高度 * - * @param listener 事件 - * @return AppDialog + * @param size 条目数量 */ - public AppDialog setLeftButton(OnButtonClickListener listener) { - return setLeftButton(null, listener); + private void setItemScrollViewHeight(int size) { + // 添加条目过多的时候控制高度 + if (size >= MAX_ITEM) { + LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) bottomScrollView.getLayoutParams(); + params.height = PxUtils.getScreenHeight(builder.context) / 2; + bottomScrollView.setLayoutParams(params); + } } + /** - * 给左边按钮设置文字 事件 + * 相机的Item * - * @param text text - * @return AppDialog - */ - public AppDialog setLeftButton(String text) { - return setLeftButton(text, null); - } + * @param context context + * @return List + */ + @NotNull + public static List getPhotoItem(@NotNull Context context) { + List items = new ArrayList<>(); + items.add(context.getString(R.string.camera)); + items.add(context.getString(R.string.album)); + return items; + } + + /** + * Describe:对话框建造者 + * Created by 吴天强 on 2018年9月27日 + */ + public static class Builder { + Context context; + /** + * 对话框类型 + */ + @DialogType.Type + int type = DialogType.DEFAULT; + + /** + * 文本框输入类型 + */ + int inputType = InputType.TYPE_CLASS_TEXT; + /** + * 对话框Title + */ + String title; + /** + * 显示内容文字颜色 + */ + int contentTextColor = Color.BLACK; + /** + * 显示内容文字大小 + */ + float contentTextSize = 16; + /** + * 对话框内容 + */ + String content; + /** + * 左按钮文字 + */ + String letButtonText; + /** + * 右按钮文字 + */ + String rightButtonText; + /** + * 左按钮事件 + */ + OnButtonClickListener letButtonListener; + /** + * 右按钮事件 + */ + OnButtonClickListener rightButtonListener; + + /** + * 左按钮文字颜色 + */ + int leftButtonTextColor = Color.GRAY; + /** + * 右按钮文字颜色 + */ + int rightButtonTextColor = Color.parseColor("#0099FF"); + /** + * 左按钮文字大小 + */ + float leftButtonTextSize = 18; + /** + * 右按钮文字大小 + */ + float rightButtonTextSize = 18; + + /** + * 底部弹出多条目内容 + */ + List bottomItems; + /** + * 底部多条目点击事件 + */ + OnItemClickListener itemClickListener; + /** + * 底部弹出对话框标题文字 + */ + String bottomTitleText; + /** + * 底部弹出对话框取消按钮文字 + */ + String bottomCancelText; + /** + * 底部弹出对话框取消按钮文字颜色 + */ + int bottomCancelTextColor = Color.GRAY; + /** + * 底部弹出对话框Item文字颜色 + */ + int bottomItemTextColor = Color.BLACK; + /** + * 底部弹出对话框取消按钮文字大小 + */ + float bottomCancelTextSize = 18; + /** + * 底部弹出对话框Item文字大小 + */ + float bottomItemTextSize = 16; + + /** + * 输入框默认文字 + */ + String inputDefaultText; + /** + * 输入框hint文字 + */ + String inputHintText; + /** + * 输入框文字颜色 + */ + int inputTextColor = Color.BLACK; + /** + * 输入框Hint文字颜色 + */ + int inputHintTextColor = Color.GRAY; + /** + * 输入框文字大小 + */ + float inputTextSize = 16; + /** + * 输入框输入监听 + */ + TextWatcher textWatcher; + /** + * 替换整个Dialog内容的View + */ + View allDialogView; + /** + * 替换中间部分View + */ + View contentView; + /** + * 替换底部弹出View + */ + View bottomView; + + /** + * 是否单按钮 + */ + boolean isSingleButton; + + /** + * 是否可以取消 + */ + boolean cancelable = true; + + /** + * 点击对话框周围是否可取消 + */ + boolean canceledOnTouchOutside = true; + + /** + * 对话框消失监听 + */ + DialogInterface.OnDismissListener dialogDismissListener; + + /** + * 初始化 + * + * @param context 上下文 + */ + public Builder(Context context) { + this.context = context; + } + /** + * 设置对话框类型 + * + * @param type DialogType + * @return Builder + */ + public Builder setDialogType(@DialogType.Type int type) { + this.type = type; + return this; + } - /** - * 给右边按钮设置文字 事件 - * - * @param text 文字 - * @param listener 事件 - * @return AppDialog - */ - public AppDialog setRightButton(String text, OnButtonClickListener listener) { - this.rightListener = listener; - if (!TextUtils.isEmpty(text)) { - btnRight.setText(text); + /** + * 设置文本框输入类型 + * + * @param inputType 输入类型 + * @return Builder + */ + public Builder setInputType(int inputType) { + this.inputType = inputType; + return this; } - return this; - } - /** - * 给右边按钮设置文字 事件 - * - * @param listener 事件 - * @return AppDialog - */ - public AppDialog setRightButton(OnButtonClickListener listener) { - return setRightButton(null, listener); - } + /** + * 设置对话框标题 + * + * @param title 标题 + * @return Builder + */ + public Builder setTitle(String title) { + this.title = title; + return this; + } - /** - * 给右边按钮设置文字 事件 - * - * @param text text - * @return AppDialog - */ - public AppDialog setRightButton(String text) { - return setRightButton(text, null); - } + /** + * 设置对话框内容 + * + * @param content 内容 + * @return Builder + */ + public Builder setContent(String content) { + this.content = content; + return this; + } - /** - * 左按钮文字颜色 - * - * @param color color - * @return AppDialog - */ - public AppDialog setLeftButtonTextColor(int color) { - btnLeft.setTextSize(mContext.getResources().getColor(color)); - return this; - } + /** + * 设置显示内容文字颜色 + * + * @param color 颜色 + * @return Builder + */ + public Builder setContentTextColor(@ColorInt int color) { + this.contentTextColor = color; + return this; + } - /** - * 右按钮文字大小 - * - * @param color color - * @return AppDialog - */ - public AppDialog setRightButtonTextColor(int color) { - btnRight.setTextSize(mContext.getResources().getColor(color)); - return this; - } + /** + * 设置显示内容文字大小 + * + * @param contentTextSize 大小 + * @return Builder + */ + public Builder setContentTextSize(float contentTextSize) { + this.contentTextSize = contentTextSize; + return this; + } + ////////////////////////////////////////左按钮设置//////////////////////////////////////////// + + /** + * 设置左按钮 + * + * @param text 显示文字 + * @return Builder + */ + public Builder setLeftButton(String text) { + return setLeftButton(text, null); + } - /** - * 单按钮文字大小 - * - * @param color color - * @return AppDialog - */ - public AppDialog setSingleButtonTextColor(int color) { - return setRightButtonTextColor(color); - } + /** + * 设置左按钮 + * + * @param listener 监听事件 + * @return Builder + */ + public Builder setLeftButton(OnButtonClickListener listener) { + return setLeftButton(null, listener); + } + /** + * 设置左按钮 + * + * @param text 显示文字 + * @param listener 监听事件 + * @return Builder + */ + public Builder setLeftButton(String text, OnButtonClickListener listener) { + this.letButtonText = text; + this.letButtonListener = listener; + return this; + } - /** - * 单按钮 - * - * @param text text - * @param listener listener - * @return AppDialog - */ - public AppDialog setSingleButton(String text, OnButtonClickListener listener) { - this.rightListener = listener; - if (!TextUtils.isEmpty(text)) { - btnRight.setText(text); - } - btnLeft.setVisibility(View.GONE); - btnLine.setVisibility(View.GONE); - btnRight.setBackgroundResource(R.drawable.corners_white_gray_selecter); - return this; - } + /** + * 设置左按钮文字颜色 + * + * @param color 颜色 + * @return Builder + */ + public Builder setLeftButtonTextColor(@ColorInt int color) { + this.leftButtonTextColor = color; + return this; + } - /** - * 单按钮 - * - * @param listener listener - * @return AppDialog - */ - public AppDialog setSingleButton(OnButtonClickListener listener) { - return setSingleButton(null, listener); - } + /** + * 设置左按钮文字大小 + * + * @param size 大小 + * @return Builder + */ + public Builder setLeftButtonTextSize(float size) { + this.leftButtonTextSize = size; + return this; + } - /** - * 单按钮 - * - * @param text listener - * @return AppDialog - */ - public AppDialog setSingleButton(String text) { - return setSingleButton(text, null); - } + ////////////////////////////////////////右按钮设置//////////////////////////////////////////// - /** - * 单按钮 - * - * @return AppDialog - */ - public AppDialog setSingleButton() { - return setSingleButton(null, null); - } + /** + * 设置右按钮 + * + * @param text 显示文字 + * @return Builder + */ + public Builder setRightButton(String text) { + return setRightButton(text, null); + } - /** - * 设置底部弹出对话框的条目 - * - * @param items 条目名称 - * @param listener listener - * @return AppDialog - */ - public AppDialog setBottomItems(List items, OnItemClickListener listener) { - this.itemClickListener = listener; - setItems(items); - return this; - } + /** + * 设置右按钮 + * + * @param listener 监听事件 + * @return Builder + */ + public Builder setRightButton(OnButtonClickListener listener) { + return setRightButton(null, listener); + } - /** - * 设置底部弹出对话框的取消文字 - * - * @param text text - * @return AppDialog - */ - public AppDialog setBottomCancelText(String text) { - if (!TextUtils.isEmpty(text)) { - tvCancel.setText(text); + /** + * 设置右按钮 + * + * @param text 显示文字 + * @param listener 监听事件 + * @return Builder + */ + public Builder setRightButton(String text, OnButtonClickListener listener) { + this.rightButtonText = text; + this.rightButtonListener = listener; + return this; } - return this; - } - /** - * 设置底部弹出对话框的取消文字颜色 - * - * @param color text - * @return AppDialog - */ - public AppDialog setBottomCancelTextColor(int color) { - tvCancel.setTextColor(mContext.getResources().getColor(color)); - return this; - } + /** + * 设置右按钮文字颜色 + * + * @param color 颜色 + * @return Builder + */ + public Builder setRightButtonTextColor(@ColorInt int color) { + this.rightButtonTextColor = color; + return this; + } + /** + * 设置右按钮文字大小 + * + * @param size 大小 + * @return Builder + */ + public Builder setRightButtonTextSize(float size) { + this.rightButtonTextSize = size; + return this; + } + ////////////////////////////////////////单按钮设置//////////////////////////////////////////// + + /** + * 单按钮设置 + * + * @param text 显示文字 + * @return Builder + */ + public Builder setSingleButton(String text) { + return setSingleButton(text, null); + } - /** - * 给整个Dialog添加View - * - * @param view view - * @return AppDialog - */ - public AppDialog addDialogView(View view) { - dialogLayout.removeAllViews(); - dialogLayout.addView(view); - return this; - } + /** + * 单按钮设置 + * + * @param listener 事件监听 + * @return Builder + */ + public Builder setSingleButton(OnButtonClickListener listener) { + return setSingleButton(null, listener); + } - /** - * 中间弹出对话框添加View - * - * @param view view - * @return AppDialog - */ - public AppDialog addContentView(View view) { - contentLayout.removeAllViews(); - contentLayout.addView(view); - return this; - } + /** + * 单按钮设置 + * + * @param text 显示文字 + * @param listener 事件监听 + * @return Builder + */ + public Builder setSingleButton(String text, OnButtonClickListener listener) { + this.isSingleButton = true; + return setRightButton(text, listener); + } - /** - * 底部弹出对话框添加View - * - * @param view view - * @param itemSize 条目数量 - * @return AppDialog - */ - public AppDialog addItemView(View view, int itemSize) { - llContext.removeAllViews(); - llContext.addView(view); - setItemScrollViewHeight(itemSize); - return this; - } + /** + * 设置单按钮文字颜色 + * + * @param color 颜色 + * @return Builder + */ + public Builder setSingleButtonTextColor(@ColorInt int color) { + return setRightButtonTextColor(color); + } + /** + * 设置单按钮文字大小 + * + * @param size 大小 + * @return Builder + */ + public Builder setSingleButtonTextSize(float size) { + return setRightButtonTextSize(size); + } - @OnClick({R2.id.btn_left, R2.id.btn_right, R2.id.minus, R2.id.plus, R2.id.tv_cancel}) - public void onClick(View v) { - if (v.getId() == R.id.btn_left) { - onButtonClick(leftListener); - } else if (v.getId() == R.id.btn_right) { - onButtonClick(rightListener); - } else if (v.getId() == R.id.minus) { - //减少 - int count = getCountEdtValue(); - if (getCountEdtValue() > minCount) { - edtCount.setText(String.valueOf(--count)); - } - judgeTheViews(count); - } else if (v.getId() == R.id.plus) { - //增加 - int count = getCountEdtValue(); - if (count < maxCount) { - edtCount.setText(String.valueOf(++count)); - } - judgeTheViews(count); - } else if (v.getId() == R.id.tv_cancel) { - dismiss(); + ////////////////////////////////////////多条目设置//////////////////////////////////////////// + + /** + * 当type = 底部弹出的时候,设置弹出条目及监听 + * + * @param items 弹出条目 + * @param listener 监听事件 + * @return Builder + */ + public Builder setBottomItems(List items, OnItemClickListener listener) { + this.bottomItems = items; + this.itemClickListener = listener; + return this; } - } - /** - * 加减模式下点击结束结算值 - */ - private void judgeTheViews(int count) { - if (count == minCount) { - ivMinus.setImageResource(R.drawable.input_minus_disabled); - } else { - ivMinus.setImageResource(R.drawable.input_minus_default); + /** + * 设置底部弹出对话框取消按钮文字 + * + * @param text 显示文字 + * @return Builder + */ + public Builder setBottomCancelText(String text) { + this.bottomCancelText = text; + return this; } - if (count == maxCount) { - ivPlus.setImageResource(R.drawable.input_add_disabled); - } else { - ivPlus.setImageResource(R.drawable.input_add_default); + + /** + * 设置底部弹出对话框标题文字 + * + * @param text 显示文字 + * @return Builder + */ + public Builder setBottomTitleText(String text) { + this.bottomTitleText = text; + return this; } - } - /** - * 给点击事件设置数据 - * - * @param listener listener - */ - private void onButtonClick(OnButtonClickListener listener) { + /** + * 设置底部弹出对话框取消按钮文字颜色 + * + * @param color 颜色 + * @return Builder + */ + public Builder setBottomCancelTextColor(@ColorInt int color) { + this.bottomCancelTextColor = color; + return this; + } - if (type == DialogType.COUNT) { - if (getCountEdtValue() >= minCount) { - if (listener != null) { - listener.onClick(String.valueOf(getCountEdtValue())); - } - } - KeyboardUtils.hideKeyboard(edtCount); - } else if (type == DialogType.INPUT) { - if (listener != null) { - listener.onClick(edtInput.getText().toString().trim()); - } - KeyboardUtils.hideKeyboard(edtInput); - } else { - if (listener != null) { - listener.onClick(tvContent.getText().toString()); - } + /** + * 设置底部弹出对话框Item文字颜色 + * + * @param color 颜色 + * @return Builder + */ + public Builder setBottomItemTextColor(@ColorInt int color) { + this.bottomItemTextColor = color; + return this; } - dismiss(); - } - /** - * 底部弹出对话框添加条目 - * - * @param items items - */ - private void setItems(List items) { - if (items != null && items.size() > 0) { - int size = items.size(); - setItemScrollViewHeight(size); - // 循环添加条目 - for (int i = 0; i <= size - 1; i++) { - View v = View.inflate(mContext, R.layout.layout_item_of_dialog_bottom_in, null); - TextView item = v.findViewById(R.id.tv_text); - item.setText(items.get(i)); - item.setTag(i); - item.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (itemClickListener != null) { - itemClickListener.onItemClick((int) v.getTag()); - } - dismiss(); - } - }); - llContext.addView(v); - } + /** + * 设置底部弹出对话框取消按钮文字大小 + * + * @param size 大小 + * @return Builder + */ + public Builder setBottomCancelTextSize(float size) { + this.bottomCancelTextSize = size; + return this; } - } - /** - * 设置底部弹出带条目的ScrollView的高度 - * - * @param size 条目数量 - */ - private void setItemScrollViewHeight(int size) { - // 添加条目过多的时候控制高度 - if (size >= 7) { - LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) sLayoutContent.getLayoutParams(); - params.height = PxUtils.getScreenHeight(mContext) / 2; - sLayoutContent.setLayoutParams(params); + /** + * 设置底部弹出对话框item文字大小 + * + * @param size 大小 + * @return Builder + */ + public Builder setBottomItemTextSize(float size) { + this.bottomItemTextSize = size; + return this; } - } - /** - * 得到 加减模式下 输入框的值 - * - * @return int - */ - private int getCountEdtValue() { - int count = 0; - String text = edtCount.getText().toString().trim(); - if (!TextUtils.isEmpty(text)) { - count = Integer.parseInt(text); + ////////////////////////////////////////输入框设置//////////////////////////////////////////// + + /** + * 设置输入框默认文字 + * + * @param text 默认文字 + * @return Builder + */ + public Builder setInputDefaultText(String text) { + this.inputDefaultText = text; + return this; } - return count; - } - /** - * 加减模式下输入框的监听 - */ - private TextWatcher textWatcher = new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { + /** + * 设置Hint文字 + * + * @param text Hint 文字 + * @return Builder + */ + public Builder setInputHintText(String text) { + this.inputHintText = text; + return this; + } + /** + * 设置输入框文字颜色 + * + * @param color 文字颜色 + * @return Builder + */ + public Builder setInputTextColor(@ColorInt int color) { + this.inputTextColor = color; + return this; } - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { + /** + * 设置输入框Hint文字颜色 + * + * @param color Hint文字颜色 + * @return Builder + */ + public Builder setInputHintTextColor(@ColorInt int color) { + this.inputHintTextColor = color; + return this; + } + /** + * 设置输入框文字大小 + * + * @param size 大小 + * @return Builder + */ + public Builder setInputTextSize(float size) { + this.inputTextSize = size; + return this; } - @Override - public void afterTextChanged(Editable s) { - if (!TextUtils.isEmpty(s.toString().trim())) { - edtCount.removeTextChangedListener(textWatcher); - int text = Integer.parseInt(s.toString()); - if (text < minCount) { - edtCount.setText(String.valueOf(minCount)); - } else if (text > maxCount) { - edtCount.setText(String.valueOf(maxCount)); - } - edtCount.setSelection(edtCount.getText().length()); - edtCount.addTextChangedListener(textWatcher); - judgeTheViews(Integer.parseInt(edtCount.getText().toString().trim())); - } else { - //删光了 减 按钮不可点击 - ivMinus.setImageResource(R.drawable.input_minus_disabled); - } + /** + * 设置输入框输入监听 + * + * @param textWatcher 监听 + * @return Builder + */ + public Builder setTextWatcher(TextWatcher textWatcher) { + this.textWatcher = textWatcher; + return this; + } + ////////////////////////////////////////其他设置//////////////////////////////////////////// + + /** + * 替换整个Dialog 内容 + * + * @param view view + * @return Builder + */ + public Builder addAllDialogView(View view) { + this.allDialogView = view; + this.type = DialogType.REPLACE_ALL; + return this; } - }; - /** - * 按钮被点击事件回调 - */ - public interface OnButtonClickListener { - void onClick(String val); - } + /** + * 替换中间部分View + * + * @param view view + * @return Builder + */ + public Builder addContentView(View view) { + this.contentView = view; + this.type = DialogType.REPLACE_CONTENT; + return this; + } - /** - * 底部弹出对话框条目被点击 - */ - public interface OnItemClickListener { - void onItemClick(int position); + /** + * 替换底部弹出的View + * + * @param view view + * @return Builder + */ + public Builder setBottomView(View view) { + this.bottomView = view; + this.type = DialogType.REPLACE_BOTTOM; + return this; + } + + /** + * 是否可取消 + * + * @param cancelable 可取消 + * @return Builder + */ + public Builder setCancelable(boolean cancelable) { + this.cancelable = cancelable; + return this; + } + + /** + * 点击对话框周围是否可取消 + * + * @param canceledOnTouchOutside 可取消 + * @return Builder + */ + public Builder setCanceledOnTouchOutside(boolean canceledOnTouchOutside) { + this.canceledOnTouchOutside = canceledOnTouchOutside; + return this; + } + + /** + * 对话框消失监听 + * + * @param dialogDismissListener 监听 + * @return Builder + */ + public Builder setDialogDismissListener(DialogInterface.OnDismissListener dialogDismissListener) { + this.dialogDismissListener = dialogDismissListener; + return this; + } + + /** + * 创建对话框 + * + * @return AppDialog + */ + public AppDialog create() { + return new AppDialog(this); + } } + } \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/widget/dialog/DateDialog.java b/common_base/src/main/java/com/wss/common/widget/dialog/DateDialog.java new file mode 100644 index 0000000..4587935 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/widget/dialog/DateDialog.java @@ -0,0 +1,261 @@ +package com.wss.common.widget.dialog; + +import android.annotation.SuppressLint; +import android.app.Dialog; +import android.content.Context; +import android.view.Gravity; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; + +import com.bigkoo.pickerview.adapter.ArrayWheelAdapter; +import com.contrarywind.view.WheelView; +import com.wss.common.base.R; +import com.wss.common.base.R2; +import com.wss.common.utils.DateUtils; +import com.wss.common.utils.PxUtils; +import com.wss.common.utils.ValidUtils; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; + + +/** + * Describe:自定义选择日期对话框,适用于在PopupWindow之上弹出 + * Created by 吴天强 on 2019年7月27日18:13:09 + */ +@SuppressLint("DefaultLocale") +public class DateDialog { + + + private static final int DEFAULT_START_YEAR = 1900; + private static final int DEFAULT_END_YEAR = 2100; + + + @BindView(R2.id.wv_year) + WheelView wvYear; + + @BindView(R2.id.wv_month) + WheelView wvMonth; + + @BindView(R2.id.wv_day) + WheelView wvDay; + + private Dialog dialog; + private int startYear = DEFAULT_START_YEAR; + private int endYear = DEFAULT_END_YEAR; + private List yearList = new ArrayList<>(); + private List monthList = new ArrayList<>(); + private List dayList = new ArrayList<>(); + /** + * 当前年份下标 + */ + private int yearPosition = 0; + /** + * 当前月份下标 + */ + private int monthPosition = 0; + /** + * 当前日下标 + */ + private int dayPosition = 0; + /** + * 默认显示的日期 yyyy-MM-dd + */ + private String defaultDate = DateUtils.getCurrentDateStr(); + private OnDateSelectListener dateSelectListener; + /** + * 切换过日期 + */ + private boolean changeDay = false; + + public DateDialog(Context context) { + View dialogView = View.inflate(context, R.layout.dailog_date, null); + ButterKnife.bind(this, dialogView); + //底部弹出对话框 + dialog = new Dialog(context, R.style.ActionSheetDialogStyle); + dialogView.setMinimumWidth(PxUtils.getScreenWidth(context)); + dialog.setContentView(dialogView); + Window window = dialog.getWindow(); + if (window != null) { + window.getAttributes().gravity = Gravity.BOTTOM; + WindowManager.LayoutParams lp = window.getAttributes(); + lp.x = 0; + lp.y = 0; + window.setAttributes(lp); + } + } + + /** + * 日期选择回调 + */ + public DateDialog setOnDateSelectListener(OnDateSelectListener dateSelectListener) { + this.dateSelectListener = dateSelectListener; + return this; + } + + /** + * 设置开始 结束年份 + */ + public DateDialog setYearStartEnd(int startYear, int endYear) { + this.startYear = startYear; + this.endYear = endYear; + return this; + } + + /** + * 设置当前日期 格式yyyy-MM-dd + */ + public DateDialog setCurrentDate(String date) { + if (ValidUtils.isValid(date)) { + this.defaultDate = date; + } + return this; + } + + private void initView() { + initData(); + //设置"年"的显示数据 + wvYear.setAdapter(new ArrayWheelAdapter<>(yearList)); + // 初始化时显示的数据 + wvYear.setCurrentItem(yearPosition); + wvYear.setOnItemSelectedListener(index -> { + yearPosition = index; + initDayDate(); + }); + wvMonth.setAdapter(new ArrayWheelAdapter<>(monthList)); + wvMonth.setCurrentItem(monthPosition); + wvMonth.setOnItemSelectedListener(index -> { + monthPosition = index; + initDayDate(); + }); + initDayDate(); + } + + /** + * 初始化年份 月份数据 + */ + private void initData() { + yearList.clear(); + monthList.clear(); + String year = DateUtils.getFormatDate(defaultDate, "yyyy"); + String month = DateUtils.getFormatDate(defaultDate, "MM"); + int yearIndex = 0; + for (int i = startYear; i < endYear + 1; i++) { + yearList.add(String.format("%s年", i)); + if (i == Integer.parseInt(year)) { + yearPosition = yearIndex; + } + yearIndex++; + } + for (int i = 1; i < 12 + 1; i++) { + monthList.add(String.format("%02d月", i)); + if (i == Integer.parseInt(month)) { + monthPosition = i - 1; + } + } + } + + /** + * 初始化日数据 + */ + private void initDayDate() { + dayList.clear(); + int maxDay = 31; + String monthString = monthList.get(monthPosition); + switch (Integer.parseInt(monthString.substring(0, monthString.length() - 1))) { + case 2: + String yearString = yearList.get(yearPosition); + int year = Integer.parseInt(yearString.substring(0, yearString.length() - 1)); + maxDay = isLeapYear(year) ? 28 : 29; + break; + case 4: + case 5: + case 6: + case 8: + case 9: + case 11: + maxDay = 30; + break; + default: + break; + } + String day = DateUtils.getFormatDate(defaultDate, "dd"); + for (int i = 1; i < maxDay + 1; i++) { + dayList.add(String.format("%02d日", i)); + if (!changeDay && i == Integer.parseInt(day)) { + dayPosition = i - 1; + } + } + wvDay.setAdapter(new ArrayWheelAdapter<>(dayList)); + wvDay.setCurrentItem(dayPosition); + wvDay.setOnItemSelectedListener(index -> { + changeDay = true; + dayPosition = index; + }); + } + + /** + * 是否闰年 + * + * @param year 年份 + * @return boolean + */ + @Contract(pure = true) + private boolean isLeapYear(int year) { + return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; + } + + private boolean isShowing() { + return dialog != null && dialog.isShowing(); + } + + /** + * 显示对话框 + */ + public void show() { + if (!isShowing()) { + initView(); + dialog.show(); + } + } + + + @OnClick({R2.id.btnCancel, R2.id.btnSubmit}) + public void onViewClicked(@NotNull View view) { + if (view.getId() == R.id.btnSubmit) { + if (dateSelectListener != null) { + String yearString = yearList.get(yearPosition); + String monthString = monthList.get(monthPosition); + String dayString = dayList.get(dayPosition); + dateSelectListener.selectDate( + yearString.substring(0, yearString.length() - 1), + monthString.substring(0, monthString.length() - 1), + dayString.substring(0, dayString.length() - 1)); + } + + } + dialog.dismiss(); + } + + /** + * 日期选择监听器 + */ + public interface OnDateSelectListener { + /** + * 日期选择了 + * + * @param year 年 + * @param month 月 + * @param day 日 + */ + void selectDate(String year, String month, String day); + } +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/widget/dialog/DialogType.java b/common_base/src/main/java/com/wss/common/widget/dialog/DialogType.java index 05bbb0b..cd8de09 100644 --- a/common_base/src/main/java/com/wss/common/widget/dialog/DialogType.java +++ b/common_base/src/main/java/com/wss/common/widget/dialog/DialogType.java @@ -1,25 +1,48 @@ package com.wss.common.widget.dialog; -import android.support.annotation.IntDef; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import androidx.annotation.IntDef; + /** * Describe:对话框类型 * Created by 吴天强 on 2018/10/26. */ - public interface DialogType { - @IntDef({DEFAULT, INPUT, COUNT, NO_TITLE, BOTTOM_IN}) + @IntDef({DEFAULT, NO_TITLE, INPUT, BOTTOM_IN, REPLACE_ALL, REPLACE_CONTENT, REPLACE_BOTTOM}) @Retention(RetentionPolicy.SOURCE) @interface Type { } + /** + * 常规 + */ int DEFAULT = 0; - int INPUT = 1; - int COUNT = 2; - int NO_TITLE = 3; - int BOTTOM_IN = 4; + /** + * 没有Title + */ + int NO_TITLE = 1; + /** + * 带输入框 + */ + int INPUT = 2; + /** + * 底部进来 + */ + int BOTTOM_IN = 3; + /** + * 替换全部 + */ + int REPLACE_ALL = 4; + /** + * 替换content + */ + int REPLACE_CONTENT = 5; + /** + * 替换底部弹出 + */ + int REPLACE_BOTTOM = 6; } diff --git a/common_base/src/main/java/com/wss/common/widget/dialog/LoadingDialog.java b/common_base/src/main/java/com/wss/common/widget/dialog/LoadingDialog.java index f29a77b..0ed0be5 100644 --- a/common_base/src/main/java/com/wss/common/widget/dialog/LoadingDialog.java +++ b/common_base/src/main/java/com/wss/common/widget/dialog/LoadingDialog.java @@ -11,7 +11,7 @@ /** - * 等待对话框 + * 加载框 * Created by wtq on 2016/3/14. */ public class LoadingDialog { @@ -19,7 +19,7 @@ public class LoadingDialog { private LVCircularRing mLoadingView; private Dialog mLoadingDialog; private Context context; - private String msg = "加载中···"; + private String msg = "加载中…"; private boolean cancelable = true; private boolean isShow; @@ -29,6 +29,9 @@ public LoadingDialog(Context context) { /** * 设置提示信息 + * + * @param msg 提示信息 + * @return dialog */ public LoadingDialog setTitleText(String msg) { this.msg = msg; @@ -36,7 +39,10 @@ public LoadingDialog setTitleText(String msg) { } /** - * 返回键是否可用 + * 设置dialog是否可以取消 + * + * @param cancelable 是否可取消 + * @return dialog */ public LoadingDialog setCancelable(boolean cancelable) { this.cancelable = cancelable; diff --git a/common_base/src/main/java/com/wss/common/widget/dialog/OnButtonClickListener.java b/common_base/src/main/java/com/wss/common/widget/dialog/OnButtonClickListener.java new file mode 100644 index 0000000..4f30a70 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/widget/dialog/OnButtonClickListener.java @@ -0,0 +1,15 @@ +package com.wss.common.widget.dialog; + +/** + * Describe:对话框按钮被点击事件 + * Created by 吴天强 on 2019/3/31. + */ +public interface OnButtonClickListener { + + /** + * 点击事件 + * + * @param val 值 + */ + void onClick(String val); +} diff --git a/common_base/src/main/java/com/wss/common/widget/dialog/OnItemClickListener.java b/common_base/src/main/java/com/wss/common/widget/dialog/OnItemClickListener.java new file mode 100644 index 0000000..7047091 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/widget/dialog/OnItemClickListener.java @@ -0,0 +1,16 @@ +package com.wss.common.widget.dialog; + +/** + * Describe:多条目对话框Item被点击事件 + * Created by 吴天强 on 2019/3/31. + */ +public interface OnItemClickListener { + + /** + * 点击事件 + * + * @param position position + * @param val 值 + */ + void onItemClick(int position, String val); +} diff --git a/common_base/src/main/java/com/wss/common/widget/dialog/ProgressBarDialog.java b/common_base/src/main/java/com/wss/common/widget/dialog/ProgressBarDialog.java new file mode 100644 index 0000000..3126570 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/widget/dialog/ProgressBarDialog.java @@ -0,0 +1,121 @@ +package com.wss.common.widget.dialog; + +import android.content.Context; +import android.view.View; +import android.widget.TextView; + +import com.wss.common.base.R; +import com.wss.common.utils.ValidUtils; +import com.wss.common.widget.NumberProgressBar; + +/** + * Describe:带进度条的加载框 + * Created by 吴天强 on 2021/5/10. + */ +public class ProgressBarDialog { + private AppDialog progressDialog; + private NumberProgressBar progressBar; + private Builder builder; + + private ProgressBarDialog() { + } + + private ProgressBarDialog(Builder builder) { + this.builder = builder; + } + + /** + * 设置进度 + * + * @param progress 进度值 + */ + public void setProgress(int progress) { + if (progressBar != null) { + progressBar.setProgress(progress); + } + } + + /** + * 显示加载库 + */ + public void show() { + View progressView = View.inflate(builder.context, R.layout.dialog_progressbar, null); + progressBar = progressView.findViewById(R.id.number_progress); + if (ValidUtils.isValid(builder.loadingText)) { + ((TextView) progressView.findViewById(R.id.tv_loading_text)).setText(builder.loadingText); + } + progressBar.setProgress(0); + progressDialog = new AppDialog.Builder(builder.context) + .addAllDialogView(progressView) + .setCancelable(builder.cancelable) + .create(); + progressDialog.show(); + } + + /** + * 关闭对话框 + */ + public void dismiss() { + if (progressDialog != null) { + progressDialog.dismiss(); + progressDialog = null; + } + } + + /** + * Describe:对话框建造者 + * Created by 吴天强 on 2018年9月27日 + */ + public static class Builder { + Context context; + /** + * 加载Text + */ + String loadingText; + /** + * 是否可以取消 + */ + boolean cancelable; + + /** + * 初始化 + * + * @param context 上下文 + */ + public Builder(Context context) { + this.context = context; + } + + /** + * 设置对话框内容 + * + * @param loadingText 加载文案 + * @return Builder + */ + public Builder setLoadingText(String loadingText) { + this.loadingText = loadingText; + return this; + } + + /** + * 是否可取消 + * + * @param cancelable 可取消 + * @return Builder + */ + public Builder setCancelable(boolean cancelable) { + this.cancelable = cancelable; + return this; + } + + + /** + * 创建对话框 + * + * @return AppDialog + */ + public ProgressBarDialog create() { + return new ProgressBarDialog(this); + } + } +} diff --git a/common_base/src/main/java/com/wss/common/widget/manager/ScrollSpeedLinearLayoutManger.java b/common_base/src/main/java/com/wss/common/widget/manager/ScrollSpeedLinearLayoutManger.java new file mode 100644 index 0000000..9dd5957 --- /dev/null +++ b/common_base/src/main/java/com/wss/common/widget/manager/ScrollSpeedLinearLayoutManger.java @@ -0,0 +1,79 @@ +package com.wss.common.widget.manager; + +import android.content.Context; +import android.graphics.PointF; +import android.util.DisplayMetrics; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.LinearSmoothScroller; +import androidx.recyclerview.widget.RecyclerView; + +/** + * Describe:带效果的RecyclerView LinearLayoutManager滚动指定位置 + * Created by 吴天强 on 2019/5/14. + */ +public class ScrollSpeedLinearLayoutManger extends LinearLayoutManager { + + /** + * 滚动速度因子 + */ + private float speed = 0.3f; + + public ScrollSpeedLinearLayoutManger(Context context) { + super(context, VERTICAL, false); + } + + public ScrollSpeedLinearLayoutManger(Context context, int orientation, boolean reverseLayout) { + super(context, orientation, reverseLayout); + } + + /** + * 设置滚动速度因子 越大越快 越小越慢 取值在0.1~1.0之间即可 + * + * @param speed 速度因子 + */ + public ScrollSpeedLinearLayoutManger setSpeed(float speed) { + if (speed < 0 && speed < 1) { + this.speed = speed; + } + return this; + } + + @Override + public void smoothScrollToPosition(@NonNull RecyclerView recyclerView, RecyclerView.State state, int position) { + RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext()); + smoothScroller.setTargetPosition(position); + startSmoothScroll(smoothScroller); + } + + private class CenterSmoothScroller extends LinearSmoothScroller { + + CenterSmoothScroller(Context context) { + super(context); + } + + @Nullable + @Override + public PointF computeScrollVectorForPosition(int targetPosition) { + return ScrollSpeedLinearLayoutManger.this.computeScrollVectorForPosition(targetPosition); + } + + @Override + public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) { + return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2); + } + + @Override + protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { + return speed; + } + + @Override + protected int getVerticalSnapPreference() { + return SNAP_TO_START; + } + } + +} \ No newline at end of file diff --git a/common_base/src/main/java/com/wss/common/widget/pulltorefresh/IRefreshView.java b/common_base/src/main/java/com/wss/common/widget/pulltorefresh/IRefreshView.java deleted file mode 100644 index 5a7367e..0000000 --- a/common_base/src/main/java/com/wss/common/widget/pulltorefresh/IRefreshView.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.wss.common.widget.pulltorefresh; - -import android.view.View; - -/** - * 刷新view - */ -public interface IRefreshView { - - /** - * 开始下拉 - */ - void begin(); - - /** - * 回调的精度,单位为px - * - * @param progress 当前高度 - * @param all 总高度 为默认高度的2倍 - */ - void progress(float progress, float all); - - void finishing(float progress, float all); - - /** - * 下拉完毕 - */ - void loading(); - - /** - * 看不见的状态 - */ - void normal(); - - /** - * 返回当前视图 - */ - View getView(); - - void setType(boolean refresh); - -} diff --git a/common_base/src/main/java/com/wss/common/widget/pulltorefresh/OnPullRefreshListener.java b/common_base/src/main/java/com/wss/common/widget/pulltorefresh/OnPullRefreshListener.java deleted file mode 100644 index 932f21d..0000000 --- a/common_base/src/main/java/com/wss/common/widget/pulltorefresh/OnPullRefreshListener.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.wss.common.widget.pulltorefresh; - - -/** - * 刷新 加载监听 - */ -public interface OnPullRefreshListener { - - - /** - * 刷新 - */ - void onRefresh(); - - /** - * 加载更多 - */ - void onLoadMore(); -} diff --git a/common_base/src/main/java/com/wss/common/widget/pulltorefresh/PullToRefreshLayout.java b/common_base/src/main/java/com/wss/common/widget/pulltorefresh/PullToRefreshLayout.java deleted file mode 100644 index 079311b..0000000 --- a/common_base/src/main/java/com/wss/common/widget/pulltorefresh/PullToRefreshLayout.java +++ /dev/null @@ -1,586 +0,0 @@ -package com.wss.common.widget.pulltorefresh; - -import android.animation.ValueAnimator; -import android.content.Context; -import android.content.res.TypedArray; -import android.support.v4.view.ViewCompat; -import android.util.AttributeSet; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.widget.FrameLayout; - -import com.wss.common.base.R; -import com.wss.common.utils.PxUtils; - - -/** - * 下拉刷新 上拉加载更多控件 - */ -public class PullToRefreshLayout extends FrameLayout { - - private IRefreshView mHeaderView; - private IRefreshView mFooterView; - private View mChildView; - - private static final long ANIM_TIME = 300; - private static int HEAD_HEIGHT = 60; - private static int FOOT_HEIGHT = 60; - - private static int head_height; - private static int head_height_2; - private static int foot_height; - private static int foot_height_2; - - private float mTouchY; - private float mCurrentY; - - private boolean canLoadMore = true; - private boolean canRefresh = true; - private boolean isRefresh; - private boolean isLoadMore; - - //滑动的最小距离 - private int mTouchSlope; - - private OnPullRefreshListener refreshListener; - - - private View loadingView, errorView, emptyView; - private int loading = R.layout.layout_loading, empty = R.layout.layout_empty, error = R.layout.layout_error; - - public void setOnPullRefreshListener(OnPullRefreshListener refreshListener) { - this.refreshListener = refreshListener; - } - - public PullToRefreshLayout(Context context) { - this(context, null); - } - - public PullToRefreshLayout(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public PullToRefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PullToRefreshLayout, defStyleAttr, 0); - error = a.getResourceId(R.styleable.PullToRefreshLayout_view_error, error); - loading = a.getResourceId(R.styleable.PullToRefreshLayout_view_loading, loading); - empty = a.getResourceId(R.styleable.PullToRefreshLayout_view_empty, empty); - a.recycle(); - init(); - } - - private void cal() { - head_height = PxUtils.dp2px(getContext(), HEAD_HEIGHT); - foot_height = PxUtils.dp2px(getContext(), FOOT_HEIGHT); - head_height_2 = PxUtils.dp2px(getContext(), HEAD_HEIGHT * 2); - foot_height_2 = PxUtils.dp2px(getContext(), FOOT_HEIGHT * 2); - - mTouchSlope = ViewConfiguration.get(getContext()).getScaledTouchSlop(); - } - - private void init() { - cal(); - int count = getChildCount(); - if (count != 1) { - new IllegalArgumentException("child only can be one"); - } - - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mChildView = getChildAt(0); - addHeadView(); - addFooterView(); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - - } - - private void addHeadView() { - if (mHeaderView == null) { - mHeaderView = new RefreshView(getContext()); - } else { - removeView(mHeaderView.getView()); - } - LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0); - mHeaderView.getView().setLayoutParams(layoutParams); - if (mHeaderView.getView().getParent() != null) - ((ViewGroup) mHeaderView.getView().getParent()).removeAllViews(); - addView(mHeaderView.getView(), 0); - } - - private void addFooterView() { - if (mFooterView == null) { - mFooterView = new RefreshView(getContext()); - mFooterView.setType(false); - } else { - removeView(mFooterView.getView()); - } - LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0); - layoutParams.gravity = Gravity.BOTTOM; - mFooterView.getView().setLayoutParams(layoutParams); - if (mFooterView.getView().getParent() != null) - ((ViewGroup) mFooterView.getView().getParent()).removeAllViews(); - addView(mFooterView.getView()); - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - if (!canLoadMore && !canRefresh) return super.onInterceptTouchEvent(ev); - switch (ev.getAction()) { - case MotionEvent.ACTION_DOWN: - mTouchY = ev.getY(); - mCurrentY = mTouchY; - break; - case MotionEvent.ACTION_MOVE: - float currentY = ev.getY(); - float dy = currentY - mCurrentY; - if (canRefresh) { - boolean canChildScrollUp = canChildScrollUp(); - if (dy > mTouchSlope && !canChildScrollUp) { - mHeaderView.begin(); - return true; - } - } - if (canLoadMore) { - boolean canChildScrollDown = canChildScrollDown(); - if (dy < -mTouchSlope && !canChildScrollDown) { - mFooterView.begin(); - return true; - } - } - } - return super.onInterceptTouchEvent(ev); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (isRefresh || isLoadMore) return true; - switch (event.getAction()) { - case MotionEvent.ACTION_MOVE: - mCurrentY = event.getY(); - float dura = (mCurrentY - mTouchY) / 3.0f; - if (dura > 0 && canRefresh) { - dura = Math.min(head_height_2, dura); - dura = Math.max(0, dura); - mHeaderView.getView().getLayoutParams().height = (int) dura; - ViewCompat.setTranslationY(mChildView, dura); - requestLayout(); - mHeaderView.progress(dura, head_height); - } else { - if (canLoadMore) { - dura = Math.min(foot_height_2, Math.abs(dura)); - dura = Math.max(0, Math.abs(dura)); - mFooterView.getView().getLayoutParams().height = (int) dura; - ViewCompat.setTranslationY(mChildView, -dura); - requestLayout(); - mFooterView.progress(dura, foot_height); - } - } - return true; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - float currentY = event.getY(); - final int dy1 = (int) (currentY - mTouchY) / 3; - if (dy1 > 0 && canRefresh) { - if (dy1 >= head_height) { - createAnimatorTranslationY(State.REFRESH, - dy1 > head_height_2 ? head_height_2 : dy1, head_height, - new CallBack() { - @Override - public void onSuccess() { - isRefresh = true; - if (refreshListener != null) { - refreshListener.onRefresh(); - } - mHeaderView.loading(); - } - }); - } else if (dy1 > 0 && dy1 < head_height) { - setFinish(dy1, State.REFRESH); - mHeaderView.normal(); - } - } else { - if (canLoadMore) { - if (Math.abs(dy1) >= foot_height) { - createAnimatorTranslationY(State.LOAD_MORE, Math.abs(dy1) > foot_height_2 ? foot_height_2 : Math.abs(dy1), foot_height, new CallBack() { - @Override - public void onSuccess() { - isLoadMore = true; - if (refreshListener != null) { - refreshListener.onLoadMore(); - } - mFooterView.loading(); - } - }); - } else { - setFinish(Math.abs(dy1), State.LOAD_MORE); - mFooterView.normal(); - } - } - } - break; - } - return super.onTouchEvent(event); - } - - private boolean canChildScrollDown() { - return mChildView != null && ViewCompat.canScrollVertically(mChildView, 1); - } - - private boolean canChildScrollUp() { - return mChildView != null && ViewCompat.canScrollVertically(mChildView, -1); - } - - /** - * 创建动画 - */ - public void createAnimatorTranslationY(@State.REFRESH_STATE final int state, final int start, - final int purpose, final CallBack callBack) { - final ValueAnimator anim; - anim = ValueAnimator.ofInt(start, purpose); - anim.setDuration(ANIM_TIME); - anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator valueAnimator) { - int value = (int) valueAnimator.getAnimatedValue(); - if (state == State.REFRESH) { - mHeaderView.getView().getLayoutParams().height = value; - ViewCompat.setTranslationY(mChildView, value); - if (purpose == 0) { //代表结束加载 - mHeaderView.finishing(value, head_height_2); - } else { - mHeaderView.progress(value, head_height); - } - } else { - mFooterView.getView().getLayoutParams().height = value; - ViewCompat.setTranslationY(mChildView, -value); - if (purpose == 0) { //代表结束加载 - mFooterView.finishing(value, head_height_2); - } else { - mFooterView.progress(value, foot_height); - } - } - if (value == purpose) { - if (callBack != null) - callBack.onSuccess(); - } - requestLayout(); - - - } - - }); - anim.start(); - } - - /** - * 结束下拉刷新 - */ - private void setFinish(int height, @State.REFRESH_STATE final int state) { - createAnimatorTranslationY(state, height, 0, new CallBack() { - @Override - public void onSuccess() { - if (state == State.REFRESH) { - isRefresh = false; - mHeaderView.normal(); - - } else { - isLoadMore = false; - mFooterView.normal(); - } - } - }); - } - - private void setFinish(@State.REFRESH_STATE int state) { - if (state == State.REFRESH) { - if (mHeaderView != null && mHeaderView.getView().getLayoutParams().height > 0 && isRefresh) { - setFinish(head_height, state); - } - } else { - if (mFooterView != null && mFooterView.getView().getLayoutParams().height > 0 && isLoadMore) { - setFinish(foot_height, state); - } - } - } - - public interface CallBack { - void onSuccess(); - } - - private void showLoadingView() { - if (loadingView == null) { - loadingView = LayoutInflater.from(getContext()).inflate(loading, null); - LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT); - addView(loadingView, layoutParams); - } else { - loadingView.setVisibility(VISIBLE); - } - } - - private void showEmptyView() { - if (emptyView == null) { - emptyView = LayoutInflater.from(getContext()).inflate(empty, null); - LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT); - addView(emptyView, layoutParams); - } else { - emptyView.setVisibility(VISIBLE); - } - } - - private void showErrorView() { - if (errorView == null) { - errorView = LayoutInflater.from(getContext()).inflate(error, null); - LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT); - addView(errorView, layoutParams); - } else { - errorView.setVisibility(VISIBLE); - } - } - - private void hideView(View view) { - if (view != null) - view.setVisibility(GONE); - } - - private void switchView(int status) { - switch (status) { - case ViewStatus.CONTENT_STATUS: - hideView(loadingView); - hideView(emptyView); - hideView(errorView); - - mChildView.setVisibility(VISIBLE); - break; - case ViewStatus.LOADING_STATUS: - hideView(mChildView); - hideView(emptyView); - hideView(errorView); - - showLoadingView(); - break; - case ViewStatus.EMPTY_STATUS: - hideView(mChildView); - hideView(loadingView); - hideView(errorView); - - showEmptyView(); - break; - case ViewStatus.ERROR_STATUS: - hideView(mChildView); - hideView(loadingView); - hideView(emptyView); - - showErrorView(); - break; - default: - hideView(loadingView); - hideView(emptyView); - hideView(errorView); - - mChildView.setVisibility(VISIBLE); - break; - } - } - - /** - * 设置展示view (error,empty,loading) - */ - public void showView(@ViewStatus.VIEW_STATUS int status) { - switchView(status); - } - - /** - * 获取view (error,empty,loading) - */ - public View getView(@ViewStatus.VIEW_STATUS int status) { - switch (status) { - case ViewStatus.EMPTY_STATUS: - return emptyView; - case ViewStatus.LOADING_STATUS: - return loadingView; - case ViewStatus.ERROR_STATUS: - return errorView; - case ViewStatus.CONTENT_STATUS: - return mChildView; - } - return null; - } - - public void autoRefresh() { - createAnimatorTranslationY(State.REFRESH, - 0, head_height, - new CallBack() { - @Override - public void onSuccess() { - isRefresh = true; - if (refreshListener != null) { - refreshListener.onRefresh(); - } - mHeaderView.loading(); - } - }); - } - - /** - * 结束刷新 - */ - public void finishRefresh() { - setFinish(State.REFRESH); - } - - /** - * 结束加载更多 - */ - public void finishLoadMore() { - setFinish(State.LOAD_MORE); - } - - /** - * 设置是否启用加载更多 - */ - public void setCanLoadMore(boolean canLoadMore) { - this.canLoadMore = canLoadMore; - } - - /** - * 设置是否启用下拉刷新 - */ - public void setCanRefresh(boolean canRefresh) { - this.canRefresh = canRefresh; - } - - /** - * 设置是下拉刷新头部 - * - * @param mHeaderView 需实现 HeadView 接口 - */ - public void setHeaderView(IRefreshView mHeaderView) { - this.mHeaderView = mHeaderView; - addHeadView(); - } - - /** - * 设置是下拉刷新尾部 - * - * @param mFooterView 需实现 IRefreshView 接口 - */ - public void setFooterView(IRefreshView mFooterView) { - this.mFooterView = mFooterView; - addFooterView(); - } - - - /** - * 设置刷新控件的高度 - * - * @param dp 单位为dp - */ - public void setHeadHeight(int dp) { - head_height = PxUtils.dp2px(getContext(), dp); - } - - /** - * 设置加载更多控件的高度 - * - * @param dp 单位为dp - */ - public void setFootHeight(int dp) { - foot_height = PxUtils.dp2px(getContext(), dp); - } - - /** - * 同时设置加载更多控件和刷新控件的高度 - * - * @param dp 单位为dp - */ - public void setAllHeight(int dp) { - head_height = PxUtils.dp2px(getContext(), dp); - foot_height = PxUtils.dp2px(getContext(), dp); - } - - /** - * 同时设置加载更多控件和刷新控件的高度 - * - * @param refresh 刷新控件的高度 单位为dp - * @param loadMore 加载控件的高度 单位为dp - */ - public void setAllHeight(int refresh, int loadMore) { - head_height = PxUtils.dp2px(getContext(), refresh); - foot_height = PxUtils.dp2px(getContext(), loadMore); - } - - /** - * 设置刷新控件的下拉的最大高度 且必须大于本身控件的高度 最佳为2倍 - * - * @param dp 单位为dp - */ - public void setMaxHeadHeight(int dp) { - if (head_height >= PxUtils.dp2px(getContext(), dp)) { - return; - } - head_height_2 = PxUtils.dp2px(getContext(), dp); - } - - /** - * 设置加载更多控件的上拉的最大高度 且必须大于本身控件的高度 最佳为2倍 - * - * @param dp 单位为dp - */ - public void setMaxFootHeight(int dp) { - if (foot_height >= PxUtils.dp2px(getContext(), dp)) { - return; - } - foot_height_2 = PxUtils.dp2px(getContext(), dp); - } - - /** - * 同时设置加载更多控件和刷新控件的最大高度 且必须大于本身控件的高度 最佳为2倍 - * - * @param dp 单位为dp - */ - public void setAllMaxHeight(int dp) { - if (head_height >= PxUtils.dp2px(getContext(), dp)) { - return; - } - if (foot_height >= PxUtils.dp2px(getContext(), dp)) { - return; - } - head_height_2 = PxUtils.dp2px(getContext(), dp); - foot_height_2 = PxUtils.dp2px(getContext(), dp); - } - - /** - * 同时设置加载更多控件和刷新控件的最大高度 且必须大于本身控件的高度 最佳为2倍 - * - * @param refresh 刷新控件下拉的最大高度 单位为dp - * @param loadMore 加载控件上拉的最大高度 单位为dp - */ - public void setAllMaxHeight(int refresh, int loadMore) { - if (head_height >= PxUtils.dp2px(getContext(), refresh)) { - return; - } - if (foot_height >= PxUtils.dp2px(getContext(), loadMore)) { - return; - } - head_height_2 = PxUtils.dp2px(getContext(), refresh); - foot_height_2 = PxUtils.dp2px(getContext(), loadMore); - } - - -} diff --git a/common_base/src/main/java/com/wss/common/widget/pulltorefresh/RefreshView.java b/common_base/src/main/java/com/wss/common/widget/pulltorefresh/RefreshView.java deleted file mode 100644 index 2c340e3..0000000 --- a/common_base/src/main/java/com/wss/common/widget/pulltorefresh/RefreshView.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.wss.common.widget.pulltorefresh; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.TextView; - -import com.wss.common.base.R; -import com.wss.common.widget.LVCircularRing; - - -/** - * 刷新控件 - */ -public class RefreshView extends FrameLayout implements IRefreshView { - - private TextView tv; - private ImageView arrow; - // private ProgressBar progressBar; - private LVCircularRing lvCircularRing; - private boolean refresh = false;//是否是刷新 - - public RefreshView(Context context) { - this(context, null); - } - - public RefreshView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public RefreshView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(context); - } - - @Override - public void setType(boolean refresh) { - this.refresh = refresh; - } - - - private void init(Context context) { - View childView = View.inflate(context, R.layout.layout_refresh_view, null); - addView(childView); - tv = childView.findViewById(R.id.header_tv); - arrow = childView.findViewById(R.id.header_arrow); - lvCircularRing = childView.findViewById(R.id.header_progress); - } - - @Override - public void begin() { - - } - - @Override - public void progress(float progress, float all) { - float s = progress / all; - if (s >= 0.9f) { - arrow.setRotation(180); - } else { - arrow.setRotation(0); - } - if (progress >= all - 10) { - tv.setText(refresh ? R.string.pull_loose_refreshing : R.string.pull_loose_load_more); - } else { - tv.setText(refresh ? R.string.pull_down_refresh : R.string.pull_up_loading); - } - } - - @Override - public void finishing(float progress, float all) { - lvCircularRing.stopAnim(); - } - - @Override - public void loading() { - arrow.setVisibility(GONE); - lvCircularRing.setVisibility(VISIBLE); - lvCircularRing.startAnim(); - tv.setText(R.string.loading); - } - - @Override - public void normal() { - arrow.setVisibility(VISIBLE); - lvCircularRing.setVisibility(GONE); - lvCircularRing.stopAnim(); - tv.setText(refresh ? R.string.pull_down_refresh : R.string.pull_up_loading); - } - - @Override - public View getView() { - return this; - } -} diff --git a/common_base/src/main/java/com/wss/common/widget/pulltorefresh/State.java b/common_base/src/main/java/com/wss/common/widget/pulltorefresh/State.java deleted file mode 100644 index a7d0efb..0000000 --- a/common_base/src/main/java/com/wss/common/widget/pulltorefresh/State.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.wss.common.widget.pulltorefresh; - -import android.support.annotation.IntDef; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - - -/** - * 刷新状态 - */ -interface State { - - - @IntDef({REFRESH, LOAD_MORE}) - @Retention(RetentionPolicy.SOURCE) - @interface REFRESH_STATE { - } - - int REFRESH = 10; - int LOAD_MORE = 11; -} diff --git a/common_base/src/main/java/com/wss/common/widget/pulltorefresh/ViewStatus.java b/common_base/src/main/java/com/wss/common/widget/pulltorefresh/ViewStatus.java deleted file mode 100644 index 8dc43e6..0000000 --- a/common_base/src/main/java/com/wss/common/widget/pulltorefresh/ViewStatus.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.wss.common.widget.pulltorefresh; - -import android.support.annotation.IntDef; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - - -/** - * 加载状态 - */ -interface ViewStatus { - - @IntDef({CONTENT_STATUS, LOADING_STATUS, EMPTY_STATUS, ERROR_STATUS}) - @Retention(RetentionPolicy.SOURCE) - @interface VIEW_STATUS { - - } - - int CONTENT_STATUS = 0; - int LOADING_STATUS = 1; - int EMPTY_STATUS = 2; - int ERROR_STATUS = 3; - -} diff --git a/common_base/src/main/java/com/wss/common/widget/scaleImg/ImageViewer.java b/common_base/src/main/java/com/wss/common/widget/scaleImg/ImageViewer.java deleted file mode 100644 index a36b162..0000000 --- a/common_base/src/main/java/com/wss/common/widget/scaleImg/ImageViewer.java +++ /dev/null @@ -1,300 +0,0 @@ -package com.wss.common.widget.scaleImg; - -import android.Manifest; -import android.annotation.SuppressLint; -import android.app.Activity; -import android.app.Dialog; -import android.net.Uri; -import android.provider.MediaStore; -import android.support.v4.view.ViewPager; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import com.bumptech.glide.Glide; -import com.bumptech.glide.request.target.Target; -import com.davemorrissey.labs.subscaleview.ImageSource; -import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView; -import com.orhanobut.logger.Logger; -import com.wss.common.base.R; -import com.wss.common.utils.PermissionsUtils; -import com.wss.common.utils.ToastUtils; - -import java.io.File; -import java.io.FileNotFoundException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutionException; - -/** - * Describe:图片查看器 - * Created by 吴天强 on 2018年11月16日17:02:05 - */ - -@SuppressLint("StaticFieldLeak") -public class ImageViewer { - - private static final byte URLS = 0; - private static final byte FILES = 1; - private byte mStatus; - - private Activity mActivity; - - //图片下载器 - private ImageDownloader mImageDownloader = new ImageDownloader() { - @Override - public File downLoad(String url, Activity activity) { - File file = null; - try { - file = Glide.with(activity) - .load(url) - .downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) - .get(); - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); - Logger.e("下载图片异常" + e.getMessage()); - } - return file; - } - }; - - private List mUrls = new ArrayList<>(); - private List mFiles = new ArrayList<>(); - private List mDownloadFiles = new ArrayList<>(); - - private int mSelectedPosition; - - private Dialog mDialog; - - private ImageView imDelete; - private ImageView imDownload; - private TextView tvImageCount; - private ViewPager mViewPager; - - private List mViews; - private ImageViewerAdapter mAdapter; - - private OnDeleteItemListener mListener; - private int mStartPosition = 0;//图片起始位置 - private static ImageViewer completeImageView; - - public static ImageViewer create(Activity activity) { - if (completeImageView == null) { - completeImageView = new ImageViewer(activity); - } - return completeImageView; - } - - private ImageViewer(Activity activity) { - mActivity = activity; - } - - /** - * 设置图片下载器 - * - * @param imageDownloader 图片下载器 - * @return ImageViewer - */ - public ImageViewer setImageDownloader(ImageDownloader imageDownloader) { - mImageDownloader = imageDownloader; - return this; - } - - /** - * 加载网络图片 - * - * @param urls 图片 - * @return ImageViewer - */ - public ImageViewer setUrls(List urls) { - mUrls.addAll(urls); - mStatus = URLS; - return this; - } - - /** - * 加载网络图片 - * - * @param url 图片 - * @return ImageViewer - */ - public ImageViewer setUrl(String url) { - List urls = new ArrayList<>(); - urls.add(url); - return setUrls(urls); - } - - /** - * 设置图片起始位置 - * - * @param position 起始位置 - * @return ImageViewer - */ - public ImageViewer setPosition(int position) { - this.mStartPosition = position; - return this; - } - - /** - * 加载本地图片 - * - * @param files 图片 - * @return ImageViewer - */ - public ImageViewer setFiles(List files) { - mFiles.addAll(files); - mStatus = FILES; - return this; - } - - /** - * 加载本地图片 - * - * @param file 图片 - * @return ImageViewer - */ - public ImageViewer setFiles(File file) { - List files = new ArrayList<>(); - files.add(file); - return setFiles(files); - } - - /** - * 删除图片监听 - * - * @param listener listener - * @return ImageViewer - */ - public ImageViewer setOnDeleteItemListener(OnDeleteItemListener listener) { - mListener = listener; - return this; - } - - private void init() { - RelativeLayout relativeLayout = (RelativeLayout) View.inflate(mActivity, R.layout.dialog_scale_image, null); - ImageView close = relativeLayout.findViewById(R.id.scale_image_close); - imDelete = relativeLayout.findViewById(R.id.scale_image_delete); - imDownload = relativeLayout.findViewById(R.id.scale_image_save); - tvImageCount = relativeLayout.findViewById(R.id.scale_image_count); - mViewPager = relativeLayout.findViewById(R.id.scale_image_view_pager); - mDialog = new Dialog(mActivity, R.style.DialogFullscreen); - mDialog.setContentView(relativeLayout); - close.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - mDialog.dismiss(); - } - }); - imDelete.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - int size = mViews.size(); - mFiles.remove(mSelectedPosition); - if (mListener != null) { - mListener.onDelete(mSelectedPosition); - } - mViewPager.removeView(mViews.remove(mSelectedPosition)); - if (mSelectedPosition != size) { - int position = mSelectedPosition + 1; - String text = position + "/" + mViews.size(); - tvImageCount.setText(text); - } - mAdapter.notifyDataSetChanged(); - } - }); - imDownload.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (PermissionsUtils.checkPermissions(mActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { - try { - MediaStore.Images.Media.insertImage(mActivity.getContentResolver(), - mDownloadFiles.get(mSelectedPosition).getAbsolutePath(), - mDownloadFiles.get(mSelectedPosition).getName(), null); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - ToastUtils.showToast(mActivity, "图片保存成功"); - } - } - }); - mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - } - - @Override - public void onPageSelected(int position) { - mSelectedPosition = position; - String text = ++position + "/" + mViews.size(); - tvImageCount.setText(text); - } - - @Override - public void onPageScrollStateChanged(int state) { - } - }); - - if (mStatus == URLS) { - imDelete.setVisibility(View.GONE); - } else { - imDownload.setVisibility(View.GONE); - } - } - - public void build() { - if (mImageDownloader == null) { - return; - } - init(); - mDialog.show(); - mViews = new ArrayList<>(); - mAdapter = new ImageViewerAdapter(mViews, mDialog); - if (mStatus == URLS) { - for (final String url : mUrls) { - final SubsamplingScaleImageView scaleImageView = new SubsamplingScaleImageView(mActivity); - scaleImageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - - IOThread.getSingleThread().execute(new Runnable() { - @Override - public void run() { - final File downLoadFile; - try { - downLoadFile = mImageDownloader.downLoad(url, mActivity); - mDownloadFiles.add(downLoadFile); - mActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - scaleImageView.setImage(ImageSource.uri(Uri.fromFile(downLoadFile))); - } - }); - } catch (Exception e) { - e.printStackTrace(); - Logger.e("加载图片异常" + e.getMessage()); - } - } - }); - mViews.add(scaleImageView); - } - mViewPager.setAdapter(mAdapter); - } else if (mStatus == FILES) { - for (File file : mFiles) { - final SubsamplingScaleImageView scaleImageView = new SubsamplingScaleImageView(mActivity); - scaleImageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - scaleImageView.setImage(ImageSource.uri(Uri.fromFile(file))); - mViews.add(scaleImageView); - } - mViewPager.setAdapter(mAdapter); - } - mViewPager.setCurrentItem(mStartPosition); - tvImageCount.setText(String.format("%s/%s", mStartPosition + 1, mUrls.size())); - } - - public interface OnDeleteItemListener { - void onDelete(int position); - } - -} \ No newline at end of file diff --git a/common_base/src/main/res/color/selector_text_color.xml b/common_base/src/main/res/color/selector_text_color.xml new file mode 100644 index 0000000..4f9bfb5 --- /dev/null +++ b/common_base/src/main/res/color/selector_text_color.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/common_base/src/main/res/color/tab_text_color.xml b/common_base/src/main/res/color/tab_text_color.xml new file mode 100644 index 0000000..8cc3e47 --- /dev/null +++ b/common_base/src/main/res/color/tab_text_color.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/common_base/src/main/res/drawable-xhdpi/ic_back.png b/common_base/src/main/res/drawable-xhdpi/ic_back.png new file mode 100644 index 0000000..e395a62 Binary files /dev/null and b/common_base/src/main/res/drawable-xhdpi/ic_back.png differ diff --git a/common_base/src/main/res/drawable-xhdpi/input_add_default.png b/common_base/src/main/res/drawable-xhdpi/input_add_default.png new file mode 100644 index 0000000..b2e5657 Binary files /dev/null and b/common_base/src/main/res/drawable-xhdpi/input_add_default.png differ diff --git a/common_base/src/main/res/drawable-xhdpi/input_add_disabled.png b/common_base/src/main/res/drawable-xhdpi/input_add_disabled.png new file mode 100644 index 0000000..dd67fb7 Binary files /dev/null and b/common_base/src/main/res/drawable-xhdpi/input_add_disabled.png differ diff --git a/common_base/src/main/res/drawable-xhdpi/input_minus_default.png b/common_base/src/main/res/drawable-xhdpi/input_minus_default.png new file mode 100644 index 0000000..753174d Binary files /dev/null and b/common_base/src/main/res/drawable-xhdpi/input_minus_default.png differ diff --git a/common_base/src/main/res/drawable-xhdpi/input_minus_disabled.png b/common_base/src/main/res/drawable-xhdpi/input_minus_disabled.png new file mode 100644 index 0000000..7b18444 Binary files /dev/null and b/common_base/src/main/res/drawable-xhdpi/input_minus_disabled.png differ diff --git a/common_base/src/main/res/drawable-xhdpi/popup_icon_close.png b/common_base/src/main/res/drawable-xhdpi/popup_icon_close.png new file mode 100644 index 0000000..220beb4 Binary files /dev/null and b/common_base/src/main/res/drawable-xhdpi/popup_icon_close.png differ diff --git a/common_base/src/main/res/drawable-xxhdpi/header_load_default.png b/common_base/src/main/res/drawable-xxhdpi/header_load_default.png new file mode 100644 index 0000000..26c21f0 Binary files /dev/null and b/common_base/src/main/res/drawable-xxhdpi/header_load_default.png differ diff --git a/common_base/src/main/res/drawable-xxhdpi/ic_back.png b/common_base/src/main/res/drawable-xxhdpi/ic_back.png index e395a62..048fb39 100644 Binary files a/common_base/src/main/res/drawable-xxhdpi/ic_back.png and b/common_base/src/main/res/drawable-xxhdpi/ic_back.png differ diff --git a/common_base/src/main/res/drawable-xxhdpi/icon_back.png b/common_base/src/main/res/drawable-xxhdpi/icon_back.png new file mode 100644 index 0000000..e395a62 Binary files /dev/null and b/common_base/src/main/res/drawable-xxhdpi/icon_back.png differ diff --git a/common_base/src/main/res/drawable-xxhdpi/icon_refresh.png b/common_base/src/main/res/drawable-xxhdpi/icon_refresh.png new file mode 100644 index 0000000..0db589f Binary files /dev/null and b/common_base/src/main/res/drawable-xxhdpi/icon_refresh.png differ diff --git a/common_base/src/main/res/drawable-xxhdpi/input_add_default.png b/common_base/src/main/res/drawable-xxhdpi/input_add_default.png index b2e5657..34fa146 100644 Binary files a/common_base/src/main/res/drawable-xxhdpi/input_add_default.png and b/common_base/src/main/res/drawable-xxhdpi/input_add_default.png differ diff --git a/common_base/src/main/res/drawable-xxhdpi/input_add_disabled.png b/common_base/src/main/res/drawable-xxhdpi/input_add_disabled.png index dd67fb7..cee60c9 100644 Binary files a/common_base/src/main/res/drawable-xxhdpi/input_add_disabled.png and b/common_base/src/main/res/drawable-xxhdpi/input_add_disabled.png differ diff --git a/common_base/src/main/res/drawable-xxhdpi/input_minus_default.png b/common_base/src/main/res/drawable-xxhdpi/input_minus_default.png index 753174d..1f8d100 100644 Binary files a/common_base/src/main/res/drawable-xxhdpi/input_minus_default.png and b/common_base/src/main/res/drawable-xxhdpi/input_minus_default.png differ diff --git a/common_base/src/main/res/drawable-xxhdpi/input_minus_disabled.png b/common_base/src/main/res/drawable-xxhdpi/input_minus_disabled.png index 7b18444..525e156 100644 Binary files a/common_base/src/main/res/drawable-xxhdpi/input_minus_disabled.png and b/common_base/src/main/res/drawable-xxhdpi/input_minus_disabled.png differ diff --git a/common_base/src/main/res/drawable-xxhdpi/list_checkbox_default.png b/common_base/src/main/res/drawable-xxhdpi/list_checkbox_default.png new file mode 100644 index 0000000..954d518 Binary files /dev/null and b/common_base/src/main/res/drawable-xxhdpi/list_checkbox_default.png differ diff --git a/common_base/src/main/res/drawable-xxhdpi/list_checkbox_select.png b/common_base/src/main/res/drawable-xxhdpi/list_checkbox_select.png new file mode 100644 index 0000000..4f5c8c4 Binary files /dev/null and b/common_base/src/main/res/drawable-xxhdpi/list_checkbox_select.png differ diff --git a/common_base/src/main/res/drawable-xxhdpi/popup_icon_close.png b/common_base/src/main/res/drawable-xxhdpi/popup_icon_close.png new file mode 100644 index 0000000..1dc435b Binary files /dev/null and b/common_base/src/main/res/drawable-xxhdpi/popup_icon_close.png differ diff --git a/common_base/src/main/res/drawable-xxxhdpi/ic_back.png b/common_base/src/main/res/drawable-xxxhdpi/ic_back.png deleted file mode 100644 index 048fb39..0000000 Binary files a/common_base/src/main/res/drawable-xxxhdpi/ic_back.png and /dev/null differ diff --git a/common_base/src/main/res/drawable-xxxhdpi/ic_launcher.png b/common_base/src/main/res/drawable-xxxhdpi/ic_launcher.png deleted file mode 100644 index 41c09d5..0000000 Binary files a/common_base/src/main/res/drawable-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/common_base/src/main/res/drawable-xxxhdpi/input_add_default.png b/common_base/src/main/res/drawable-xxxhdpi/input_add_default.png deleted file mode 100644 index 34fa146..0000000 Binary files a/common_base/src/main/res/drawable-xxxhdpi/input_add_default.png and /dev/null differ diff --git a/common_base/src/main/res/drawable-xxxhdpi/input_add_disabled.png b/common_base/src/main/res/drawable-xxxhdpi/input_add_disabled.png deleted file mode 100644 index cee60c9..0000000 Binary files a/common_base/src/main/res/drawable-xxxhdpi/input_add_disabled.png and /dev/null differ diff --git a/common_base/src/main/res/drawable-xxxhdpi/input_minus_default.png b/common_base/src/main/res/drawable-xxxhdpi/input_minus_default.png deleted file mode 100644 index 1f8d100..0000000 Binary files a/common_base/src/main/res/drawable-xxxhdpi/input_minus_default.png and /dev/null differ diff --git a/common_base/src/main/res/drawable-xxxhdpi/input_minus_disabled.png b/common_base/src/main/res/drawable-xxxhdpi/input_minus_disabled.png deleted file mode 100644 index 525e156..0000000 Binary files a/common_base/src/main/res/drawable-xxxhdpi/input_minus_disabled.png and /dev/null differ diff --git a/common_base/src/main/res/drawable/bg_of_add_count_view.xml b/common_base/src/main/res/drawable/bg_of_add_count_view.xml new file mode 100644 index 0000000..8215d70 --- /dev/null +++ b/common_base/src/main/res/drawable/bg_of_add_count_view.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/common_base/src/main/res/drawable/bg_of_color_f5_4radius.xml b/common_base/src/main/res/drawable/bg_of_color_f5_4radius.xml new file mode 100644 index 0000000..f633d90 --- /dev/null +++ b/common_base/src/main/res/drawable/bg_of_color_f5_4radius.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/common_base/src/main/res/drawable/bg_of_green_gradient.xml b/common_base/src/main/res/drawable/bg_of_green_gradient_radius.xml similarity index 100% rename from common_base/src/main/res/drawable/bg_of_green_gradient.xml rename to common_base/src/main/res/drawable/bg_of_green_gradient_radius.xml diff --git a/common_base/src/main/res/drawable/bg_of_minus_count_view.xml b/common_base/src/main/res/drawable/bg_of_minus_count_view.xml new file mode 100644 index 0000000..1b6aa1c --- /dev/null +++ b/common_base/src/main/res/drawable/bg_of_minus_count_view.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/common_base/src/main/res/drawable/bg_of_orange_gradient.xml b/common_base/src/main/res/drawable/bg_of_orange_gradient.xml index 26a204d..8cc2733 100644 --- a/common_base/src/main/res/drawable/bg_of_orange_gradient.xml +++ b/common_base/src/main/res/drawable/bg_of_orange_gradient.xml @@ -4,5 +4,4 @@ android:endColor="#FF8000" android:startColor="#FFA82E" android:type="linear" /> - \ No newline at end of file diff --git a/common_base/src/main/res/drawable/bg_of_gradient.xml b/common_base/src/main/res/drawable/bg_of_orange_gradient_radius.xml similarity index 85% rename from common_base/src/main/res/drawable/bg_of_gradient.xml rename to common_base/src/main/res/drawable/bg_of_orange_gradient_radius.xml index 8cc2733..26a204d 100644 --- a/common_base/src/main/res/drawable/bg_of_gradient.xml +++ b/common_base/src/main/res/drawable/bg_of_orange_gradient_radius.xml @@ -4,4 +4,5 @@ android:endColor="#FF8000" android:startColor="#FFA82E" android:type="linear" /> + \ No newline at end of file diff --git a/common_base/src/main/res/drawable/bg_of_red_gradient.xml b/common_base/src/main/res/drawable/bg_of_red_gradient.xml new file mode 100644 index 0000000..43fdb81 --- /dev/null +++ b/common_base/src/main/res/drawable/bg_of_red_gradient.xml @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/common_base/src/main/res/drawable/bg_of_select_icon_selector.xml b/common_base/src/main/res/drawable/bg_of_select_icon_selector.xml new file mode 100644 index 0000000..eb644aa --- /dev/null +++ b/common_base/src/main/res/drawable/bg_of_select_icon_selector.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/common_base/src/main/res/drawable/browser_progress_bg.xml b/common_base/src/main/res/drawable/browser_progress_bg.xml new file mode 100644 index 0000000..d887fed --- /dev/null +++ b/common_base/src/main/res/drawable/browser_progress_bg.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/common_base/src/main/res/drawable/corners_black_shape.xml b/common_base/src/main/res/drawable/corners_black_shape.xml new file mode 100644 index 0000000..695d250 --- /dev/null +++ b/common_base/src/main/res/drawable/corners_black_shape.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/common_base/src/main/res/drawable/corners_theme_shape_45.xml b/common_base/src/main/res/drawable/corners_theme_shape_45.xml new file mode 100644 index 0000000..e85348d --- /dev/null +++ b/common_base/src/main/res/drawable/corners_theme_shape_45.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/module_market/src/main/res/drawable/market_shape_round_red.xml b/common_base/src/main/res/drawable/market_shape_round_red.xml similarity index 100% rename from module_market/src/main/res/drawable/market_shape_round_red.xml rename to common_base/src/main/res/drawable/market_shape_round_red.xml diff --git a/common_base/src/main/res/drawable/stroke_gray_white_shape.xml b/common_base/src/main/res/drawable/stroke_gray_white_shape.xml new file mode 100644 index 0000000..8125cfd --- /dev/null +++ b/common_base/src/main/res/drawable/stroke_gray_white_shape.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/common_base/src/main/res/layout/action_bar.xml b/common_base/src/main/res/layout/action_bar.xml index 85fd5c6..9da3300 100644 --- a/common_base/src/main/res/layout/action_bar.xml +++ b/common_base/src/main/res/layout/action_bar.xml @@ -7,12 +7,12 @@ + android:paddingStart="@dimen/title_bar_padding" + android:paddingEnd="6dp" /> diff --git a/common_base/src/main/res/layout/activity_base.xml b/common_base/src/main/res/layout/activity_base.xml index d37ca85..79d7212 100644 --- a/common_base/src/main/res/layout/activity_base.xml +++ b/common_base/src/main/res/layout/activity_base.xml @@ -2,15 +2,20 @@ + android:layout_height="@dimen/title_bar_height" + android:background="@color/white" + android:visibility="gone" /> - + + + diff --git a/common_base/src/main/res/layout/activity_browser.xml b/common_base/src/main/res/layout/activity_browser.xml new file mode 100644 index 0000000..ea06bb1 --- /dev/null +++ b/common_base/src/main/res/layout/activity_browser.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/common_base/src/main/res/layout/activity_horizontal_tab.xml b/common_base/src/main/res/layout/activity_horizontal_tab.xml index 8c026bc..6e353e7 100644 --- a/common_base/src/main/res/layout/activity_horizontal_tab.xml +++ b/common_base/src/main/res/layout/activity_horizontal_tab.xml @@ -13,16 +13,16 @@ android:background="@color/white" app:pstsBold="true" app:pstsHasTopLine="false" - app:pstsIndicatorColor="@color/blue" + app:pstsIndicatorColor="@color/theme" app:pstsIndicatorHeight="1.5dp" app:pstsShouldExpand="true" app:pstsTextDefaultColor="@color/black" - app:pstsTextSelectedColor="@color/blue" + app:pstsTextSelectedColor="@color/theme" app:pstsTextSize="14sp" app:pstsUnderlineColor="@color/gray" app:pstsUnderlineHeight="1px" /> - diff --git a/common_base/src/main/res/layout/activity_image_gallery.xml b/common_base/src/main/res/layout/activity_image_gallery.xml new file mode 100644 index 0000000..fa58373 --- /dev/null +++ b/common_base/src/main/res/layout/activity_image_gallery.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/common_base/src/main/res/layout/activity_scan.xml b/common_base/src/main/res/layout/activity_scan.xml new file mode 100644 index 0000000..c6f24c3 --- /dev/null +++ b/common_base/src/main/res/layout/activity_scan.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/module_main/src/main/res/layout/main_fragment_center.xml b/common_base/src/main/res/layout/activity_select_file.xml similarity index 65% rename from module_main/src/main/res/layout/main_fragment_center.xml rename to common_base/src/main/res/layout/activity_select_file.xml index f6d11cb..1936a51 100644 --- a/module_main/src/main/res/layout/main_fragment_center.xml +++ b/common_base/src/main/res/layout/activity_select_file.xml @@ -1,14 +1,13 @@ - - + android:layout_marginStart="5dp" + android:layout_marginEnd="5dp" /> + \ No newline at end of file diff --git a/common_base/src/main/res/layout/activity_springboard.xml b/common_base/src/main/res/layout/activity_springboard.xml new file mode 100644 index 0000000..8e17cb3 --- /dev/null +++ b/common_base/src/main/res/layout/activity_springboard.xml @@ -0,0 +1,6 @@ + + diff --git a/common_base/src/main/res/layout/base_tablayout_child.xml b/common_base/src/main/res/layout/base_tablayout_child.xml new file mode 100644 index 0000000..ab0e0dd --- /dev/null +++ b/common_base/src/main/res/layout/base_tablayout_child.xml @@ -0,0 +1,13 @@ + + + \ No newline at end of file diff --git a/common_base/src/main/res/layout/dailog_date.xml b/common_base/src/main/res/layout/dailog_date.xml new file mode 100644 index 0000000..0ed6397 --- /dev/null +++ b/common_base/src/main/res/layout/dailog_date.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + diff --git a/common_base/src/main/res/layout/dialog_app.xml b/common_base/src/main/res/layout/dialog_app.xml index a15c600..54c0709 100644 --- a/common_base/src/main/res/layout/dialog_app.xml +++ b/common_base/src/main/res/layout/dialog_app.xml @@ -7,12 +7,13 @@ + android:paddingTop="15dp" + android:visibility="gone"> - - - - - + android:layout_height="wrap_content"> - - - - - - - + android:id="@+id/ll_content_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:orientation="vertical" + android:paddingLeft="10dp" + android:paddingRight="10dp"> - + - - - - - - - - - - + android:visibility="gone" /> - + + android:layout_marginTop="15dp"> - - - - - + + + + + + \ No newline at end of file diff --git a/common_base/src/main/res/layout/dialog_scale_image.xml b/common_base/src/main/res/layout/dialog_scale_image.xml deleted file mode 100644 index 10c8e9c..0000000 --- a/common_base/src/main/res/layout/dialog_scale_image.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/common_base/src/main/res/layout/empty_layout.xml b/common_base/src/main/res/layout/empty_layout.xml deleted file mode 100644 index cec4857..0000000 --- a/common_base/src/main/res/layout/empty_layout.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - diff --git a/common_base/src/main/res/layout/item_of_load_all_data.xml b/common_base/src/main/res/layout/item_of_load_all_data.xml new file mode 100644 index 0000000..e72aab4 --- /dev/null +++ b/common_base/src/main/res/layout/item_of_load_all_data.xml @@ -0,0 +1,17 @@ + + + + + \ No newline at end of file diff --git a/common_base/src/main/res/layout/item_of_select_file.xml b/common_base/src/main/res/layout/item_of_select_file.xml new file mode 100644 index 0000000..6986840 --- /dev/null +++ b/common_base/src/main/res/layout/item_of_select_file.xml @@ -0,0 +1,27 @@ + + + + + + + + \ No newline at end of file diff --git a/common_base/src/main/res/layout/item_of_select_image.xml b/common_base/src/main/res/layout/item_of_select_image.xml new file mode 100644 index 0000000..ac480ff --- /dev/null +++ b/common_base/src/main/res/layout/item_of_select_image.xml @@ -0,0 +1,26 @@ + + + + + + + + \ No newline at end of file diff --git a/common_base/src/main/res/layout/item_of_selector_pop.xml b/common_base/src/main/res/layout/item_of_selector_pop.xml new file mode 100644 index 0000000..79adb8e --- /dev/null +++ b/common_base/src/main/res/layout/item_of_selector_pop.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/common_base/src/main/res/layout/fragment_base.xml b/common_base/src/main/res/layout/layout_base.xml similarity index 86% rename from common_base/src/main/res/layout/fragment_base.xml rename to common_base/src/main/res/layout/layout_base.xml index 15cc49e..9919d9a 100644 --- a/common_base/src/main/res/layout/fragment_base.xml +++ b/common_base/src/main/res/layout/layout_base.xml @@ -2,13 +2,14 @@ + android:layout="@layout/layout_empty" /> + android:layout_height="12dp" + android:background="@drawable/bg_of_minus_count_view" /> + android:layout_height="12dp" + android:background="@drawable/bg_of_add_count_view" /> \ No newline at end of file diff --git a/common_base/src/main/res/layout/layout_empty.xml b/common_base/src/main/res/layout/layout_empty.xml index b7568b5..05e4928 100644 --- a/common_base/src/main/res/layout/layout_empty.xml +++ b/common_base/src/main/res/layout/layout_empty.xml @@ -1,21 +1,39 @@ + android:id="@+id/iv_empty" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + android:layout_marginTop="19dp" + android:textColor="@color/color_999999" + android:textSize="14sp" /> + + + - \ No newline at end of file + diff --git a/common_base/src/main/res/layout/layout_error.xml b/common_base/src/main/res/layout/layout_error.xml deleted file mode 100644 index 8f580bc..0000000 --- a/common_base/src/main/res/layout/layout_error.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/common_base/src/main/res/layout/layout_item_of_dialog_bottom_in.xml b/common_base/src/main/res/layout/layout_item_of_dialog_bottom_in.xml index ed06b47..a7c33fd 100644 --- a/common_base/src/main/res/layout/layout_item_of_dialog_bottom_in.xml +++ b/common_base/src/main/res/layout/layout_item_of_dialog_bottom_in.xml @@ -8,10 +8,10 @@ android:id="@+id/tv_text" style="@style/TextStyle" android:layout_width="match_parent" - android:layout_height="50dp" - android:gravity="center" /> + android:layout_height="wrap_content" + android:gravity="center" + android:minHeight="45dp" /> - diff --git a/common_base/src/main/res/layout/layout_loading.xml b/common_base/src/main/res/layout/layout_loading.xml deleted file mode 100644 index 773706a..0000000 --- a/common_base/src/main/res/layout/layout_loading.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/common_base/src/main/res/layout/layout_nothing.xml b/common_base/src/main/res/layout/layout_nothing.xml new file mode 100644 index 0000000..4ce1eae --- /dev/null +++ b/common_base/src/main/res/layout/layout_nothing.xml @@ -0,0 +1,5 @@ + + + diff --git a/common_base/src/main/res/layout/layout_refresh.xml b/common_base/src/main/res/layout/layout_refresh.xml index c29def5..e0845be 100644 --- a/common_base/src/main/res/layout/layout_refresh.xml +++ b/common_base/src/main/res/layout/layout_refresh.xml @@ -1,13 +1,15 @@ - + android:layout_height="match_parent" + android:background="@color/bg" + android:fillViewport="true"> - + android:layout_height="match_parent" + android:background="@color/bg" /> - - + diff --git a/common_base/src/main/res/layout/layout_refresh_view.xml b/common_base/src/main/res/layout/layout_refresh_view.xml deleted file mode 100644 index b1a4130..0000000 --- a/common_base/src/main/res/layout/layout_refresh_view.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/common_base/src/main/res/layout/layout_search.xml b/common_base/src/main/res/layout/layout_search.xml new file mode 100644 index 0000000..4eeffa7 --- /dev/null +++ b/common_base/src/main/res/layout/layout_search.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/common_base/src/main/res/layout/pop_date_range.xml b/common_base/src/main/res/layout/pop_date_range.xml new file mode 100644 index 0000000..a58e5ce --- /dev/null +++ b/common_base/src/main/res/layout/pop_date_range.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/common_base/src/main/res/layout/pop_selector.xml b/common_base/src/main/res/layout/pop_selector.xml new file mode 100644 index 0000000..d1a280c --- /dev/null +++ b/common_base/src/main/res/layout/pop_selector.xml @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/common_base/src/main/res/layout/toast.xml b/common_base/src/main/res/layout/toast.xml deleted file mode 100644 index be9a8d1..0000000 --- a/common_base/src/main/res/layout/toast.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - diff --git a/common_base/src/main/res/layout/update_progress_layout.xml b/common_base/src/main/res/layout/update_progress_layout.xml deleted file mode 100644 index 53a4998..0000000 --- a/common_base/src/main/res/layout/update_progress_layout.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/common_base/src/main/res/layout/view_scale_image.xml b/common_base/src/main/res/layout/view_scale_image.xml deleted file mode 100644 index d6daa5b..0000000 --- a/common_base/src/main/res/layout/view_scale_image.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/common_base/src/main/res/values/attrs.xml b/common_base/src/main/res/values/attrs.xml index a746863..2441cb3 100644 --- a/common_base/src/main/res/values/attrs.xml +++ b/common_base/src/main/res/values/attrs.xml @@ -1,13 +1,6 @@ - - - - - - - @@ -26,15 +19,19 @@ + + + - + + @@ -50,21 +47,6 @@ - - - - - - - - - - - - - - - @@ -89,6 +71,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -97,4 +151,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/common_base/src/main/res/values/colors.xml b/common_base/src/main/res/values/colors.xml index b26bb20..46caca2 100644 --- a/common_base/src/main/res/values/colors.xml +++ b/common_base/src/main/res/values/colors.xml @@ -5,7 +5,7 @@ #00000000 #FFFFFF #BBBBBB - #DC143C + #FF0000 #0099FF #000000 #FFA82E @@ -15,5 +15,9 @@ #E1FFFF #F0E68C #7FFF00 + #333333 + #666666 + #999999 + #F5F5F5 diff --git a/common_base/src/main/res/values/dimens.xml b/common_base/src/main/res/values/dimens.xml index 29627de..9451c33 100644 --- a/common_base/src/main/res/values/dimens.xml +++ b/common_base/src/main/res/values/dimens.xml @@ -8,6 +8,12 @@ 150dp 115dp 100dp + + 20dp + + 50dp + + 14dp \ No newline at end of file diff --git a/common_base/src/main/res/values/strings.xml b/common_base/src/main/res/values/strings.xml index 93f1ce9..5ff7237 100644 --- a/common_base/src/main/res/values/strings.xml +++ b/common_base/src/main/res/values/strings.xml @@ -1,8 +1,122 @@ AMD + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 暂无数据 - 网络请求失败 + 网络连接失败, 请检查网络 + 服务器异常 + 请求超时 上拉加载 下拉刷新 松开刷新 @@ -11,5 +125,45 @@ 取消 确定 提示 + 您必须授权必要权限才可使用该功能 + 返回 + 关闭 + 删除成功 + 您最多可选%d张图片 + 您最多可选%d个文件 + 选择图片 + 选择文件 + 您还未选择呢 + 请先设置图片 + 选择图片失败 + 扫一扫 + 相机 + 相册 + ~没有更多拉~ + 正在处理中,请稍等… + + + + 下拉可以刷新 + 正在刷新… + 正在加载… + 释放立即刷新 + 刷新完成 + 刷新失败 + 上次更新 MM-dd HH:mm + 释放进入二楼 + 上拉加载更多 + 释放立即加载 + 正在加载… + 正在刷新… + 加载完成 + 加载失败 + ~没有更多啦~ + 刷新重试 + 开始时间 + 结束时间 + + 重置 + diff --git a/common_base/src/main/res/values/styles.xml b/common_base/src/main/res/values/styles.xml index 05fe726..464bda8 100644 --- a/common_base/src/main/res/values/styles.xml +++ b/common_base/src/main/res/values/styles.xml @@ -4,6 +4,11 @@ + + + + + diff --git a/module_market/README.txt b/module_market/README.txt new file mode 100644 index 0000000..5cecda0 --- /dev/null +++ b/module_market/README.txt @@ -0,0 +1,11 @@ +商城模块 + +为防止同名资源文件被覆盖,则采用如下方式来规避 +1.该module的资源命名必须以[market_]打头 + 如:market_icon_close,market_img_bg,market_shape_round_4 + +2.该module的布局文件命名必须以[market_]打头 + 如:market_activity_main,market_fragment_main,market_item_of_user_list + +3.涉及到跨module跳转的Activity、Fragment需要在common_base模块的ARouterConfig中配置跳转的Path + diff --git a/module_market/build.gradle b/module_market/build.gradle index 22ab269..2050c26 100644 --- a/module_market/build.gradle +++ b/module_market/build.gradle @@ -50,6 +50,10 @@ android { } } } + compileOptions { + targetCompatibility rootProject.ext.versions.javaSDKVersion + sourceCompatibility rootProject.ext.versions.javaSDKVersion + } } dependencies { @@ -58,8 +62,8 @@ dependencies { implementation project(':common_base') //Arouter路由 - annotationProcessor rootProject.ext.dependencies["arouter_compiler"] + annotationProcessor rootProject.ext.dependencies["arouterCompiler"] //黄油刀 - annotationProcessor rootProject.ext.dependencies["butterknife_compiler"] + annotationProcessor rootProject.ext.dependencies["butterknifeCompiler"] } \ No newline at end of file diff --git a/module_market/doc.txt b/module_market/doc.txt deleted file mode 100644 index 749ae55..0000000 --- a/module_market/doc.txt +++ /dev/null @@ -1,4 +0,0 @@ - - -商城模块 封装各种商城 可能用到的东西 -如: 仿京东 商品详情滑动页 促销倒计时 购物车 等 \ No newline at end of file diff --git a/module_market/src/main/AndroidManifest.xml b/module_market/src/main/AndroidManifest.xml index 6569522..8e4b2c4 100644 --- a/module_market/src/main/AndroidManifest.xml +++ b/module_market/src/main/AndroidManifest.xml @@ -5,5 +5,6 @@ +
diff --git a/module_market/src/main/assets/html/goods_detail.html b/module_market/src/main/assets/html/goods_detail.html new file mode 100644 index 0000000..51bccb6 --- /dev/null +++ b/module_market/src/main/assets/html/goods_detail.html @@ -0,0 +1,83 @@ + + + + + + + + + + 商品详情 + + + + + +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/module_market/src/main/java/com/wss/module/market/bean/GoodsComment.java b/module_market/src/main/java/com/wss/module/market/bean/GoodsComment.java index e5dd09e..137cfaf 100644 --- a/module_market/src/main/java/com/wss/module/market/bean/GoodsComment.java +++ b/module_market/src/main/java/com/wss/module/market/bean/GoodsComment.java @@ -9,13 +9,13 @@ * Describe:商品评论 * Created by 吴天强 on 2018/11/1. */ - @Getter @Setter public class GoodsComment extends BaseBean { private String userHead; private String userName; - private String comment;//评论内容 - private float star;//星级 + private String comment; + private float star; + private String date; } diff --git a/module_market/src/main/java/com/wss/module/market/bean/GoodsInfo.java b/module_market/src/main/java/com/wss/module/market/bean/GoodsInfo.java index 8690c91..e0c71b3 100644 --- a/module_market/src/main/java/com/wss/module/market/bean/GoodsInfo.java +++ b/module_market/src/main/java/com/wss/module/market/bean/GoodsInfo.java @@ -1,6 +1,7 @@ package com.wss.module.market.bean; import com.wss.common.base.bean.BaseBean; +import com.wss.common.bean.Banner; import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Generated; @@ -9,11 +10,15 @@ import java.util.List; +import lombok.Getter; +import lombok.Setter; + /** * Describe:商品信息 购物车做了本地化存储 * Created by 吴天强 on 2018/11/1. */ - +@Getter +@Setter @Entity public class GoodsInfo extends BaseBean { @@ -26,10 +31,10 @@ public class GoodsInfo extends BaseBean { private String praiseRate;//好评率 private String commentCount;//用户点评数 private int num;//数量 - @Transient - private boolean checked;// @Transient//该字段不入库 - private List goodsHeadImg;//商品头图 + private boolean checked;//是否选择 + @Transient//该字段不入库 + private List goodsHeadImg;//商品头图 private String vendorId;//供应商ID @@ -151,20 +156,4 @@ public String getVendorId() { public void setVendorId(String vendorId) { this.vendorId = vendorId; } - - public boolean isChecked() { - return checked; - } - - public void setChecked(boolean checked) { - this.checked = checked; - } - - public List getGoodsHeadImg() { - return goodsHeadImg; - } - - public void setGoodsHeadImg(List goodsHeadImg) { - this.goodsHeadImg = goodsHeadImg; - } } diff --git a/module_market/src/main/java/com/wss/module/market/bean/Vendor.java b/module_market/src/main/java/com/wss/module/market/bean/Vendor.java index 1ea0703..179b5dc 100644 --- a/module_market/src/main/java/com/wss/module/market/bean/Vendor.java +++ b/module_market/src/main/java/com/wss/module/market/bean/Vendor.java @@ -16,8 +16,8 @@ @Setter public class Vendor extends BaseBean { - private String vendorId;//供应商ID - private String vendorName;//供应商名称 + private String vendorId; + private String vendorName; private List goodsInfos; private boolean checked; diff --git a/module_market/src/main/java/com/wss/module/market/db/MarketDBFactory.java b/module_market/src/main/java/com/wss/module/market/db/MarketDBFactory.java index 3da3e48..564156d 100644 --- a/module_market/src/main/java/com/wss/module/market/db/MarketDBFactory.java +++ b/module_market/src/main/java/com/wss/module/market/db/MarketDBFactory.java @@ -30,7 +30,7 @@ public static MarketDBFactory getInstance() { */ public GoodsInfoManage getGoodsInfoManage() { if (goodsInfoManage == null) { - goodsInfoManage = new GoodsInfoManage(MarketDBManage.getInstance(BaseApplication.getApplication()).getDaoSession().getGoodsInfoDao()); + goodsInfoManage = new GoodsInfoManage(MarketDBManage.getInstance(BaseApplication.i()).getDaoSession().getGoodsInfoDao()); } return goodsInfoManage; } diff --git a/module_market/src/main/java/com/wss/module/market/db/MarketDBManage.java b/module_market/src/main/java/com/wss/module/market/db/MarketDBManage.java index 4c461e6..c4bd949 100644 --- a/module_market/src/main/java/com/wss/module/market/db/MarketDBManage.java +++ b/module_market/src/main/java/com/wss/module/market/db/MarketDBManage.java @@ -2,7 +2,7 @@ import android.content.Context; -import com.wss.common.constants.DBConfig; +import com.wss.common.constants.Constants; import com.wss.module.market.bean.DaoMaster; import com.wss.module.market.bean.DaoSession; @@ -72,7 +72,7 @@ public synchronized void closeDataBase() { */ private DaoMaster getDaoMaster() { if (null == mDaoMaster) { - mHelper = new DaoMaster.DevOpenHelper(context, DBConfig.DB_NAME, null); + mHelper = new DaoMaster.DevOpenHelper(context, Constants.DBConfig.DB_NAME, null); mDaoMaster = new DaoMaster(mHelper.getWritableDb()); } return mDaoMaster; diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/cart/OrderSettlementActivity.java b/module_market/src/main/java/com/wss/module/market/ui/goods/cart/OrderSettlementActivity.java new file mode 100644 index 0000000..de46c58 --- /dev/null +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/cart/OrderSettlementActivity.java @@ -0,0 +1,139 @@ +package com.wss.module.market.ui.goods.cart; + +import android.view.View; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.wss.common.base.BaseActionBarActivity; +import com.wss.common.base.mvp.BasePresenter; +import com.wss.common.constants.Dic; +import com.wss.common.utils.JsonUtils; +import com.wss.common.utils.MoneyUtils; +import com.wss.common.utils.ToastUtils; +import com.wss.common.widget.MultipleItemView; +import com.wss.module.market.R; +import com.wss.module.market.R2; +import com.wss.module.market.bean.Vendor; +import com.wss.module.market.ui.goods.cart.adapter.OrderSettlementGoodsAdapter; +import com.wss.module.market.utils.ShoppingCartUtils; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import butterknife.BindView; +import butterknife.OnClick; + +/** + * Describe:结算订单 + * Created by 吴天强 on 2020/10/20. + */ +public class OrderSettlementActivity extends BaseActionBarActivity { + + @BindView(R2.id.tv_no_address) + TextView tvNoAddress; + + @BindView(R2.id.tv_name) + TextView tvName; + + @BindView(R2.id.tv_address) + TextView tvAddress; + + @BindView(R2.id.rv_goods_list) + RecyclerView rvGoodsList; + + @BindView(R2.id.miv_coupon) + MultipleItemView mivCoupon; + + @BindView(R2.id.miv_shopping_bi) + MultipleItemView mivShoppingBi; + + @BindView(R2.id.tv_goods_price) + TextView tvGoodsPrice; + + @BindView(R2.id.tv_coupon_price) + TextView tvCouponPrice; + + @BindView(R2.id.rl_coupon_money) + RelativeLayout rlCouponMoney; + + @BindView(R2.id.rl_shopping_bi_money) + RelativeLayout rlShoppingBiMoney; + + @BindView(R2.id.tv_shopping_bi) + TextView tvShoppingBi; + + @BindView(R2.id.tv_total) + TextView tvTotal; + + @BindView(R2.id.btn_buy) + TextView btnBuy; + + @BindView(R2.id.rl_bottom) + RelativeLayout rlBottom; + + private List vendorList = new ArrayList<>(); + + private double cartCountPrice; + + @Override + protected BasePresenter createPresenter() { + return null; + } + + @Override + protected int getLayoutId() { + return R.layout.market_order_settlement; + } + + @Override + protected void initView() { + setCenterText("结算订单"); + //以JSON的形式传入商品信息 + String goodsJson = getIntent().getStringExtra(Dic.VENDOR_GOODS_INFO); + vendorList.addAll(JsonUtils.getList(goodsJson, Vendor.class)); + cartCountPrice = ShoppingCartUtils.getCartCountPrice(vendorList); + + rvGoodsList.setLayoutManager(new LinearLayoutManager(context)); + rvGoodsList.setAdapter(new OrderSettlementGoodsAdapter(context, vendorList, (data, position) -> { + + ToastUtils.show("商品清单"); + })); + mivShoppingBi.setRightIconChangedListener(checked -> { + if (checked) { + rlShoppingBiMoney.setVisibility(View.VISIBLE); + cartCountPrice -= 10.00; + } else { + cartCountPrice += 10.00; + rlShoppingBiMoney.setVisibility(View.GONE); + } + setTotal(); + }); + setTotal(); + } + + private void setTotal() { + //减掉优惠券 + String subtract = MoneyUtils.Algorithm.subtract(String.valueOf(cartCountPrice), "100"); + tvTotal.setText(String.format("合计:%s", subtract)); + } + + + @OnClick({R2.id.tv_no_address, R2.id.miv_coupon, R2.id.btn_buy}) + public void onViewClicked(@NotNull View view) { + int id = view.getId(); + if (id == R.id.tv_no_address) { + //去添加地址 + ToastUtils.show("去添加地址"); + } else if (id == R.id.miv_coupon) { + //优惠券 + ToastUtils.show("优惠券页面"); + } else if (id == R.id.btn_buy) { + //去支付 + ToastUtils.show("去支付"); + } + } +} diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/cart/ShoppingCartActivity.java b/module_market/src/main/java/com/wss/module/market/ui/goods/cart/ShoppingCartActivity.java index afddbf7..c8bf4e7 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/goods/cart/ShoppingCartActivity.java +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/cart/ShoppingCartActivity.java @@ -1,19 +1,19 @@ package com.wss.module.market.ui.goods.cart; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.view.View; import android.widget.ImageView; import android.widget.TextView; -import com.wss.common.base.ActionBarActivity; +import com.wss.common.base.BaseActionBarActivity; import com.wss.common.bean.Event; +import com.wss.common.constants.Dic; import com.wss.common.constants.EventAction; -import com.wss.common.listener.OnListItemClickListener; -import com.wss.common.utils.ToastUtils; +import com.wss.common.manage.ActivityToActivity; +import com.wss.common.utils.JsonUtils; import com.wss.module.market.R; import com.wss.module.market.R2; +import com.wss.module.market.bean.GoodsInfo; import com.wss.module.market.bean.Vendor; import com.wss.module.market.ui.goods.cart.adapter.ShoppingCartAdapter; import com.wss.module.market.ui.goods.cart.mvp.CartPresenter; @@ -21,8 +21,12 @@ import com.wss.module.market.utils.ShoppingCartUtils; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import butterknife.BindView; import butterknife.OnClick; @@ -30,20 +34,24 @@ * Describe:购物车 * Created by 吴天强 on 2018/11/5. */ - -public class ShoppingCartActivity extends ActionBarActivity implements ShoppingCartContract.View, - OnListItemClickListener { +public class ShoppingCartActivity extends BaseActionBarActivity implements ShoppingCartContract.View { @BindView(R2.id.recycle_view) RecyclerView recycleView; + @BindView(R2.id.iv_check_all) ImageView ivCheckAll; + @BindView(R2.id.tv_total) TextView tvTotal; + @BindView(R2.id.btn_buy) TextView btnBuy; + private TextView tvRight; + private boolean isEdit; + @Override protected CartPresenter createPresenter() { return new CartPresenter(); @@ -55,57 +63,72 @@ protected CartPresenter createPresenter() { @Override protected int getLayoutId() { - return R.layout.market_activity_shopping_cart; } @Override protected void initView() { - setTitleText("购物车"); - adapter = new ShoppingCartAdapter(mContext, mData, R.layout.market_item_of_shopping_cart_list, this); - recycleView.setLayoutManager(new LinearLayoutManager(mContext)); - recycleView.setAdapter(adapter); - actionBar.setRightText("清空", new View.OnClickListener() { - @Override - public void onClick(View v) { - ShoppingCartUtils.cleanLocal(); - } + setCenterText("购物车"); + adapter = new ShoppingCartAdapter(context, mData, (data, position) -> { + }); - presenter.start(); + recycleView.setLayoutManager(new LinearLayoutManager(context)); + recycleView.setAdapter(adapter); + tvRight = getTitleBar().getTextView(); + tvRight.setText("编辑"); + tvRight.setOnClickListener(v -> onRightChange()); + getTitleBar().setRightView(tvRight); + getPresenter().start(); } + + private void onRightChange() { + isEdit = !isEdit; + if (isEdit) { + tvRight.setText("完成"); + tvTotal.setVisibility(View.GONE); + btnBuy.setText("删除"); + btnBuy.setBackgroundResource(R.drawable.market_shopping_cart_next_btn_red); + } else { + tvTotal.setVisibility(View.VISIBLE); + tvRight.setText("编辑"); + btnBuy.setText("下一步"); + btnBuy.setBackgroundResource(R.drawable.market_shopping_cart_next_btn); + } + adapter.setEdit(isEdit); + } + + @Override - protected boolean regEvent() { + protected boolean registerEventBus() { return true; } @Override public void onEventBus(Event event) { super.onEventBus(event); - if (TextUtils.equals(EventAction.EVENT_SHOPPING_CART_REFRESH, event.getAction())) { + if (TextUtils.equals(EventAction.EVENT_SHOPPING_CART_CHANGED, event.getAction())) { //购物车有变化 adapter.notifyDataSetChanged(); ivCheckAll.setSelected(ShoppingCartUtils.isAllVendorChecked(mData)); displayResult(); - } else if (TextUtils.equals(EventAction.EVENT_SHOPPING_CART_CLEAN, event.getAction())) { - showEmptyView("车里空空如也"); + } else if (TextUtils.equals(EventAction.EVENT_SHOPPING_CART_REFRESH, event.getAction())) { + //重新获取购物车数据 + getPresenter().getCartData(); } } private void displayResult() { btnBuy.setSelected(ShoppingCartUtils.isCheckedLeastOne(mData)); - tvTotal.setText(String.format("%s%s", getString(R.string.total), ShoppingCartUtils.getCartCountPrice(mData))); + tvTotal.setText(String.format("%s%s", getString(R.string.market_total), ShoppingCartUtils.getCartCountPrice(mData))); } @Override - public void cartData(List dataList) { + public void refreshCartData(List dataList) { this.mData.clear(); this.mData.addAll(dataList); adapter.notifyDataSetChanged(); - //默认全部选中 - ShoppingCartUtils.checkAll(mData, true); - ivCheckAll.setSelected(true); displayResult(); } @@ -120,7 +143,17 @@ public void onViewClicked(View view) { adapter.notifyDataSetChanged(); displayResult(); } else if (i == R.id.btn_buy) { - ToastUtils.showToast(mContext, "可点击"); + List checkedGoods = ShoppingCartUtils.getAllCheckedGoods(mData); + if (checkedGoods.size() > 0) { + if (isEdit) { + //删除 + ShoppingCartUtils.delete(checkedGoods); + } else { + Map param = new HashMap<>(); + param.put(Dic.VENDOR_GOODS_INFO, JsonUtils.toJson(ShoppingCartUtils.getCheckedGoodsVendor(mData))); + ActivityToActivity.toActivity(context, OrderSettlementActivity.class, param); + } + } } } @@ -129,9 +162,4 @@ public void onEmpty(Object tag) { super.onEmpty(tag); showEmptyView("车里空空如也"); } - - @Override - public void onItemClick(View view, int position) { - //TODO - } } diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/cart/adapter/OrderSettlementGoodsAdapter.java b/module_market/src/main/java/com/wss/module/market/ui/goods/cart/adapter/OrderSettlementGoodsAdapter.java new file mode 100644 index 0000000..3dea4d0 --- /dev/null +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/cart/adapter/OrderSettlementGoodsAdapter.java @@ -0,0 +1,72 @@ +package com.wss.module.market.ui.goods.cart.adapter; + +import android.content.Context; +import android.view.View; + +import com.wss.common.base.adapter.BaseListAdapter; +import com.wss.common.utils.ImageUtils; +import com.wss.module.market.R; +import com.wss.module.market.bean.GoodsInfo; +import com.wss.module.market.bean.Vendor; +import com.wss.module.market.utils.ShoppingCartUtils; + +import org.byteam.superadapter.SuperViewHolder; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +/** + * Describe:订单页商品-供应商适配器 + * Created by 吴天强 on 2020/10/20. + */ +public class OrderSettlementGoodsAdapter extends BaseListAdapter { + + private OnGoodsItemClickListener onGoodsItemClickListener; + + public OrderSettlementGoodsAdapter(Context context, List mData, OnGoodsItemClickListener onGoodsItemClickListener) { + super(context, mData, R.layout.market_item_of_order_goods_vendor, null); + this.onGoodsItemClickListener = onGoodsItemClickListener; + } + + @Override + public void onBindData(@NotNull SuperViewHolder holder, int viewType, int layoutPosition, @NotNull Vendor data) { + holder.setText(R.id.tv_vendor_name, data.getVendorName()); + if (data.getGoodsInfos().size() == 1) { + //一种商品 + GoodsInfo goodsInfo = data.getGoodsInfos().get(0); + holder.setVisibility(R.id.rl_only_goods, View.VISIBLE); + ImageUtils.loadImage(holder.findViewById(R.id.iv_goods), goodsInfo.getGoodsMasterImg()); + holder.setText(R.id.tv_goods_name, goodsInfo.getGoodsName()); + holder.setText(R.id.tv_goods_price, String.format("¥%s", goodsInfo.getGoodsPrice())); + holder.setText(R.id.tv_goods_count, String.format("x%s", goodsInfo.getNum())); + } else { + //多种商品 + holder.setVisibility(R.id.rl_many, View.VISIBLE); + holder.setText(R.id.tv_goods_total_count, String.format("共%s件", ShoppingCartUtils.calculationGoodsCount(data.getGoodsInfos()))); + RecyclerView recyclerView = holder.findViewById(R.id.rv_goods_list); + recyclerView.setLayoutManager(new LinearLayoutManager(getContext(), RecyclerView.HORIZONTAL, false)); + recyclerView.setAdapter(new OrderSettlementGoodsInfoAdapter(getContext(), data.getGoodsInfos())); + if (onGoodsItemClickListener != null) { + holder.setOnClickListener(R.id.ll_more_goods_list, + v -> onGoodsItemClickListener.onMoreGoodsClick(data, layoutPosition)); + } + } + } + + /** + * 商品Item点击事件回调 + */ + public interface OnGoodsItemClickListener { + + /** + * 更多商品点击 + * + * @param data 供应商 + * @param position position + */ + void onMoreGoodsClick(Vendor data, int position); + } +} diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/cart/adapter/OrderSettlementGoodsInfoAdapter.java b/module_market/src/main/java/com/wss/module/market/ui/goods/cart/adapter/OrderSettlementGoodsInfoAdapter.java new file mode 100644 index 0000000..71f8d63 --- /dev/null +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/cart/adapter/OrderSettlementGoodsInfoAdapter.java @@ -0,0 +1,30 @@ +package com.wss.module.market.ui.goods.cart.adapter; + +import android.content.Context; + +import com.wss.common.base.adapter.BaseListAdapter; +import com.wss.common.utils.ImageUtils; +import com.wss.module.market.R; +import com.wss.module.market.bean.GoodsInfo; + +import org.byteam.superadapter.SuperViewHolder; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * Describe:订单页商品信息适配器 + * Created by 吴天强 on 2020/10/20. + */ +public class OrderSettlementGoodsInfoAdapter extends BaseListAdapter { + + + OrderSettlementGoodsInfoAdapter(Context context, List mData) { + super(context, mData, R.layout.market_item_of_order_goods_info, null); + } + + @Override + public void onBindData(@NotNull SuperViewHolder holder, int viewType, int layoutPosition, @NotNull GoodsInfo data) { + ImageUtils.loadImage(holder.findViewById(R.id.iv_goods), data.getGoodsMasterImg()); + } +} diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/cart/adapter/ShoppingCartAdapter.java b/module_market/src/main/java/com/wss/module/market/ui/goods/cart/adapter/ShoppingCartAdapter.java index 80177c1..6b2ef72 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/goods/cart/adapter/ShoppingCartAdapter.java +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/cart/adapter/ShoppingCartAdapter.java @@ -8,9 +8,9 @@ import android.widget.TextView; import com.wss.common.base.adapter.BaseListAdapter; +import com.wss.common.base.adapter.listener.OnListItemClickListener; import com.wss.common.bean.Event; import com.wss.common.constants.EventAction; -import com.wss.common.listener.OnListItemClickListener; import com.wss.common.utils.EventBusUtils; import com.wss.common.utils.ImageUtils; import com.wss.common.widget.CountClickView; @@ -31,17 +31,17 @@ * Describe:购物车适配器 * Created by 吴天强 on 2018/11/5. */ - public class ShoppingCartAdapter extends BaseListAdapter implements OnClickListener { private boolean isEdit; public void setEdit(boolean edit) { isEdit = edit; + notifyDataSetChanged(); } - public ShoppingCartAdapter(Context context, List items, int layoutResId, OnListItemClickListener listener) { - super(context, items, layoutResId, listener); + public ShoppingCartAdapter(Context context, List items, OnListItemClickListener listener) { + super(context, items, R.layout.market_item_of_shopping_cart_list, listener); } @Override @@ -53,7 +53,6 @@ public void onBindData(SuperViewHolder holder, int viewType, int layoutPosition, ivVendor.setTag(layoutPosition); ivVendor.setOnClickListener(this); goodsLayout.removeAllViews(); - for (int i = 0; i < data.getGoodsInfos().size(); i++) { View view = View.inflate(getContext(), R.layout.market_item_of_shopping_cart_list_goods_list, null); new ViewHolder(view).onBindData(layoutPosition, i); @@ -114,22 +113,14 @@ void onBindData(final int parent, final int child) { ccvClick.setMinCount(1); ccvClick.setMaxCount(99); ccvClick.setInput(true); - ccvClick.setCurrCount(goodsInfo.getNum() < 1 ? 1 : goodsInfo.getNum()); - ccvClick.setAfterClickListener(new CountClickView.OnClickAfterListener() { - @Override - public void onAfter(int value) { - //修改源数据 - getData().get(parent).getGoodsInfos().get(child).setNum(value); - //修改本地数据库数据 - goodsInfo.setNum(value); - ShoppingCartUtils.updateCartGoodsNum(goodsInfo); - updateCart(); - } - - @Override - public void onMin() { - - } + ccvClick.setCurrCount(Math.max(goodsInfo.getNum(), 1)); + ccvClick.setAfterClickListener((view, value) -> { + //修改源数据 + getData().get(parent).getGoodsInfos().get(child).setNum(value); + //修改本地数据库数据 + goodsInfo.setNum(value); + ShoppingCartUtils.updateCartGoodsNum(goodsInfo); + updateCart(); }); tvPrice.setVisibility(isEdit ? View.GONE : View.VISIBLE); ccvClick.setVisibility(isEdit ? View.GONE : View.VISIBLE); @@ -138,6 +129,6 @@ public void onMin() { private void updateCart() { //刷新购物车 - EventBusUtils.sendEvent(new Event(EventAction.EVENT_SHOPPING_CART_REFRESH)); + EventBusUtils.sendEvent(new Event(EventAction.EVENT_SHOPPING_CART_CHANGED)); } } diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/cart/mvp/CartPresenter.java b/module_market/src/main/java/com/wss/module/market/ui/goods/cart/mvp/CartPresenter.java index d62e174..6011c93 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/goods/cart/mvp/CartPresenter.java +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/cart/mvp/CartPresenter.java @@ -3,6 +3,7 @@ import com.wss.common.base.mvp.BasePresenter; import com.wss.module.market.bean.Vendor; import com.wss.module.market.ui.goods.cart.mvp.contract.ShoppingCartContract; +import com.wss.module.market.ui.goods.cart.mvp.model.ShoppingCartModel; import com.wss.module.market.utils.ShoppingCartUtils; import java.util.List; @@ -11,24 +12,21 @@ * Describe:购物车Presenter * Created by 吴天强 on 2018/11/5. */ +public class CartPresenter extends BasePresenter implements ShoppingCartContract.Presenter { -public class CartPresenter extends BasePresenter - implements ShoppingCartContract.Presenter { @Override public void getCartData() { - if (isViewAttached()) { - List localData = ShoppingCartUtils.getLocalData(); - if (localData == null || localData.size() < 1) { - getView().onEmpty(""); - } else { - getView().cartData(localData); - } + List localData = ShoppingCartUtils.getLocalData(); + if (localData == null || localData.size() < 1) { + getView().onEmpty(""); + } else { + getView().refreshCartData(localData); } } @Override - protected ShoppingCartContract.Model createModule() { - return null; + protected ShoppingCartModel createModule() { + return new ShoppingCartModel(getLifecycleOwner()); } @Override diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/cart/mvp/contract/ShoppingCartContract.java b/module_market/src/main/java/com/wss/module/market/ui/goods/cart/mvp/contract/ShoppingCartContract.java index 32fc135..cfe666a 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/goods/cart/mvp/contract/ShoppingCartContract.java +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/cart/mvp/contract/ShoppingCartContract.java @@ -1,6 +1,5 @@ package com.wss.module.market.ui.goods.cart.mvp.contract; -import com.wss.common.base.mvp.IBaseModel; import com.wss.common.base.mvp.IBaseView; import com.wss.module.market.bean.Vendor; @@ -13,18 +12,18 @@ public interface ShoppingCartContract { - interface Model extends IBaseModel{ + + interface Model { } interface View extends IBaseView { - /** * 购物车数据 * * @param dataList dataList */ - void cartData(List dataList); + void refreshCartData(List dataList); } interface Presenter { @@ -33,4 +32,5 @@ interface Presenter { */ void getCartData(); } + } diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/cart/mvp/model/ShoppingCartModel.java b/module_market/src/main/java/com/wss/module/market/ui/goods/cart/mvp/model/ShoppingCartModel.java new file mode 100644 index 0000000..cc72835 --- /dev/null +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/cart/mvp/model/ShoppingCartModel.java @@ -0,0 +1,17 @@ +package com.wss.module.market.ui.goods.cart.mvp.model; + +import com.wss.common.base.mvp.BaseModel; +import com.wss.module.market.ui.goods.cart.mvp.contract.ShoppingCartContract; + +import androidx.lifecycle.LifecycleOwner; + +/** + * Describe:购物车Model + * Created by 吴天强 on 2020/8/11. + */ +public class ShoppingCartModel extends BaseModel implements ShoppingCartContract.Model { + + public ShoppingCartModel(LifecycleOwner lifecycleOwner) { + super(lifecycleOwner); + } +} diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/GoodsDetailActivity.java b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/GoodsDetailActivity.java index 1c62503..1ebc173 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/GoodsDetailActivity.java +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/GoodsDetailActivity.java @@ -1,19 +1,31 @@ package com.wss.module.market.ui.goods.detail; +import android.os.Handler; +import android.text.TextUtils; import android.view.View; +import android.widget.ImageView; import android.widget.TextView; import com.wss.common.adapter.FragmentPagerAdapter; import com.wss.common.base.BaseActivity; import com.wss.common.base.BaseFragment; +import com.wss.common.bean.Event; import com.wss.common.bean.HorizontalTabTitle; +import com.wss.common.constants.Dic; +import com.wss.common.constants.EventAction; +import com.wss.common.manage.ActivityToActivity; +import com.wss.common.utils.EventBusUtils; +import com.wss.common.utils.ToastUtils; import com.wss.common.widget.NoScrollViewPager; import com.wss.common.widget.PagerSlidingTabStrip; import com.wss.module.market.R; import com.wss.module.market.R2; +import com.wss.module.market.bean.GoodsInfo; +import com.wss.module.market.ui.goods.cart.ShoppingCartActivity; import com.wss.module.market.ui.goods.detail.fragment.GoodsInfoDetailMainFragment; import com.wss.module.market.ui.goods.detail.fragment.GoodsInfoMainFragment; import com.wss.module.market.ui.goods.detail.fragment.child.GoodsCommentFragment; +import com.wss.module.market.utils.ShoppingCartUtils; import java.util.ArrayList; import java.util.List; @@ -36,6 +48,17 @@ public class GoodsDetailActivity extends BaseActivity { @BindView(R2.id.vp_content) public NoScrollViewPager vpContent; + @BindView(R2.id.tv_count) + TextView tvCount; + + @BindView(R2.id.iv_cart) + ImageView ivCart; + + //TODO 测试使用列表造的伪数据表示不同商品做加入购物车操作 + private GoodsInfo goodsInfo; + + private GoodsInfoMainFragment goodsInfoMainFragment; + @Override protected int getLayoutId() { return R.layout.market_activity_goods_details; @@ -43,6 +66,11 @@ protected int getLayoutId() { @Override protected void initView() { + setImmersionBarColor(R.color.theme); + if (getIntent() != null) { + goodsInfo = (GoodsInfo) getIntent().getSerializableExtra(Dic.GOODS_INFO); + } + List title = new ArrayList<>(); title.add(new HorizontalTabTitle("商品")); title.add(new HorizontalTabTitle("详情")); @@ -50,19 +78,19 @@ protected void initView() { List fragmentList = new ArrayList<>(); - fragmentList.add(new GoodsInfoMainFragment()); + fragmentList.add(goodsInfoMainFragment = new GoodsInfoMainFragment()); fragmentList.add(new GoodsInfoDetailMainFragment()); fragmentList.add(new GoodsCommentFragment()); vpContent.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager(), title, fragmentList)); vpContent.setOffscreenPageLimit(3); pstsTabs.setViewPager(vpContent); - } - @OnClick(R2.id.ll_back) - public void onClick(View v) { - finish(); + setCartNumber(); } + /** + * 设置内容 + */ public void setViewContent(boolean scrollToBottom) { if (scrollToBottom) { // 图文详情 @@ -77,7 +105,82 @@ public void setViewContent(boolean scrollToBottom) { } } + @Override + protected boolean registerEventBus() { + return true; + } + + @Override + public void onEventBus(Event event) { + super.onEventBus(event); + if (TextUtils.equals(EventAction.EVENT_SHOPPING_CART_REFRESH, event.getAction())) { + setCartNumber(); + } + } + + @Override + protected void onResume() { + super.onResume(); + setCartNumber(); + } + + @OnClick({R2.id.ll_back, R2.id.rl_cart, R2.id.tv_add_cart, R2.id.tv_buy_now}) + public void onViewClicked(View view) { + int i = view.getId(); + if (i == R.id.ll_back) { + finish(); + } else if (i == R.id.rl_cart) { + //去购物车 + ActivityToActivity.toActivity(context, ShoppingCartActivity.class); + } else if (i == R.id.tv_add_cart) { + //加入购物车 + if (goodsInfo != null) { + final long time = 500; + ivCart.animate() + .scaleX(1.3f) + .scaleY(1.3f) + .setDuration(time) + .start(); + new Handler().postDelayed(() -> { + goodsInfo.setNum(goodsInfoMainFragment.getGoodsCount()); + ShoppingCartUtils.addCartGoods(goodsInfo); + EventBusUtils.sendEvent(new Event(EventAction.EVENT_SHOPPING_CART_REFRESH)); + ivCart.animate() + .scaleX(1.0f) + .scaleY(1.0f) + .setDuration(time) + .start(); + }, time * 2); + + } else { + ToastUtils.show("没有正经的商品信息~"); + } + } else if (i == R.id.tv_buy_now) { + //立即购买 + ToastUtils.show("立即购买"); + } + } + + /** + * 设置购物车数量 + */ + private void setCartNumber() { + int count = ShoppingCartUtils.getCartCount(); + if (count < 1) { + tvCount.setVisibility(View.GONE); + } else { + tvCount.setVisibility(View.VISIBLE); + tvCount.setText(String.valueOf(count)); + } + } + + /** + * 切换Fragment + * + * @param position position + */ public void setCurrentFragment(int position) { vpContent.setCurrentItem(position); } + } diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/adapter/GoodsCommentAdapter.java b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/adapter/GoodsCommentAdapter.java index 1ec80ee..a1e1646 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/adapter/GoodsCommentAdapter.java +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/adapter/GoodsCommentAdapter.java @@ -1,7 +1,6 @@ package com.wss.module.market.ui.goods.detail.adapter; import android.content.Context; -import android.widget.ImageView; import com.wss.common.base.adapter.BaseListAdapter; import com.wss.common.utils.ImageUtils; @@ -20,13 +19,13 @@ public class GoodsCommentAdapter extends BaseListAdapter { - public GoodsCommentAdapter(Context context, List items, int layoutResId) { - super(context, items, layoutResId, null); + public GoodsCommentAdapter(Context context, List items) { + super(context, items, R.layout.market_item_of_goods_comment_list, null); } @Override public void onBindData(SuperViewHolder holder, int viewType, int layoutPosition, GoodsComment data) { - ImageUtils.loadImageCircle((ImageView) holder.findViewById(R.id.iv_head), data.getUserHead()); + ImageUtils.loadImageCircle(holder.findViewById(R.id.iv_head), data.getUserHead()); holder.setText(R.id.tv_name, data.getUserName()); holder.setText(R.id.tv_comment, data.getComment()); } diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/adapter/GoodsConfigAdapter.java b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/adapter/GoodsConfigAdapter.java index e217f2f..e9ea90c 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/adapter/GoodsConfigAdapter.java +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/adapter/GoodsConfigAdapter.java @@ -17,8 +17,8 @@ public class GoodsConfigAdapter extends BaseListAdapter { - public GoodsConfigAdapter(Context context, List items, int layoutResId) { - super(context, items, layoutResId, null); + public GoodsConfigAdapter(Context context, List items) { + super(context, items, R.layout.market_item_of_goods_config_list, null); } @Override diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/adapter/RecommendGoodsAdapter.java b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/adapter/RecommendGoodsAdapter.java index da0485d..d103ee2 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/adapter/RecommendGoodsAdapter.java +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/adapter/RecommendGoodsAdapter.java @@ -1,20 +1,20 @@ package com.wss.module.market.ui.goods.detail.adapter; import android.content.Context; -import android.support.v7.widget.GridLayoutManager; -import android.support.v7.widget.RecyclerView; import android.view.View; import com.bigkoo.convenientbanner.holder.CBViewHolderCreator; import com.bigkoo.convenientbanner.holder.Holder; -import com.wss.common.listener.OnListItemClickListener; -import com.wss.common.utils.ActivityToActivity; +import com.wss.common.manage.ActivityToActivity; import com.wss.module.market.R; import com.wss.module.market.bean.GoodsInfo; import com.wss.module.market.ui.goods.detail.GoodsDetailActivity; import java.util.List; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + /** * Describe:商品详情-店主推荐-商品滑动适配器 配合ConvenientBanner 使用 * Created by 吴天强 on 2018/10/19. @@ -40,12 +40,9 @@ protected void initView(View itemView) { @Override public void updateUI(List data) { recyclerView.setLayoutManager(new GridLayoutManager(mContext, 2)); - recyclerView.setAdapter(new RecommendGoodsInfoAdapter(mContext, data, R.layout.market_item_of_goods_recommend_list, new OnListItemClickListener() { - @Override - public void onItemClick(View view, int position) { - //推荐位商品详情 - ActivityToActivity.toActivity(mContext, GoodsDetailActivity.class); - } + recyclerView.setAdapter(new RecommendGoodsInfoAdapter(mContext, data, (data1, position) -> { + //推荐位商品详情 + ActivityToActivity.toActivity(mContext, GoodsDetailActivity.class); })); } }; diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/adapter/RecommendGoodsInfoAdapter.java b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/adapter/RecommendGoodsInfoAdapter.java index 89402b9..75d9bbe 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/adapter/RecommendGoodsInfoAdapter.java +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/adapter/RecommendGoodsInfoAdapter.java @@ -2,11 +2,10 @@ import android.content.Context; import android.graphics.Paint; -import android.widget.ImageView; import android.widget.TextView; import com.wss.common.base.adapter.BaseListAdapter; -import com.wss.common.listener.OnListItemClickListener; +import com.wss.common.base.adapter.listener.OnListItemClickListener; import com.wss.common.utils.ImageUtils; import com.wss.module.market.R; import com.wss.module.market.bean.GoodsInfo; @@ -23,14 +22,13 @@ public class RecommendGoodsInfoAdapter extends BaseListAdapter { - public RecommendGoodsInfoAdapter(Context context, List items, int layoutResId, OnListItemClickListener listener) { - super(context, items, layoutResId, listener); + public RecommendGoodsInfoAdapter(Context context, List items, OnListItemClickListener listener) { + super(context, items, R.layout.market_item_of_goods_recommend_list, listener); } @Override public void onBindData(SuperViewHolder holder, int viewType, int layoutPosition, GoodsInfo data) { - - ImageUtils.loadImage((ImageView) holder.findViewById(R.id.iv_goods), data.getGoodsMasterImg()); + ImageUtils.loadImage(holder.findViewById(R.id.iv_goods), data.getGoodsMasterImg()); holder.setText(R.id.tv_goods_name, data.getGoodsName()); holder.setText(R.id.tv_goods_price, String.format("¥%s", data.getGoodsPrice())); diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/GoodsInfoDetailMainFragment.java b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/GoodsInfoDetailMainFragment.java index ad936da..860511f 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/GoodsInfoDetailMainFragment.java +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/GoodsInfoDetailMainFragment.java @@ -1,8 +1,5 @@ package com.wss.module.market.ui.goods.detail.fragment; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentTransaction; import android.view.View; import android.view.animation.TranslateAnimation; import android.widget.FrameLayout; @@ -17,6 +14,9 @@ import java.util.ArrayList; import java.util.List; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; import butterknife.BindView; import butterknife.OnClick; diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/GoodsInfoMainFragment.java b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/GoodsInfoMainFragment.java index bdc634b..3dd5ba3 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/GoodsInfoMainFragment.java +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/GoodsInfoMainFragment.java @@ -2,8 +2,6 @@ import android.content.Context; import android.graphics.Paint; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; @@ -13,6 +11,8 @@ import com.bigkoo.convenientbanner.ConvenientBanner; import com.wss.common.adapter.BannerImgAdapter; import com.wss.common.base.BaseMvpFragment; +import com.wss.common.bean.Banner; +import com.wss.common.widget.CountClickView; import com.wss.common.widget.SlideLayout; import com.wss.module.market.R; import com.wss.module.market.R2; @@ -21,11 +21,14 @@ import com.wss.module.market.ui.goods.detail.GoodsDetailActivity; import com.wss.module.market.ui.goods.detail.adapter.GoodsCommentAdapter; import com.wss.module.market.ui.goods.detail.adapter.RecommendGoodsAdapter; +import com.wss.module.market.ui.goods.detail.helper.GoodsSpecificationPop; import com.wss.module.market.ui.goods.detail.mvp.GoodsDetailPresenter; import com.wss.module.market.ui.goods.detail.mvp.contract.GoodsDetailContract; import java.util.List; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import butterknife.BindView; import butterknife.OnClick; @@ -37,7 +40,7 @@ public class GoodsInfoMainFragment extends BaseMvpFragment SlideLayout.OnSlideDetailsListener, GoodsDetailContract.View { @BindView(R2.id.vp_item_goods_img) - ConvenientBanner vpItemGoodsImg; + ConvenientBanner vpItemGoodsImg; @BindView(R2.id.tv_goods_name) TextView tvGoodsName; @@ -66,6 +69,9 @@ public class GoodsInfoMainFragment extends BaseMvpFragment @BindView(R2.id.sv_switch) SlideLayout svSwitch; + @BindView(R2.id.ccv_click) + CountClickView ccvClick;//商品数量加减控件 + /** * 当前商品详情数据页的索引分别是图文详情、规格参数 @@ -86,20 +92,27 @@ protected int getLayoutId() { @Override protected void initView() { + + ccvClick.setMinCount(1); + ccvClick.setCurrCount(1); svSwitch.setOnSlideDetailsListener(this); //设置文字中间一条横线 tvOldPrice.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG); - presenter.start(); + getPresenter().start(); } - @OnClick({R2.id.ll_pull_up, R2.id.ll_comment}) + @OnClick({R2.id.ll_pull_up, R2.id.ll_comment, R2.id.miv_goods_specification}) public void onClick(View v) { - if (v.getId() == R.id.ll_pull_up) {//上拉查看图文详情 + if (v.getId() == R.id.ll_pull_up) { + //上拉查看图文详情 svSwitch.smoothOpen(true); } else if (v.getId() == R.id.ll_comment) { //查看评论 goodsDetailActivity.setCurrentFragment(2); + } else if (v.getId() == R.id.miv_goods_specification) { + //选择商品规格 + GoodsSpecificationPop.getInstance(context).show(v); } } @@ -119,7 +132,7 @@ private void setGoodsHeadImg() { vpItemGoodsImg.setPages(new BannerImgAdapter() { @Override public ImageView getImageView() { - ImageView imageView = new ImageView(mContext); + ImageView imageView = new ImageView(context); imageView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); return imageView; @@ -150,27 +163,27 @@ public String getGoodsId() { } @Override - public void goodsInfo(GoodsInfo goodsInfo) { + public void refreshGoodsInfo(GoodsInfo goodsInfo) { this.goodsInfo = goodsInfo; setGoodsHeadImg(); setGoodsInfo(); } @Override - public void recommendList(List> recommendList) { + public void refreshRecommendList(List> recommendList) { //加载推荐位商品 - vpRecommend.setPages(new RecommendGoodsAdapter(mContext), recommendList) + vpRecommend.setPages(new RecommendGoodsAdapter(context), recommendList) .setCanLoop(recommendList.size() != 1) .setPageIndicator(new int[]{R.drawable.shape_item_index_white, R.drawable.shape_item_index_red}) .setPageIndicatorAlign(ConvenientBanner.PageIndicatorAlign.CENTER_HORIZONTAL); } @Override - public void commentList(List commentList) { + public void refreshCommentList(List commentList) { if (commentList.size() > 0) { tvEmptyComment.setVisibility(View.GONE); - recyclerView.setLayoutManager(new LinearLayoutManager(mContext)); - recyclerView.setAdapter(new GoodsCommentAdapter(mContext, commentList, R.layout.market_item_of_goods_comment_list)); + recyclerView.setLayoutManager(new LinearLayoutManager(context)); + recyclerView.setAdapter(new GoodsCommentAdapter(context, commentList)); } else { tvEmptyComment.setVisibility(View.VISIBLE); tvEmptyComment.setText("暂无精彩评论"); @@ -182,4 +195,13 @@ public void commentList(List commentList) { protected GoodsDetailPresenter createPresenter() { return new GoodsDetailPresenter(); } + + /** + * 得到当前商品增减数量 + * + * @return int + */ + public int getGoodsCount() { + return ccvClick.getCount(); + } } diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/child/GoodsCommentFragment.java b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/child/GoodsCommentFragment.java index 5f2edc9..6179af2 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/child/GoodsCommentFragment.java +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/child/GoodsCommentFragment.java @@ -1,7 +1,5 @@ package com.wss.module.market.ui.goods.detail.fragment.child; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.ImageView; import android.widget.TextView; @@ -17,6 +15,8 @@ import java.util.ArrayList; import java.util.List; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import butterknife.BindView; /** @@ -51,9 +51,8 @@ protected int getLayoutId() { @Override protected void initView() { - - adapter = new GoodsCommentAdapter(mContext, commentList, R.layout.market_item_of_goods_comment_list); - recycleView.setLayoutManager(new LinearLayoutManager(mContext)); + adapter = new GoodsCommentAdapter(context, commentList); + recycleView.setLayoutManager(new LinearLayoutManager(context)); recycleView.setAdapter(adapter); ivRight.setVisibility(View.GONE); @@ -61,13 +60,12 @@ protected void initView() { recycleView.setVisibility(View.VISIBLE); tvCommentCount.setText("用户点评(999)"); tvPraiseRate.setText("好评率97.8%"); - - presenter.start(); + getPresenter().start(); } @Override - public void commentList(List commentList) { + public void refreshCommentList(List commentList) { this.commentList.addAll(commentList); adapter.notifyDataSetChanged(); } diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/child/GoodsConfigFragment.java b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/child/GoodsConfigFragment.java index f1093ff..b1a4805 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/child/GoodsConfigFragment.java +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/child/GoodsConfigFragment.java @@ -31,9 +31,21 @@ protected int getLayoutId() { protected void initView() { listView.setFocusable(false); List data = new ArrayList<>(); - data.add(new GoodsConfigBean("品牌", "小米Mix 3")); - data.add(new GoodsConfigBean("型号", "全面屏 小米Mix 3")); - listView.setAdapter(new GoodsConfigAdapter(mContext, data, R.layout.market_item_of_goods_config_list)); + data.add(new GoodsConfigBean("品牌", "小米(MI)")); + data.add(new GoodsConfigBean("型号", "小米MIX3")); + data.add(new GoodsConfigBean("入网型号", "以官网信息为准")); + data.add(new GoodsConfigBean("上市时间", "2018年10月")); + data.add(new GoodsConfigBean("操作系统", "Android")); + data.add(new GoodsConfigBean("CPU", "骁龙845 八核")); + data.add(new GoodsConfigBean("ROM", "128GB")); + data.add(new GoodsConfigBean("RAM", "8GM")); + data.add(new GoodsConfigBean("网络支持", "2G/3G/4G")); + data.add(new GoodsConfigBean("屏幕尺寸", "3.98英寸")); + data.add(new GoodsConfigBean("分辨率", "2340*1080")); + data.add(new GoodsConfigBean("摄像头", "2400万+2000万像素")); + data.add(new GoodsConfigBean("电池容量(mAh)", "3200mAh (typ)/ 3100mAh (min)")); + data.add(new GoodsConfigBean("数据接口", "蓝牙/NFC")); + listView.setAdapter(new GoodsConfigAdapter(context, data)); } diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/child/GoodsInfoWebFragment.java b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/child/GoodsInfoWebFragment.java index 9932a0c..d126588 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/child/GoodsInfoWebFragment.java +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/fragment/child/GoodsInfoWebFragment.java @@ -31,9 +31,9 @@ protected void initView() { } public void initWebView() { - String url = "http://m.okhqb.com/item/description/1000334264.html?fromApp=true"; +// String url = "http://m.okhqb.com/item/description/1000334264.html?fromApp=true"; webView.setFocusable(false); - webView.loadUrl(url); + webView.loadUrl("file:///android_asset/html/goods_detail.html"); webSettings = webView.getSettings(); webSettings.setLoadWithOverviewMode(true); webSettings.setBuiltInZoomControls(true); diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/helper/GoodsSpecificationPop.java b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/helper/GoodsSpecificationPop.java new file mode 100644 index 0000000..58e3bee --- /dev/null +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/helper/GoodsSpecificationPop.java @@ -0,0 +1,106 @@ +package com.wss.module.market.ui.goods.detail.helper; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.PopupWindow; +import android.widget.TextView; + +import com.wss.common.utils.ImageUtils; +import com.wss.common.utils.PxUtils; +import com.wss.common.widget.FlowLayout; +import com.wss.module.market.R; +import com.wss.module.market.R2; + +import butterknife.BindView; +import butterknife.ButterKnife; + +/** + * Describe:商品规格Pop + * Created by 吴天强 on 2019/1/31. + */ + +public class GoodsSpecificationPop extends PopupWindow { + + private String imgUrl = "https://img14.360buyimg.com/n0/jfs/t1/1867/31/11716/401006/5bd072f8E6db292ab/f3610e2e816ade0f.jpg"; + private String[] colors = new String[]{"黑色", "宝石蓝", "翡翠绿", "红色", "藏青色", "胡杨黄"}; + private String[] versions = new String[]{"6GB+128G", "8GB+128GB", "8GB+256GB", "10GB+256GB"}; + private String[] buyWays = new String[]{"官网套餐", "碎屏保险服务", "故宫特别版", "贴膜套装"}; + + + private Context context; + @SuppressLint("StaticFieldLeak") + private static GoodsSpecificationPop specificationPop; + + @BindView(R2.id.fl_color) + FlowLayout flColor;//颜色 + + @BindView(R2.id.fl_version) + FlowLayout flVersion;//版本 + + @BindView(R2.id.fl_buy_way) + FlowLayout flBuyWay;//购买方式 + + @BindView(R2.id.iv_goods_img) + ImageView imageView; + + public GoodsSpecificationPop(Context context) { + this.context = context; + } + + public static synchronized GoodsSpecificationPop getInstance(Context context) { + if (specificationPop == null) { + specificationPop = new GoodsSpecificationPop(context); + } + return specificationPop; + } + + public void show(View parent) { + View view = View.inflate(context, R.layout.market_pop_goods_specification, null); + ButterKnife.bind(this, view); + setAnimationStyle(R.style.AnimSheetBottom); + setBackgroundDrawable(new ColorDrawable(0)); + setWidth(ViewGroup.LayoutParams.MATCH_PARENT); + setHeight(ViewGroup.LayoutParams.MATCH_PARENT); + setFocusable(true); + setOutsideTouchable(true); + setContentView(view); + showAtLocation(parent, Gravity.CENTER, 0, 0); + loadData(); + update(); + } + + private void loadData() { + ImageUtils.loadImage(imageView, imgUrl); + flColor.removeAllViews(); + //加载颜色 + for (String color : colors) { + TextView textView = new TextView(context); + textView.setText(color); + textView.setBackgroundResource(R.drawable.market_bg_of_ellipse_button_select); +// textView.setTextColor(R.color.market_goods_button_text_color); + textView.setTextColor(Color.BLACK); + ViewGroup.MarginLayoutParams mlp = new ViewGroup.MarginLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + mlp.setMargins(0, PxUtils.dp2px(5), PxUtils.dp2px(5), 0); + textView.setLayoutParams(mlp); + textView.setPadding(PxUtils.dp2px(10), PxUtils.dp2px(4), PxUtils.dp2px(10), PxUtils.dp2px(4)); + textView.setGravity(Gravity.CENTER); + textView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + v.setSelected(!v.isSelected()); + } + }); + + flColor.addView(textView); + } + + + } + +} diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/GoodsCommentPresent.java b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/GoodsCommentPresent.java index 3c880b2..5d9e376 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/GoodsCommentPresent.java +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/GoodsCommentPresent.java @@ -3,6 +3,7 @@ import com.wss.common.base.mvp.BasePresenter; import com.wss.module.market.bean.GoodsComment; import com.wss.module.market.ui.goods.detail.mvp.contract.GoodsCommentContract; +import com.wss.module.market.ui.goods.detail.mvp.model.GoodsCommentModel; import java.util.ArrayList; import java.util.List; @@ -12,99 +13,108 @@ * Created by 吴天强 on 2018/11/5. */ -public class GoodsCommentPresent extends BasePresenter +public class GoodsCommentPresent extends BasePresenter implements GoodsCommentContract.Presenter { @Override public void getGoodsCommentList() { - if (isViewAttached()) { - List commentList = new ArrayList<>(); - GoodsComment comment = new GoodsComment(); - comment.setComment("手机到了刚弄好,非常流畅"); - comment.setStar(5); - comment.setUserHead("http://i10.hoopchina.com.cn/hupuapp/bbs/966/16313966/thread_16313966_20180726164538_s_65949_o_w1024_h1024_62044.jpg?x-oss-process=image/resize,w_800/format,jpg"); - comment.setUserName("噶***蛋"); - commentList.add(comment); - - comment = new GoodsComment(); - comment.setComment("最重要的还是手机,各种操作都很流畅信号各方面都没有问题,谢谢!"); - comment.setStar(2); - comment.setUserHead("https://img4.duitang.com/uploads/item/201602/01/20160201111345_4kvQA.jpeg"); - comment.setUserName("王***想"); - commentList.add(comment); - - comment = new GoodsComment(); - comment.setComment("物流速度很给力,同时店家也很有耐心客服也很有责任心各种操作都很流畅信号各方面都没有问题,谢谢!"); - comment.setStar(3); - comment.setUserName("阿***蛋"); - comment.setUserHead("https://img4.duitang.com/uploads/item/201601/16/20160116161347_svH5y.thumb.224_0.jpeg"); - commentList.add(comment); - - comment = new GoodsComment(); - comment.setComment("雷总果然强大,谢谢!"); - comment.setStar(1); - comment.setUserName("P***去"); - comment.setUserHead("http://img1.touxiang.cn/uploads/20130927/27-020608_93.jpg"); - commentList.add(comment); - - comment = new GoodsComment(); - comment.setComment("雷总果然强大,家里好多电器都是小米的"); - comment.setStar(3); - comment.setUserHead("http://imgsrc.baidu.com/imgad/pic/item/ca1349540923dd54afaa0d4bdb09b3de9c82483c.jpg"); - comment.setUserName("补***萨"); - commentList.add(comment); - - comment = new GoodsComment(); - comment.setComment("手机到了刚弄好,非常流畅,家里好多电器都是小米的 谢谢!"); - comment.setStar(5); - comment.setUserHead("http://img1.touxiang.cn/uploads/20131017/17-090235_674.jpg"); - comment.setUserName("b***y"); - commentList.add(comment); - - - comment = new GoodsComment(); - comment.setComment("雷总果然强大,谢谢!"); - comment.setStar(1); - comment.setUserName("P***去"); - comment.setUserHead("http://img1.touxiang.cn/uploads/20130927/27-020608_93.jpg"); - commentList.add(comment); - - comment = new GoodsComment(); - comment.setComment("物流速度很给力,同时店家也很有耐心客服也很有责任心各种操作都很流畅信号各方面都没有问题,谢谢!"); - comment.setStar(3); - comment.setUserName("阿***蛋"); - comment.setUserHead("https://img4.duitang.com/uploads/item/201601/16/20160116161347_svH5y.thumb.224_0.jpeg"); - commentList.add(comment); - - comment = new GoodsComment(); - comment.setComment("雷总果然强大,家里好多电器都是小米的"); - comment.setStar(3); - comment.setUserHead("http://imgsrc.baidu.com/imgad/pic/item/ca1349540923dd54afaa0d4bdb09b3de9c82483c.jpg"); - comment.setUserName("补***萨"); - commentList.add(comment); - - comment = new GoodsComment(); - comment.setComment("雷总果然强大,谢谢!"); - comment.setStar(1); - comment.setUserName("P***去"); - comment.setUserHead("http://img1.touxiang.cn/uploads/20130927/27-020608_93.jpg"); - commentList.add(comment); - - comment = new GoodsComment(); - comment.setComment("最重要的还是手机,各种操作都很流畅信号各方面都没有问题,谢谢!"); - comment.setStar(2); - comment.setUserHead("https://img4.duitang.com/uploads/item/201602/01/20160201111345_4kvQA.jpeg"); - comment.setUserName("王***想"); - commentList.add(comment); - getView().commentList(commentList); - } + List commentList = new ArrayList<>(); + GoodsComment comment = new GoodsComment(); + comment.setComment("手机到了刚弄好,非常流畅!就是电池不耐用,充一次用不到一天就没了 呸"); + comment.setStar(5); + comment.setDate("2020年10月20日09:47:59"); + comment.setUserHead("http://i10.hoopchina.com.cn/hupuapp/bbs/966/16313966/thread_16313966_20180726164538_s_65949_o_w1024_h1024_62044.jpg?x-oss-process=image/resize,w_800/format,jpg"); + comment.setUserName("噶***蛋"); + commentList.add(comment); + + comment = new GoodsComment(); + comment.setComment("最重要的还是手机,各种操作都很流畅信号各方面都没有问题,谢谢!"); + comment.setStar(2); + comment.setDate("2020年10月20日09:47:59"); + comment.setUserHead("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603168237890&di=e924574070032a4d98643123d7e11586&imgtype=0&src=https%3A%2F%2Fround-lake.dustinice.workers.dev%3A443%2Fhttp%2Fcdn.duitang.com%2Fuploads%2Fitem%2F201410%2F08%2F20141008210803_Kxjhf.thumb.700_0.jpeg"); + comment.setUserName("王***想"); + commentList.add(comment); + + comment = new GoodsComment(); + comment.setComment("物流速度很给力,同时店家也很有耐心客服也很有责任心各种操作都很流畅信号各方面都没有问题,谢谢!"); + comment.setStar(3); + comment.setUserName("阿***蛋"); + comment.setDate("2020年10月20日09:47:59"); + comment.setUserHead("hhttps://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603168239065&di=e5b7ef4102677e10de3de3bfebf5491a&imgtype=0&src=https%3A%2F%2Fround-lake.dustinice.workers.dev%3A443%2Fhttp%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201708%2F23%2F20170823102305_WeA2y.thumb.700_0.jpeg"); + commentList.add(comment); + + comment = new GoodsComment(); + comment.setComment("雷总果然强大,谢谢!"); + comment.setStar(1); + comment.setUserName("P***去"); + comment.setUserHead("http://img1.touxiang.cn/uploads/20130927/27-020608_93.jpg"); + commentList.add(comment); + comment.setDate("2020年10月20日09:47:59"); + + comment = new GoodsComment(); + comment.setComment("雷总果然强大,家里好多电器都是小米的"); + comment.setStar(3); + comment.setDate("2020年10月20日09:47:59"); + comment.setUserHead("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603168241013&di=6d4f6b4f0995325f4723460d0d956f1c&imgtype=0&src=https%3A%2F%2Fround-lake.dustinice.workers.dev%3A443%2Fhttp%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20171114%2F0fc43e9ad58f4a5cb41a018925b0e475.jpeg"); + comment.setUserName("补***萨"); + commentList.add(comment); + + comment = new GoodsComment(); + comment.setComment("手机到了刚弄好,非常流畅,家里好多电器都是小米的 谢谢!"); + comment.setStar(5); + comment.setUserHead("http://img1.touxiang.cn/uploads/20131017/17-090235_674.jpg"); + comment.setUserName("b***y"); + comment.setDate("2020年10月20日09:47:59"); + commentList.add(comment); + + + comment = new GoodsComment(); + comment.setComment("雷总果然强大,谢谢!"); + comment.setStar(1); + comment.setDate("2020年10月20日09:47:59"); + comment.setUserName("P***去"); + comment.setUserHead("http://img1.touxiang.cn/uploads/20130927/27-020608_93.jpg"); + commentList.add(comment); + + comment = new GoodsComment(); + comment.setComment("物流速度很给力,同时店家也很有耐心客服也很有责任心各种操作都很流畅信号各方面都没有问题,谢谢!"); + comment.setStar(3); + comment.setDate("2020年10月20日09:47:59"); + comment.setUserName("阿***蛋"); + comment.setUserHead("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603168242468&di=e62f8708f01cd7f85ef0a40bfa1fdee1&imgtype=0&src=https%3A%2F%2Fround-lake.dustinice.workers.dev%3A443%2Fhttp%2Fgaitaobao4.alicdn.com%2Ftfscom%2Fi4%2F2040947480%2FTB27GrsAgmTBuNjy1XbXXaMrVXa_%2521%25212040947480.jpg_300x300q90.jpg"); + commentList.add(comment); + + comment = new GoodsComment(); + comment.setComment("雷总果然强大,家里好多电器都是小米的"); + comment.setStar(3); + comment.setDate("2020年10月20日09:47:59"); + comment.setUserHead("https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2456975006,3192848039&fm=26&gp=0.jpg"); + comment.setUserName("补***萨"); + commentList.add(comment); + + comment = new GoodsComment(); + comment.setComment("雷总果然强大,谢谢!"); + comment.setStar(1); + comment.setDate("2020年10月20日09:47:59"); + comment.setUserName("P***去"); + comment.setUserHead("http://img1.touxiang.cn/uploads/20130927/27-020608_93.jpg"); + commentList.add(comment); + + comment = new GoodsComment(); + comment.setComment("最重要的还是手机,各种操作都很流畅信号各方面都没有问题,谢谢!"); + comment.setStar(2); + comment.setUserHead("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603168248736&di=7e59800fa7af4c3194872a78540af6f9&imgtype=0&src=https%3A%2F%2Fround-lake.dustinice.workers.dev%3A443%2Fhttp%2Ftupian.qqw21.com%2Farticle%2FUploadPic%2F2020-9%2F2020922033115276.jpg"); + comment.setUserName("王***想"); + commentList.add(comment); + comment.setDate("2020年10月20日09:47:59"); + getView().refreshCommentList(commentList); } @Override - protected GoodsCommentContract.Model createModule() { - return null; + protected GoodsCommentModel createModule() { + return new GoodsCommentModel(getLifecycleOwner()); } @Override diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/GoodsDetailPresenter.java b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/GoodsDetailPresenter.java index 93cef66..6f4b26e 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/GoodsDetailPresenter.java +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/GoodsDetailPresenter.java @@ -1,9 +1,11 @@ package com.wss.module.market.ui.goods.detail.mvp; import com.wss.common.base.mvp.BasePresenter; +import com.wss.common.bean.Banner; import com.wss.module.market.bean.GoodsComment; import com.wss.module.market.bean.GoodsInfo; import com.wss.module.market.ui.goods.detail.mvp.contract.GoodsDetailContract; +import com.wss.module.market.ui.goods.detail.mvp.model.GoodsDetailModel; import java.util.ArrayList; import java.util.List; @@ -13,7 +15,7 @@ * Created by 吴天强 on 2018/11/1. */ -public class GoodsDetailPresenter extends BasePresenter +public class GoodsDetailPresenter extends BasePresenter implements GoodsDetailContract.Presenter { @@ -22,24 +24,22 @@ public class GoodsDetailPresenter extends BasePresenter goodsImgs = new ArrayList<>(); - goodsImgs.add("https://img14.360buyimg.com/n0/jfs/t1/1867/31/11716/401006/5bd072f8E6db292ab/f3610e2e816ade0f.jpg"); - goodsImgs.add("https://img14.360buyimg.com/n0/jfs/t1/2695/31/11550/73677/5bd072f8E7a7372dc/0a3da61ccc9e3762.jpg"); - goodsImgs.add("https://img14.360buyimg.com/n0/jfs/t1/708/33/12050/20042/5bd072f9E6702c378/3d2b5d137aea371a.jpg"); - goodsInfo.setGoodsHeadImg(goodsImgs); - goodsInfo.setGoodsOldPrice("9999"); - goodsInfo.setGoodsPrice("3999"); - goodsInfo.setCommentCount("999"); - goodsInfo.setPraiseRate("97.8%"); - getView().goodsInfo(goodsInfo); - } + //造伪数据 + GoodsInfo goodsInfo = new GoodsInfo(); + goodsInfo.setGoodsId("1"); + goodsInfo.setGoodsName("小米Mix3 6GB+128GB黑色 骁龙845 全网通4G 双卡双待 全面屏拍照游戏智能手机"); + goodsInfo.setVendorId("1"); + goodsInfo.setGoodsMasterImg("https://img14.360buyimg.com/n0/jfs/t1/1768/16/11748/360528/5bd072f8E06e4e532/b5d152da8a5dd0dc.jpg"); + List goodsImgs = new ArrayList<>(); + goodsImgs.add(new Banner("https://img14.360buyimg.com/n0/jfs/t1/1867/31/11716/401006/5bd072f8E6db292ab/f3610e2e816ade0f.jpg")); + goodsImgs.add(new Banner("https://img14.360buyimg.com/n0/jfs/t1/2695/31/11550/73677/5bd072f8E7a7372dc/0a3da61ccc9e3762.jpg")); + goodsImgs.add(new Banner("https://img14.360buyimg.com/n0/jfs/t1/708/33/12050/20042/5bd072f9E6702c378/3d2b5d137aea371a.jpg")); + goodsInfo.setGoodsHeadImg(goodsImgs); + goodsInfo.setGoodsOldPrice("9999"); + goodsInfo.setGoodsPrice("3999"); + goodsInfo.setCommentCount("999"); + goodsInfo.setPraiseRate("97.8%"); + getView().refreshGoodsInfo(goodsInfo); } /** @@ -47,44 +47,42 @@ public void getGoodsInfo() { */ @Override public void getRecommendList() { - if (isViewAttached()) { - List> recommendList = new ArrayList<>(); - List goodsInfoList1 = new ArrayList<>(); - GoodsInfo goodsInfo1 = new GoodsInfo(); - goodsInfo1.setGoodsId("1"); - goodsInfo1.setGoodsName("小米(MI) 小米mix3 手机 黑色 全网通6G RAM 128G ROM "); - goodsInfo1.setGoodsMasterImg("https://img14.360buyimg.com/n0/jfs/t1/8925/38/4406/349935/5bdad9b1Eb8638a99/0c7c764b234e0c02.jpg"); - goodsInfo1.setGoodsOldPrice("777"); - goodsInfo1.setGoodsPrice("3899"); - goodsInfoList1.add(goodsInfo1); - GoodsInfo goodsInfo2 = new GoodsInfo(); - goodsInfo2.setGoodsId("1"); - goodsInfo2.setGoodsName("小米(MI) 送豪礼 Mix3手机 全面屏 黑色 8G+256G "); - goodsInfo2.setGoodsMasterImg("https://img14.360buyimg.com/n0/jfs/t1/8996/26/2402/124002/5bd27d42E7c3950db/f51f482b3c0a50e6.jpg"); - goodsInfo2.setGoodsOldPrice("8888"); - goodsInfo2.setGoodsPrice("4699"); - goodsInfoList1.add(goodsInfo2); - - List goodsInfoList2 = new ArrayList<>(); - GoodsInfo goodsInfo3 = new GoodsInfo(); - goodsInfo3.setGoodsId("1"); - goodsInfo3.setGoodsName("小米(MI) MIX2S 全面屏手机 游戏手机 白 全网通(6G+128G)"); - goodsInfo3.setGoodsMasterImg("https://img14.360buyimg.com/n1/s546x546_jfs/t22591/58/2380284311/151588/1344c74b/5b7d2296N224823a9.jpg"); - goodsInfo3.setGoodsOldPrice("10001"); - goodsInfo3.setGoodsPrice("5688"); - goodsInfoList2.add(goodsInfo3); - GoodsInfo goodsInfo4 = new GoodsInfo(); - goodsInfo4.setGoodsId("1"); - goodsInfo4.setGoodsName(" 小米(MI) 小米 MIX2 手机s 黑色 全网通(6G+64G)"); - goodsInfo4.setGoodsMasterImg("https://img14.360buyimg.com/n0/jfs/t26539/294/374934442/170031/37ad9714/5b8f9d4eN5455c30c.jpg"); - goodsInfo4.setGoodsOldPrice("3333"); - goodsInfo4.setGoodsPrice("2049"); - goodsInfoList2.add(goodsInfo4); - - recommendList.add(goodsInfoList1); - recommendList.add(goodsInfoList2); - getView().recommendList(recommendList); - } + List> recommendList = new ArrayList<>(); + List goodsInfoList1 = new ArrayList<>(); + GoodsInfo goodsInfo1 = new GoodsInfo(); + goodsInfo1.setGoodsId("1"); + goodsInfo1.setGoodsName("小米(MI) 小米mix3 手机 黑色 全网通6G RAM 128G ROM "); + goodsInfo1.setGoodsMasterImg("https://img14.360buyimg.com/n0/jfs/t1/8925/38/4406/349935/5bdad9b1Eb8638a99/0c7c764b234e0c02.jpg"); + goodsInfo1.setGoodsOldPrice("777"); + goodsInfo1.setGoodsPrice("3899"); + goodsInfoList1.add(goodsInfo1); + GoodsInfo goodsInfo2 = new GoodsInfo(); + goodsInfo2.setGoodsId("1"); + goodsInfo2.setGoodsName("小米(MI) 送豪礼 Mix3手机 全面屏 黑色 8G+256G "); + goodsInfo2.setGoodsMasterImg("https://img14.360buyimg.com/n0/jfs/t1/8996/26/2402/124002/5bd27d42E7c3950db/f51f482b3c0a50e6.jpg"); + goodsInfo2.setGoodsOldPrice("8888"); + goodsInfo2.setGoodsPrice("4699"); + goodsInfoList1.add(goodsInfo2); + + List goodsInfoList2 = new ArrayList<>(); + GoodsInfo goodsInfo3 = new GoodsInfo(); + goodsInfo3.setGoodsId("1"); + goodsInfo3.setGoodsName("小米(MI) MIX2S 全面屏手机 游戏手机 白 全网通(6G+128G)"); + goodsInfo3.setGoodsMasterImg("https://img14.360buyimg.com/n1/s546x546_jfs/t22591/58/2380284311/151588/1344c74b/5b7d2296N224823a9.jpg"); + goodsInfo3.setGoodsOldPrice("10001"); + goodsInfo3.setGoodsPrice("5688"); + goodsInfoList2.add(goodsInfo3); + GoodsInfo goodsInfo4 = new GoodsInfo(); + goodsInfo4.setGoodsId("1"); + goodsInfo4.setGoodsName(" 小米(MI) 小米 MIX2 手机s 黑色 全网通(6G+64G)"); + goodsInfo4.setGoodsMasterImg("https://img14.360buyimg.com/n0/jfs/t26539/294/374934442/170031/37ad9714/5b8f9d4eN5455c30c.jpg"); + goodsInfo4.setGoodsOldPrice("3333"); + goodsInfo4.setGoodsPrice("2049"); + goodsInfoList2.add(goodsInfo4); + + recommendList.add(goodsInfoList1); + recommendList.add(goodsInfoList2); + getView().refreshRecommendList(recommendList); } /** @@ -92,50 +90,61 @@ public void getRecommendList() { */ @Override public void getCommentList() { - if (isViewAttached()) { - List commentList = new ArrayList<>(); - GoodsComment comment = new GoodsComment(); - comment.setComment("手机到了刚弄好,非常流畅"); - comment.setStar(5); - comment.setUserHead("http://i10.hoopchina.com.cn/hupuapp/bbs/966/16313966/thread_16313966_20180726164538_s_65949_o_w1024_h1024_62044.jpg?x-oss-process=image/resize,w_800/format,jpg"); - comment.setUserName("噶***蛋"); - commentList.add(comment); - - comment = new GoodsComment(); - comment.setComment("最重要的还是手机,各种操作都很流畅信号各方面都没有问题,谢谢!"); - comment.setStar(2); - comment.setUserHead("https://img4.duitang.com/uploads/item/201602/01/20160201111345_4kvQA.jpeg"); - comment.setUserName("王***想"); - commentList.add(comment); - - comment = new GoodsComment(); - comment.setComment("物流速度很给力,同时店家也很有耐心客服也很有责任心各种操作都很流畅信号各方面都没有问题,谢谢!"); - comment.setStar(3); - comment.setUserName("阿***蛋"); - comment.setUserHead("https://img4.duitang.com/uploads/item/201601/16/20160116161347_svH5y.thumb.224_0.jpeg"); - commentList.add(comment); - - comment = new GoodsComment(); - comment.setComment("雷总果然强大,谢谢!"); - comment.setStar(1); - comment.setUserName("P***去"); - comment.setUserHead("http://img1.touxiang.cn/uploads/20130927/27-020608_93.jpg"); - commentList.add(comment); - - comment = new GoodsComment(); - comment.setComment("雷总果然强大,家里好多电器都是小米的"); - comment.setStar(3); - comment.setUserHead("http://imgsrc.baidu.com/imgad/pic/item/ca1349540923dd54afaa0d4bdb09b3de9c82483c.jpg"); - comment.setUserName("补***萨"); - commentList.add(comment); - - getView().commentList(commentList); - } + List commentList = new ArrayList<>(); + GoodsComment comment = new GoodsComment(); + + comment.setComment("雷总果然强大,谢谢!"); + comment.setStar(1); + comment.setUserName("P***去"); + comment.setDate("2010年12月20日01:37:59"); + comment.setUserHead("http://img1.touxiang.cn/uploads/20130927/27-020608_93.jpg"); + commentList.add(comment); + + comment = new GoodsComment(); + comment.setComment("物流速度很给力,同时店家也很有耐心客服也很有责任心各种操作都很流畅信号各方面都没有问题,谢谢!"); + comment.setStar(3); + comment.setDate("2020年10月20日09:47:59"); + comment.setUserName("阿***蛋"); + comment.setUserHead("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603168242468&di=e62f8708f01cd7f85ef0a40bfa1fdee1&imgtype=0&src=https%3A%2F%2Fround-lake.dustinice.workers.dev%3A443%2Fhttp%2Fgaitaobao4.alicdn.com%2Ftfscom%2Fi4%2F2040947480%2FTB27GrsAgmTBuNjy1XbXXaMrVXa_%2521%25212040947480.jpg_300x300q90.jpg"); + commentList.add(comment); + + comment = new GoodsComment(); + comment.setComment("雷总果然强大,家里好多电器都是小米的"); + comment.setStar(3); + comment.setDate("2020年10月20日09:47:59"); + comment.setUserHead("https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2456975006,3192848039&fm=26&gp=0.jpg"); + comment.setUserName("补***萨"); + commentList.add(comment); + + comment = new GoodsComment(); + comment.setComment("雷总果然强大,谢谢!"); + comment.setStar(1); + comment.setDate("2020年10月20日09:47:59"); + comment.setUserName("P***去"); + comment.setUserHead("http://img1.touxiang.cn/uploads/20130927/27-020608_93.jpg"); + commentList.add(comment); + + comment = new GoodsComment(); + comment.setComment("最重要的还是手机,各种操作都很流畅信号各方面都没有问题,谢谢!"); + comment.setStar(2); + comment.setDate("2020年10月20日09:47:59"); + comment.setUserHead("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1603168248736&di=7e59800fa7af4c3194872a78540af6f9&imgtype=0&src=https%3A%2F%2Fround-lake.dustinice.workers.dev%3A443%2Fhttp%2Ftupian.qqw21.com%2Farticle%2FUploadPic%2F2020-9%2F2020922033115276.jpg"); + comment.setUserName("王***想"); + commentList.add(comment); + + comment = new GoodsComment(); + comment.setComment("雷总果然强大,谢谢!"); + comment.setStar(1); + comment.setUserName("P***去"); + comment.setDate("2020年10月20日09:47:59"); + comment.setUserHead("http://img1.touxiang.cn/uploads/20130927/27-020608_93.jpg"); + commentList.add(comment); + getView().refreshCommentList(commentList); } @Override - protected GoodsDetailContract.Model createModule() { - return null; + protected GoodsDetailModel createModule() { + return new GoodsDetailModel(getLifecycleOwner()); } @Override diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/contract/GoodsCommentContract.java b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/contract/GoodsCommentContract.java index 4a98325..6c0de87 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/contract/GoodsCommentContract.java +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/contract/GoodsCommentContract.java @@ -1,6 +1,5 @@ package com.wss.module.market.ui.goods.detail.mvp.contract; -import com.wss.common.base.mvp.IBaseModel; import com.wss.common.base.mvp.IBaseView; import com.wss.module.market.bean.GoodsComment; @@ -13,7 +12,7 @@ public interface GoodsCommentContract { - interface Model extends IBaseModel { + interface Model { } @@ -21,8 +20,10 @@ interface View extends IBaseView { /** * 商品评论列表 + * + * @param commentList 商品评论列表 */ - void commentList(List commentList); + void refreshCommentList(List commentList); } interface Presenter { diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/contract/GoodsDetailContract.java b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/contract/GoodsDetailContract.java index 342c03c..9e0bc6e 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/contract/GoodsDetailContract.java +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/contract/GoodsDetailContract.java @@ -1,6 +1,5 @@ package com.wss.module.market.ui.goods.detail.mvp.contract; -import com.wss.common.base.mvp.IBaseModel; import com.wss.common.base.mvp.IBaseView; import com.wss.module.market.bean.GoodsComment; import com.wss.module.market.bean.GoodsInfo; @@ -14,7 +13,7 @@ public interface GoodsDetailContract { - interface Model extends IBaseModel { + interface Model { } @@ -27,18 +26,24 @@ interface View extends IBaseView { /** * 商品详情 + * + * @param goodsInfo 商品详情 */ - void goodsInfo(GoodsInfo goodsInfo); + void refreshGoodsInfo(GoodsInfo goodsInfo); /** * 推荐商品列表 + * + * @param recommendList 推荐商品列表 */ - void recommendList(List> recommendList); + void refreshRecommendList(List> recommendList); /** * 商品评论列表 + * + * @param commentList 商品评论列表 */ - void commentList(List commentList); + void refreshCommentList(List commentList); } interface Presenter { diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/model/GoodsCommentModel.java b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/model/GoodsCommentModel.java new file mode 100644 index 0000000..b750fab --- /dev/null +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/model/GoodsCommentModel.java @@ -0,0 +1,17 @@ +package com.wss.module.market.ui.goods.detail.mvp.model; + +import com.wss.common.base.mvp.BaseModel; +import com.wss.module.market.ui.goods.detail.mvp.contract.GoodsCommentContract; + +import androidx.lifecycle.LifecycleOwner; + +/** + * Describe: 商品评论Model + * Created by 吴天强 on 2020/8/11. + */ +public class GoodsCommentModel extends BaseModel implements GoodsCommentContract.Model { + + public GoodsCommentModel(LifecycleOwner lifecycleOwner) { + super(lifecycleOwner); + } +} diff --git a/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/model/GoodsDetailModel.java b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/model/GoodsDetailModel.java new file mode 100644 index 0000000..12393d0 --- /dev/null +++ b/module_market/src/main/java/com/wss/module/market/ui/goods/detail/mvp/model/GoodsDetailModel.java @@ -0,0 +1,17 @@ +package com.wss.module.market.ui.goods.detail.mvp.model; + +import com.wss.common.base.mvp.BaseModel; +import com.wss.module.market.ui.goods.detail.mvp.contract.GoodsDetailContract; + +import androidx.lifecycle.LifecycleOwner; + +/** + * Describe:商品详情Model + * Created by 吴天强 on 2020/8/11. + */ +public class GoodsDetailModel extends BaseModel implements GoodsDetailContract.Model { + + public GoodsDetailModel(LifecycleOwner lifecycleOwner) { + super(lifecycleOwner); + } +} diff --git a/module_market/src/main/java/com/wss/module/market/ui/main/MarketMainActivity.java b/module_market/src/main/java/com/wss/module/market/ui/main/MarketMainActivity.java index 2fc502f..56e4df2 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/main/MarketMainActivity.java +++ b/module_market/src/main/java/com/wss/module/market/ui/main/MarketMainActivity.java @@ -1,45 +1,45 @@ package com.wss.module.market.ui.main; -import android.support.v7.widget.GridLayoutManager; -import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.view.View; import android.widget.TextView; import com.alibaba.android.arouter.facade.annotation.Route; -import com.wss.common.base.ActionBarActivity; +import com.wss.common.base.BaseActionBarActivity; import com.wss.common.bean.Event; import com.wss.common.constants.ARouterConfig; +import com.wss.common.constants.Dic; import com.wss.common.constants.EventAction; -import com.wss.common.listener.OnListItemClickListener; -import com.wss.common.utils.ActivityToActivity; +import com.wss.common.manage.ActivityToActivity; import com.wss.module.market.R; import com.wss.module.market.R2; import com.wss.module.market.bean.GoodsInfo; import com.wss.module.market.ui.goods.cart.ShoppingCartActivity; import com.wss.module.market.ui.goods.detail.GoodsDetailActivity; import com.wss.module.market.ui.main.adapter.MarketMainAdapter; -import com.wss.module.market.ui.main.mvp.contract.MarketMainContract; import com.wss.module.market.ui.main.mvp.MarketMainPresenter; +import com.wss.module.market.ui.main.mvp.contract.MarketMainContract; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import butterknife.BindView; /** * Describe:商场首页 * Created by 吴天强 on 2018/10/19. */ - @Route(path = ARouterConfig.MARKET_MAIN_ACTIVITY) -public class MarketMainActivity extends ActionBarActivity implements MarketMainContract.View, - OnListItemClickListener { +public class MarketMainActivity extends BaseActionBarActivity implements MarketMainContract.View { @BindView(R2.id.rv_list) RecyclerView recyclerView; - private TextView tvCount;//购物车商品数量 + private TextView tvCount; private MarketMainAdapter adapter; private List marketInfoList = new ArrayList<>(); @@ -56,37 +56,31 @@ protected int getLayoutId() { @Override protected void initView() { - setTitleText("商城"); - adapter = new MarketMainAdapter(mContext, marketInfoList, R.layout.market_item_of_market_list, this); - recyclerView.setLayoutManager(new GridLayoutManager(mContext, 2)); + setCenterText("商城模板"); + adapter = new MarketMainAdapter(context, marketInfoList, (data, position) -> { + Map param = new HashMap<>(); + param.put(Dic.GOODS_INFO, marketInfoList.get(position)); + ActivityToActivity.toActivity(context, GoodsDetailActivity.class, param); + }); + recyclerView.setLayoutManager(new GridLayoutManager(context, 2)); recyclerView.setAdapter(adapter); - View cartView = View.inflate(mContext, R.layout.market_layout_market_main_shopping_cart, null); + View cartView = View.inflate(context, R.layout.market_layout_market_main_shopping_cart, null); tvCount = cartView.findViewById(R.id.tv_count); - cartView.findViewById(R.id.iv_cart).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - //TO 购物车 - ActivityToActivity.toActivity(mContext, ShoppingCartActivity.class); - } - }); - actionBar.setRightView(cartView); - presenter.start(); + cartView.findViewById(R.id.iv_cart).setOnClickListener( + v -> ActivityToActivity.toActivity(context, ShoppingCartActivity.class)); + getTitleBar().setRightView(cartView); + getPresenter().start(); } @Override - public void dataList(List dataList) { + public void refreshGoodsList(List dataList) { this.marketInfoList.addAll(dataList); - runOnUiThread(new Runnable() { - @Override - public void run() { - adapter.notifyDataSetChanged(); - } - }); + adapter.notifyDataSetChanged(); } @Override - public void cartCount(long count) { + public void refreshCartCount(long count) { if (count > 0) { tvCount.setVisibility(View.VISIBLE); tvCount.setText(String.valueOf(count)); @@ -95,23 +89,19 @@ public void cartCount(long count) { } } - @Override - public void onItemClick(View view, int position) { - ActivityToActivity.toActivity(mContext, GoodsDetailActivity.class); - } - @Override public void onEventBus(Event event) { super.onEventBus(event); - if (TextUtils.equals(EventAction.EVENT_SHOPPING_CART_REFRESH, event.getAction()) || - TextUtils.equals(EventAction.EVENT_SHOPPING_CART_CLEAN, event.getAction())) { + if (TextUtils.equals(EventAction.EVENT_SHOPPING_CART_CHANGED, event.getAction()) || + TextUtils.equals(EventAction.EVENT_SHOPPING_CART_REFRESH, event.getAction())) { //刷新购物车 - presenter.getCartCount(); + getPresenter().getCartCount(); } } @Override - protected boolean regEvent() { + protected boolean registerEventBus() { return true; } + } diff --git a/module_market/src/main/java/com/wss/module/market/ui/main/adapter/MarketMainAdapter.java b/module_market/src/main/java/com/wss/module/market/ui/main/adapter/MarketMainAdapter.java index 5fce483..fc250b8 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/main/adapter/MarketMainAdapter.java +++ b/module_market/src/main/java/com/wss/module/market/ui/main/adapter/MarketMainAdapter.java @@ -2,14 +2,13 @@ import android.content.Context; import android.graphics.Paint; -import android.view.View; import android.widget.ImageView; import android.widget.TextView; import com.wss.common.base.adapter.BaseListAdapter; +import com.wss.common.base.adapter.listener.OnListItemClickListener; import com.wss.common.bean.Event; import com.wss.common.constants.EventAction; -import com.wss.common.listener.OnListItemClickListener; import com.wss.common.utils.EventBusUtils; import com.wss.common.utils.ImageUtils; import com.wss.module.market.R; @@ -27,27 +26,25 @@ public class MarketMainAdapter extends BaseListAdapter { - public MarketMainAdapter(Context context, List items, int layoutResId, OnListItemClickListener listener) { - super(context, items, layoutResId, listener); + public MarketMainAdapter(Context context, List items, OnListItemClickListener listener) { + super(context, items, R.layout.market_item_of_market_list, listener); } @Override public void onBindData(SuperViewHolder holder, int viewType, int layoutPosition, GoodsInfo data) { - ImageUtils.loadImage((ImageView) holder.findViewById(R.id.iv_img), data.getGoodsMasterImg()); + ImageUtils.loadImage(holder.findViewById(R.id.iv_img), data.getGoodsMasterImg()); holder.setText(R.id.tv_title, data.getGoodsName()); holder.setText(R.id.tv_price, data.getGoodsPrice()); TextView tvOldPrice = holder.findViewById(R.id.tv_old_price); tvOldPrice.setText(data.getGoodsOldPrice()); - //设置文字中间一条横线, + final GoodsInfo goodsInfo = data; + //设置文字中间一条横线, tvOldPrice.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG); - holder.findViewById(R.id.iv_add_cart).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - //加入购物车 - ShoppingCartUtils.addCartGoods(goodsInfo); - EventBusUtils.sendEvent(new Event(EventAction.EVENT_SHOPPING_CART_REFRESH)); - } + holder.findViewById(R.id.iv_add_cart).setOnClickListener(v -> { + //加入购物车 + ShoppingCartUtils.addCartGoods(goodsInfo); + EventBusUtils.sendEvent(new Event(EventAction.EVENT_SHOPPING_CART_CHANGED)); }); } } diff --git a/module_market/src/main/java/com/wss/module/market/ui/main/mvp/MarketMainPresenter.java b/module_market/src/main/java/com/wss/module/market/ui/main/mvp/MarketMainPresenter.java index 74b3a90..c93dd3a 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/main/mvp/MarketMainPresenter.java +++ b/module_market/src/main/java/com/wss/module/market/ui/main/mvp/MarketMainPresenter.java @@ -3,6 +3,7 @@ import com.wss.common.base.mvp.BasePresenter; import com.wss.module.market.bean.GoodsInfo; import com.wss.module.market.ui.main.mvp.contract.MarketMainContract; +import com.wss.module.market.ui.main.mvp.model.MarketMainModel; import com.wss.module.market.utils.ShoppingCartUtils; import java.util.ArrayList; @@ -13,34 +14,32 @@ * Created by 吴天强 on 2018/10/19. */ -public class MarketMainPresenter extends BasePresenter +public class MarketMainPresenter extends BasePresenter implements MarketMainContract.Presenter { @Override public void getMarketData() { - if (isViewAttached()) { - List list = new ArrayList<>(); - list.add(new GoodsInfo("0", "联想ThinkPad 翼480(04CD)", "https://img10.360buyimg.com/mobilecms/s250x250_jfs/t22711/247/184038096/247446/b7dbcb19/5b286798Ncdb5c00e.jpg", "3999.00", "4929.00", "1")); - list.add(new GoodsInfo("1", "小米8 全面屏游戏智能手机", "https://img14.360buyimg.com/n7/jfs/t20509/311/508682869/290069/4d2c41e/5b0fcab1N217bcf3d.jpg", "2499.00", "3333.00", "1")); - list.add(new GoodsInfo("2", "母婴车车", "https://img14.360buyimg.com/n2/jfs/t9682/50/12021355/222280/25a2d659/59c372bbNa76076b9.jpg", "388.00", "888.00", "2")); - list.add(new GoodsInfo("3", "纽伯瑞国际大奖小说全8册", "https://img14.360buyimg.com/n2/jfs/t24700/38/859671102/205515/9aa10d3d/5b7e75e7N1ea9a98e.jpg", "96.00", "101.02", "1")); - list.add(new GoodsInfo("4", "三只松鼠巨型网红零食大礼包30包抖音", "https://img12.360buyimg.com/n2/jfs/t22789/25/1266822087/198554/baab6908/5b586392Nfc017771.jpg", "178.00", "200.00", "2")); - list.add(new GoodsInfo("5", "陈粒:第四张创作专辑《玩》(京东专卖)", "https://img13.360buyimg.com/n3/jfs/t26320/135/1040252244/267213/868dfef3/5bc01445N84d634df.jpg!q80.jpg", "120", "200.00", "2")); - list.add(new GoodsInfo("6", "燕京啤酒 330ml*24罐 特制啤酒", "https://img12.360buyimg.com/n2/s160x160_jfs/t1/836/11/4243/311829/5b9b03f5E56ff9777/f797222e042abcdf.jpg", "68.00", "99.00", "1")); - list.add(new GoodsInfo("7", "天堂伞", "https://img11.360buyimg.com/babel/s180x180_jfs/t3208/128/5610451092/185712/7b14491a/5875e378N5360f782.jpg", "39.90", "40.00", "2")); - list.add(new GoodsInfo("8", "万仟堂(Edenus)旅行茶具户外旅游茶具套装一壶一杯快客杯女", "https://img14.360buyimg.com/n2/jfs/t1/5365/5/4056/131744/5b9b0d84E079a9ea1/00491a9f45d53409.jpg!q90.jpg", "489.00", "50.00", "1")); - getView().dataList(list); - } + List list = new ArrayList<>(); + list.add(new GoodsInfo("0", "联想ThinkPad 翼480(04CD)", "https://img10.360buyimg.com/mobilecms/s250x250_jfs/t22711/247/184038096/247446/b7dbcb19/5b286798Ncdb5c00e.jpg", "3999.00", "4929.00", "1")); + list.add(new GoodsInfo("1", "小米8 全面屏游戏智能手机", "https://img14.360buyimg.com/n7/jfs/t20509/311/508682869/290069/4d2c41e/5b0fcab1N217bcf3d.jpg", "2499.00", "3333.00", "1")); + list.add(new GoodsInfo("2", "母婴车车", "https://img14.360buyimg.com/n2/jfs/t9682/50/12021355/222280/25a2d659/59c372bbNa76076b9.jpg", "388.00", "888.00", "2")); + list.add(new GoodsInfo("3", "纽伯瑞国际大奖小说全8册", "https://img14.360buyimg.com/n2/jfs/t24700/38/859671102/205515/9aa10d3d/5b7e75e7N1ea9a98e.jpg", "96.00", "101.02", "1")); + list.add(new GoodsInfo("4", "三只松鼠巨型网红零食大礼包30包抖音", "https://img12.360buyimg.com/n2/jfs/t22789/25/1266822087/198554/baab6908/5b586392Nfc017771.jpg", "178.00", "200.00", "2")); + list.add(new GoodsInfo("5", "陈粒:第四张创作专辑《玩》(京东专卖)", "https://img13.360buyimg.com/n3/jfs/t26320/135/1040252244/267213/868dfef3/5bc01445N84d634df.jpg!q80.jpg", "120", "200.00", "2")); + list.add(new GoodsInfo("6", "燕京啤酒 330ml*24罐 特制啤酒", "https://img12.360buyimg.com/n2/s160x160_jfs/t1/836/11/4243/311829/5b9b03f5E56ff9777/f797222e042abcdf.jpg", "68.00", "99.00", "1")); + list.add(new GoodsInfo("7", "天堂伞", "https://img11.360buyimg.com/babel/s180x180_jfs/t3208/128/5610451092/185712/7b14491a/5875e378N5360f782.jpg", "39.90", "40.00", "2")); + list.add(new GoodsInfo("8", "万仟堂(Edenus)旅行茶具户外旅游茶具套装一壶一杯快客杯女", "https://img14.360buyimg.com/n2/jfs/t1/5365/5/4056/131744/5b9b0d84E079a9ea1/00491a9f45d53409.jpg!q90.jpg", "489.00", "50.00", "1")); + getView().refreshGoodsList(list); } @Override public void getCartCount() { - getView().cartCount(ShoppingCartUtils.getCartCount()); + getView().refreshCartCount(ShoppingCartUtils.getCartCount()); } @Override - protected MarketMainContract.Model createModule() { - return null; + protected MarketMainModel createModule() { + return new MarketMainModel(getLifecycleOwner()); } @Override diff --git a/module_market/src/main/java/com/wss/module/market/ui/main/mvp/contract/MarketMainContract.java b/module_market/src/main/java/com/wss/module/market/ui/main/mvp/contract/MarketMainContract.java index 89bbab6..9b7c6c4 100644 --- a/module_market/src/main/java/com/wss/module/market/ui/main/mvp/contract/MarketMainContract.java +++ b/module_market/src/main/java/com/wss/module/market/ui/main/mvp/contract/MarketMainContract.java @@ -1,6 +1,5 @@ package com.wss.module.market.ui.main.mvp.contract; -import com.wss.common.base.mvp.IBaseModel; import com.wss.common.base.mvp.IBaseView; import com.wss.module.market.bean.GoodsInfo; @@ -13,7 +12,7 @@ public interface MarketMainContract { - interface Model extends IBaseModel { + interface Model { } @@ -23,14 +22,14 @@ interface View extends IBaseView { * * @param dataList dataList */ - void dataList(List dataList); + void refreshGoodsList(List dataList); /** * 购物车商品数量 * * @param count count */ - void cartCount(long count); + void refreshCartCount(long count); } interface Presenter { diff --git a/module_market/src/main/java/com/wss/module/market/ui/main/mvp/model/MarketMainModel.java b/module_market/src/main/java/com/wss/module/market/ui/main/mvp/model/MarketMainModel.java new file mode 100644 index 0000000..653b0df --- /dev/null +++ b/module_market/src/main/java/com/wss/module/market/ui/main/mvp/model/MarketMainModel.java @@ -0,0 +1,17 @@ +package com.wss.module.market.ui.main.mvp.model; + +import com.wss.common.base.mvp.BaseModel; +import com.wss.module.market.ui.main.mvp.contract.MarketMainContract; + +import androidx.lifecycle.LifecycleOwner; + +/** + * Describe:商品首页Model + * Created by 吴天强 on 2020/8/11. + */ +public class MarketMainModel extends BaseModel implements MarketMainContract.Model { + + public MarketMainModel(LifecycleOwner lifecycleOwner) { + super(lifecycleOwner); + } +} diff --git a/module_market/src/main/java/com/wss/module/market/utils/ShoppingCartUtils.java b/module_market/src/main/java/com/wss/module/market/utils/ShoppingCartUtils.java index f9e96c1..1bc6149 100644 --- a/module_market/src/main/java/com/wss/module/market/utils/ShoppingCartUtils.java +++ b/module_market/src/main/java/com/wss/module/market/utils/ShoppingCartUtils.java @@ -11,6 +11,8 @@ import com.wss.module.market.bean.Vendor; import com.wss.module.market.db.MarketDBFactory; +import org.jetbrains.annotations.NotNull; + import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -20,7 +22,6 @@ * Describe:购物车帮助类 * Created by 吴天强 on 2018/11/5. */ - public class ShoppingCartUtils { /** @@ -113,20 +114,37 @@ public static int getCartCount() { * @return count */ public static double getCartCountPrice(List vendors) { - double price = 0.0; for (GoodsInfo info : getAllCheckedGoods(vendors)) { - price += info.getNum() * Double.valueOf(info.getGoodsPrice()); + price += info.getNum() * Double.parseDouble(info.getGoodsPrice()); } return price; } - public static void cleanLocal() { - + /** + * 删除购物车数据 + * + * @param goodsList goodsList + */ + public static void delete(List goodsList) { MarketDBFactory.getInstance() .getGoodsInfoManage() - .deleteAll(); - EventBusUtils.sendEvent(new Event(EventAction.EVENT_SHOPPING_CART_CLEAN)); + .delete(goodsList); + EventBusUtils.sendEvent(new Event(EventAction.EVENT_SHOPPING_CART_REFRESH)); + } + + /** + * 计算商品总数 + * + * @param goodsInfoList 商品列表 + * @return 总数 + */ + public static int calculationGoodsCount(@NotNull List goodsInfoList) { + int count = 0; + for (GoodsInfo goodsInfo : goodsInfoList) { + count += goodsInfo.getNum(); + } + return count; } //**********************************购物车点击逻辑操作******************************************* @@ -221,4 +239,33 @@ public static List getAllCheckedGoods(List vendors) { return result; } + /** + * 获取已选中的商品 和供应商 + * + * @param vendors 供应商 + * @return 供应商 + */ + @NotNull + public static List getCheckedGoodsVendor(@NotNull List vendors) { + List result = new ArrayList<>(); + for (Vendor deliveryInfo : vendors) { + if (deliveryInfo.isChecked()) { + result.add(deliveryInfo); + } else { + List goodsInfoList = new ArrayList<>(); + for (GoodsInfo info : deliveryInfo.getGoodsInfos()) { + if (info.isChecked()) { + goodsInfoList.add(info); + } + } + Vendor vendor = new Vendor(); + vendor.setVendorId(deliveryInfo.getVendorId()); + vendor.setVendorName(deliveryInfo.getVendorName()); + vendor.setGoodsInfos(goodsInfoList); + result.add(vendor); + } + } + return result; + } + } diff --git a/module_market/src/main/res/color/market_goods_button_text_color.xml b/module_market/src/main/res/color/market_goods_button_text_color.xml new file mode 100644 index 0000000..236489e --- /dev/null +++ b/module_market/src/main/res/color/market_goods_button_text_color.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/module_market/src/main/res/drawable-xxhdpi/market_icon_shopping_cart.png b/module_market/src/main/res/drawable-xxhdpi/market_icon_shopping_cart.png index c9bdb3c..96addd3 100644 Binary files a/module_market/src/main/res/drawable-xxhdpi/market_icon_shopping_cart.png and b/module_market/src/main/res/drawable-xxhdpi/market_icon_shopping_cart.png differ diff --git a/module_market/src/main/res/drawable-xxxhdpi/market_address_img_bg.png b/module_market/src/main/res/drawable-xxxhdpi/market_address_img_bg.png new file mode 100644 index 0000000..3e7ead4 Binary files /dev/null and b/module_market/src/main/res/drawable-xxxhdpi/market_address_img_bg.png differ diff --git a/module_market/src/main/res/drawable/market_bg_of_ellipse_button_black.xml b/module_market/src/main/res/drawable/market_bg_of_ellipse_button_black.xml new file mode 100644 index 0000000..24ce153 --- /dev/null +++ b/module_market/src/main/res/drawable/market_bg_of_ellipse_button_black.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/module_market/src/main/res/drawable/market_bg_of_ellipse_button_red.xml b/module_market/src/main/res/drawable/market_bg_of_ellipse_button_red.xml new file mode 100644 index 0000000..6b34ee9 --- /dev/null +++ b/module_market/src/main/res/drawable/market_bg_of_ellipse_button_red.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/module_market/src/main/res/drawable/market_bg_of_ellipse_button_select.xml b/module_market/src/main/res/drawable/market_bg_of_ellipse_button_select.xml new file mode 100644 index 0000000..7763649 --- /dev/null +++ b/module_market/src/main/res/drawable/market_bg_of_ellipse_button_select.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/module_market/src/main/res/drawable/market_shopping_cart_next_btn.xml b/module_market/src/main/res/drawable/market_shopping_cart_next_btn.xml index 58e9161..b79d1b6 100644 --- a/module_market/src/main/res/drawable/market_shopping_cart_next_btn.xml +++ b/module_market/src/main/res/drawable/market_shopping_cart_next_btn.xml @@ -1,7 +1,6 @@ - - + \ No newline at end of file diff --git a/module_market/src/main/res/drawable/market_shopping_cart_next_btn_red.xml b/module_market/src/main/res/drawable/market_shopping_cart_next_btn_red.xml new file mode 100644 index 0000000..9b3afd2 --- /dev/null +++ b/module_market/src/main/res/drawable/market_shopping_cart_next_btn_red.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/module_market/src/main/res/layout/market_activity_goods_details.xml b/module_market/src/main/res/layout/market_activity_goods_details.xml index ae0026b..bf5be57 100644 --- a/module_market/src/main/res/layout/market_activity_goods_details.xml +++ b/module_market/src/main/res/layout/market_activity_goods_details.xml @@ -1,7 +1,8 @@ - @@ -65,5 +68,73 @@ - + android:layout_height="wrap_content" + android:layout_above="@+id/rl_bottom" + android:layout_below="@+id/rl_top" /> + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_market/src/main/res/layout/market_activity_market_mian.xml b/module_market/src/main/res/layout/market_activity_market_mian.xml index 70ff6d0..e022280 100644 --- a/module_market/src/main/res/layout/market_activity_market_mian.xml +++ b/module_market/src/main/res/layout/market_activity_market_mian.xml @@ -3,7 +3,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - @@ -48,7 +48,7 @@ android:layout_centerVertical="true" android:layout_marginStart="8dp" android:layout_toEndOf="@+id/ll_checked_view" - android:text="@string/total" /> + android:text="@string/market_total" /> diff --git a/module_market/src/main/res/layout/market_fragment_goods_comment.xml b/module_market/src/main/res/layout/market_fragment_goods_comment.xml index d35b15f..6e9536c 100644 --- a/module_market/src/main/res/layout/market_fragment_goods_comment.xml +++ b/module_market/src/main/res/layout/market_fragment_goods_comment.xml @@ -59,7 +59,7 @@ android:textSize="12sp" android:visibility="gone" /> - diff --git a/module_market/src/main/res/layout/market_fragment_goods_info_main.xml b/module_market/src/main/res/layout/market_fragment_goods_info_main.xml index 1a919ff..3101260 100644 --- a/module_market/src/main/res/layout/market_fragment_goods_info_main.xml +++ b/module_market/src/main/res/layout/market_fragment_goods_info_main.xml @@ -7,7 +7,7 @@ android:orientation="vertical"> - - @@ -65,19 +64,27 @@ android:id="@+id/tv_old_price" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_alignParentBottom="true" + android:layout_marginBottom="2dp" android:layout_marginStart="5dp" + android:layout_toEndOf="@+id/tv_goods_price" android:gravity="center_vertical" android:textColor="@color/gray" android:textSize="13sp" /> - + + @@ -155,7 +162,7 @@ - + + android:layout_height="match_parent" + android:background="@color/gray" /> - - - - + android:layout_height="1px" + android:background="@color/gray" /> diff --git a/module_market/src/main/res/layout/market_item_of_goods_recommend.xml b/module_market/src/main/res/layout/market_item_of_goods_recommend.xml index 9a7ef79..0c4028c 100644 --- a/module_market/src/main/res/layout/market_item_of_goods_recommend.xml +++ b/module_market/src/main/res/layout/market_item_of_goods_recommend.xml @@ -1,5 +1,5 @@ - diff --git a/module_market/src/main/res/layout/market_item_of_order_goods_info.xml b/module_market/src/main/res/layout/market_item_of_order_goods_info.xml new file mode 100644 index 0000000..9609264 --- /dev/null +++ b/module_market/src/main/res/layout/market_item_of_order_goods_info.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/module_market/src/main/res/layout/market_item_of_order_goods_vendor.xml b/module_market/src/main/res/layout/market_item_of_order_goods_vendor.xml new file mode 100644 index 0000000..b9b2bb9 --- /dev/null +++ b/module_market/src/main/res/layout/market_item_of_order_goods_vendor.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/module_market/src/main/res/layout/market_order_settlement.xml b/module_market/src/main/res/layout/market_order_settlement.xml new file mode 100644 index 0000000..dc363cf --- /dev/null +++ b/module_market/src/main/res/layout/market_order_settlement.xml @@ -0,0 +1,206 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/module_market/src/main/res/layout/market_pop_goods_specification.xml b/module_market/src/main/res/layout/market_pop_goods_specification.xml new file mode 100644 index 0000000..b635e41 --- /dev/null +++ b/module_market/src/main/res/layout/market_pop_goods_specification.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/module_market/src/main/res/values/strings.xml b/module_market/src/main/res/values/strings.xml index f06d7d5..01df41a 100644 --- a/module_market/src/main/res/values/strings.xml +++ b/module_market/src/main/res/values/strings.xml @@ -1,6 +1,8 @@ module_market - 全选 - 合计: - 下一步 + 全选 + 合计: + 下一步 + 加入购物车 + 立即购买 diff --git a/module_user/README.txt b/module_user/README.txt new file mode 100644 index 0000000..81b7809 --- /dev/null +++ b/module_user/README.txt @@ -0,0 +1,11 @@ +用户模块 + +为防止同名资源文件被覆盖,则采用如下方式来规避 +1.该module的资源命名必须以[user_]打头 + 如:user_icon_close,user_img_bg,user_shape_round_4 + +2.该module的布局文件命名必须以[user_]打头 + 如:user_activity_main,user_fragment_main,user_item_of_user_list + +3.涉及到跨module跳转的Activity、Fragment需要在common_base模块的ARouterConfig中配置跳转的Path + diff --git a/module_user/build.gradle b/module_user/build.gradle index 22ab269..2050c26 100644 --- a/module_user/build.gradle +++ b/module_user/build.gradle @@ -50,6 +50,10 @@ android { } } } + compileOptions { + targetCompatibility rootProject.ext.versions.javaSDKVersion + sourceCompatibility rootProject.ext.versions.javaSDKVersion + } } dependencies { @@ -58,8 +62,8 @@ dependencies { implementation project(':common_base') //Arouter路由 - annotationProcessor rootProject.ext.dependencies["arouter_compiler"] + annotationProcessor rootProject.ext.dependencies["arouterCompiler"] //黄油刀 - annotationProcessor rootProject.ext.dependencies["butterknife_compiler"] + annotationProcessor rootProject.ext.dependencies["butterknifeCompiler"] } \ No newline at end of file diff --git a/module_user/src/main/java/com/wss/module/user/common/UserApplication.java b/module_user/src/main/java/com/wss/module/user/common/UserApplication.java index 8a7703c..b8babfa 100644 --- a/module_user/src/main/java/com/wss/module/user/common/UserApplication.java +++ b/module_user/src/main/java/com/wss/module/user/common/UserApplication.java @@ -6,6 +6,5 @@ * Describe: * Created by 吴天强 on 2018/11/13. */ - public class UserApplication extends BaseApplication { } diff --git a/module_user/src/main/java/com/wss/module/user/ui/about/AboutActivity.java b/module_user/src/main/java/com/wss/module/user/ui/about/AboutActivity.java index 9bf51c0..fe9b0e4 100644 --- a/module_user/src/main/java/com/wss/module/user/ui/about/AboutActivity.java +++ b/module_user/src/main/java/com/wss/module/user/ui/about/AboutActivity.java @@ -1,10 +1,8 @@ package com.wss.module.user.ui.about; -import android.content.Intent; -import android.net.Uri; import android.widget.TextView; -import com.wss.common.base.ActionBarActivity; +import com.wss.common.base.BaseActionBarActivity; import com.wss.common.base.mvp.BasePresenter; import com.wss.common.utils.Utils; import com.wss.module.user.R; @@ -17,8 +15,7 @@ * Describe:关于 * Created by 吴天强 on 2018/11/13. */ - -public class AboutActivity extends ActionBarActivity { +public class AboutActivity extends BaseActionBarActivity { @BindView(R2.id.tv_version) TextView tvVersion; @@ -34,17 +31,13 @@ protected int getLayoutId() { @Override protected void initView() { - setTitleText("关于"); + setCenterText("关于"); tvVersion.setText(String.format("当前版本:%s", Utils.getVersionName())); } @OnClick(R2.id.tv_wan) public void onViewClicked() { - Intent intent = new Intent(); - intent.setAction("android.intent.action.VIEW"); - Uri content_url = Uri.parse("http://www.wanandroid.com"); - intent.setData(content_url); - startActivity(intent); + Utils.toSystemBrowser(context, "http://www.wanandroid.com"); } } diff --git a/module_user/src/main/java/com/wss/module/user/ui/account/LoginActivity.java b/module_user/src/main/java/com/wss/module/user/ui/account/LoginActivity.java index 4f317a1..f738b03 100644 --- a/module_user/src/main/java/com/wss/module/user/ui/account/LoginActivity.java +++ b/module_user/src/main/java/com/wss/module/user/ui/account/LoginActivity.java @@ -6,15 +6,11 @@ import android.widget.TextView; import com.alibaba.android.arouter.facade.annotation.Route; -import com.wss.common.base.ActionBarActivity; +import com.wss.common.base.BaseActionBarActivity; import com.wss.common.bean.Event; -import com.wss.common.bean.User; import com.wss.common.constants.ARouterConfig; import com.wss.common.constants.EventAction; -import com.wss.common.utils.ActivityToActivity; -import com.wss.common.utils.EventBusUtils; -import com.wss.common.utils.ToastUtils; -import com.wss.common.utils.UserInfoUtils; +import com.wss.common.manage.ActivityToActivity; import com.wss.common.widget.ObserverButton; import com.wss.module.user.R; import com.wss.module.user.R2; @@ -29,7 +25,7 @@ * Created by 吴天强 on 2018/11/13. */ @Route(path = ARouterConfig.USER_LOGIN) -public class LoginActivity extends ActionBarActivity implements LoginContract.View { +public class LoginActivity extends BaseActionBarActivity implements LoginContract.View { @BindView(R2.id.edt_name) EditText edtName; @@ -50,7 +46,7 @@ protected int getLayoutId() { @Override protected void initView() { - setTitleText("登录"); + setCenterText("登录"); obLogin.observer(edtName, edtPwd); } @@ -59,26 +55,12 @@ protected void initView() { public void onViewClicked(View view) { int i = view.getId(); if (i == R.id.ob_login) { - presenter.login(); + getPresenter().login(edtName.getText().toString().trim(), edtPwd.getText().toString().trim()); } else if (i == R.id.ob_register) { - ActivityToActivity.toActivity(mContext, RegisterActivity.class); + ActivityToActivity.toActivity(context, RegisterActivity.class); } } - @Override - public void loginSuccess(User user) { - UserInfoUtils.saveUser(user); - EventBusUtils.sendEvent(new Event(EventAction.EVENT_LOGIN_SUCCESS)); - finish(); - } - - - @Override - public void onError(Object tag, String errorMsg) { - super.onError(tag, errorMsg); - ToastUtils.showToast(mContext, errorMsg); - } - @Override protected LoginPresenter createPresenter() { return new LoginPresenter(); @@ -93,12 +75,7 @@ public void onEventBus(Event event) { } @Override - protected boolean regEvent() { + protected boolean registerEventBus() { return true; } - - @Override - public User getUserInfo() { - return new User(edtName.getText().toString().trim(), edtPwd.getText().toString().trim()); - } } diff --git a/module_user/src/main/java/com/wss/module/user/ui/account/RegisterActivity.java b/module_user/src/main/java/com/wss/module/user/ui/account/RegisterActivity.java index a9be5d9..ac7a738 100644 --- a/module_user/src/main/java/com/wss/module/user/ui/account/RegisterActivity.java +++ b/module_user/src/main/java/com/wss/module/user/ui/account/RegisterActivity.java @@ -1,15 +1,8 @@ package com.wss.module.user.ui.account; -import android.text.TextUtils; import android.widget.EditText; -import com.wss.common.base.ActionBarActivity; -import com.wss.common.bean.Event; -import com.wss.common.bean.User; -import com.wss.common.constants.EventAction; -import com.wss.common.utils.EventBusUtils; -import com.wss.common.utils.ToastUtils; -import com.wss.common.utils.UserInfoUtils; +import com.wss.common.base.BaseActionBarActivity; import com.wss.common.widget.ObserverButton; import com.wss.module.user.R; import com.wss.module.user.R2; @@ -24,8 +17,7 @@ * Created by 吴天强 on 2018/11/13. */ -public class RegisterActivity extends ActionBarActivity implements RegisterContract.View { - +public class RegisterActivity extends BaseActionBarActivity implements RegisterContract.View { @BindView(R2.id.edt_name) EditText edtName; @@ -44,47 +36,15 @@ protected int getLayoutId() { @Override protected void initView() { - setTitleText("注册"); + setCenterText("注册"); obRegister.observer(edtName, edtPwd, edtConfirm); } @OnClick(R2.id.ob_register) public void viewClick() { - if (edtName.getText().toString().trim().length() < 6 || - edtPwd.getText().toString().trim().length() < 6 || - edtConfirm.getText().toString().trim().length() < 6) { - ToastUtils.showToast(mContext, "用户名或密码长度至少6位!"); - return; - } - if (!TextUtils.equals(edtPwd.getText().toString().trim(), - edtConfirm.getText().toString().trim())) { - ToastUtils.showToast(mContext, "两次输入密码不一致!"); - edtPwd.setText(""); - edtConfirm.setText(""); - return; - } - presenter.register(); - } - - @Override - public void onError(Object tag, String errorMsg) { - super.onError(tag, errorMsg); - ToastUtils.showToast(mContext, errorMsg); - } - - @Override - public User getUserInfo() { - return new User(edtName.getText().toString().trim(), edtPwd.getText().toString().trim()); - } - - @Override - public void registerSuccess(User user) { - //注册成功 已经默认登录了 - UserInfoUtils.saveUser(user); - EventBusUtils.sendEvent(new Event(EventAction.EVENT_REGISTER_SUCCESS)); - EventBusUtils.sendEvent(new Event(EventAction.EVENT_LOGIN_SUCCESS)); - finish(); + getPresenter().register(edtName.getText().toString().trim(), + edtPwd.getText().toString().trim(), edtConfirm.getText().toString().trim()); } @Override diff --git a/module_user/src/main/java/com/wss/module/user/ui/account/mvp/LoginModel.java b/module_user/src/main/java/com/wss/module/user/ui/account/mvp/LoginModel.java deleted file mode 100644 index f55ff67..0000000 --- a/module_user/src/main/java/com/wss/module/user/ui/account/mvp/LoginModel.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.wss.module.user.ui.account.mvp; - -import com.tamic.novate.Throwable; -import com.wss.common.bean.User; -import com.wss.common.net.Api; -import com.wss.common.net.HttpUtils; -import com.wss.common.net.RequestParam; -import com.wss.common.net.callback.OnResultCallBack; -import com.wss.module.user.ui.account.mvp.contract.LoginContract; - -/** - * Describe:登录Module - * Created by 吴天强 on 2018/11/13. - */ - -public class LoginModel implements LoginContract.Model { - - @Override - public void login(User user, OnResultCallBack callback) { - if (user == null) { - callback.onError("", (Throwable) new Exception("用户信息为空")); - } - RequestParam param = new RequestParam(); - param.addParameter("username", user.getUsername()); - param.addParameter("password", user.getPassword()); - HttpUtils.getInstance() - .postRequest(Api.LOGIN, param, callback); - } -} diff --git a/module_user/src/main/java/com/wss/module/user/ui/account/mvp/LoginPresenter.java b/module_user/src/main/java/com/wss/module/user/ui/account/mvp/LoginPresenter.java index a2b44d6..a8df9fa 100644 --- a/module_user/src/main/java/com/wss/module/user/ui/account/mvp/LoginPresenter.java +++ b/module_user/src/main/java/com/wss/module/user/ui/account/mvp/LoginPresenter.java @@ -1,56 +1,51 @@ package com.wss.module.user.ui.account.mvp; -import android.text.TextUtils; +import android.app.Activity; +import com.wss.common.base.BaseApplication; import com.wss.common.base.mvp.BasePresenter; -import com.wss.common.bean.User; -import com.wss.common.net.callback.OnResultObjectCallBack; +import com.wss.common.bean.Event; +import com.wss.common.constants.EventAction; +import com.wss.common.utils.EventBusUtils; +import com.wss.common.utils.ValidUtils; +import com.wss.common.widget.dialog.AppDialog; import com.wss.module.user.ui.account.mvp.contract.LoginContract; +import com.wss.module.user.ui.account.mvp.model.LoginModel; /** * Describe:登录Presenter * Created by 吴天强 on 2018/11/13. */ -public class LoginPresenter extends BasePresenter - implements LoginContract.Presenter { - +public class LoginPresenter extends BasePresenter implements LoginContract.Presenter { @Override - public void login() { - if (isViewAttached()) { - getView().showLoading(); - getModule().login(getView().getUserInfo(), new OnResultObjectCallBack() { - @Override - public void onSuccess(boolean success, int code, String msg, Object tag, User response) { - if (code == 0 && response != null && !TextUtils.isEmpty(String.valueOf(response.getId()))) { - getView().loginSuccess(response); - } else { - getView().onError(tag, msg); - } - } - - @Override - public void onFailure(Object tag, Exception e) { - getView().onError(tag, msg); - } - - @Override - public void onCompleted() { - getView().dismissLoading(); - } - }); - } + public void login(String userName, String password) { + showLoading(); + getModel().login(userName, password).subscribe( + user -> { + dismissLoading(); + BaseApplication.i().setUser(user); + EventBusUtils.sendEvent(new Event(EventAction.EVENT_LOGIN_SUCCESS)); + ((Activity) getContext()).finish(); + }, t -> { + dismissLoading(); + new AppDialog.Builder(getContext()) + .setContent(ValidUtils.isValid(t.getMessage()) ? t.getMessage() : "登录失败") + .setSingleButton("确定") + .create() + .show(); + + }); } @Override protected LoginModel createModule() { - return new LoginModel(); + return new LoginModel(getLifecycleOwner()); } @Override public void start() { - } } diff --git a/module_user/src/main/java/com/wss/module/user/ui/account/mvp/RegisterModel.java b/module_user/src/main/java/com/wss/module/user/ui/account/mvp/RegisterModel.java deleted file mode 100644 index 6fadcfc..0000000 --- a/module_user/src/main/java/com/wss/module/user/ui/account/mvp/RegisterModel.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.wss.module.user.ui.account.mvp; - -import com.wss.common.bean.User; -import com.wss.common.net.Api; -import com.wss.common.net.HttpUtils; -import com.wss.common.net.RequestParam; -import com.wss.common.net.callback.OnResultCallBack; -import com.wss.module.user.ui.account.mvp.contract.RegisterContract; - -/** - * Describe:注册Module - * Created by 吴天强 on 2018/11/13. - */ - -public class RegisterModel implements RegisterContract.Model { - - - @Override - public void register(User user, OnResultCallBack callback) { - if (user == null) - callback.onError("",null); - RequestParam param = new RequestParam(); - param.addParameter("username", user.getUsername()); - param.addParameter("password", user.getPassword()); - param.addParameter("repassword", user.getPassword()); - HttpUtils.getInstance() - .postRequest(Api.REGISTER, param, callback); - } -} diff --git a/module_user/src/main/java/com/wss/module/user/ui/account/mvp/RegisterPresenter.java b/module_user/src/main/java/com/wss/module/user/ui/account/mvp/RegisterPresenter.java index 2ca9777..50c5d6f 100644 --- a/module_user/src/main/java/com/wss/module/user/ui/account/mvp/RegisterPresenter.java +++ b/module_user/src/main/java/com/wss/module/user/ui/account/mvp/RegisterPresenter.java @@ -1,47 +1,57 @@ package com.wss.module.user.ui.account.mvp; +import android.app.Activity; import android.text.TextUtils; +import com.wss.common.base.BaseApplication; import com.wss.common.base.mvp.BasePresenter; -import com.wss.common.bean.User; -import com.wss.common.constants.Constants; -import com.wss.common.net.callback.OnResultObjectCallBack; +import com.wss.common.bean.Event; +import com.wss.common.constants.EventAction; +import com.wss.common.utils.EventBusUtils; +import com.wss.common.utils.ToastUtils; +import com.wss.common.utils.ValidUtils; import com.wss.module.user.ui.account.mvp.contract.RegisterContract; +import com.wss.module.user.ui.account.mvp.model.RegisterModel; /** * Describe:注册Presenter * Created by 吴天强 on 2018/11/13. */ +public class RegisterPresenter extends BasePresenter implements RegisterContract.Presenter { -public class RegisterPresenter extends BasePresenter - implements RegisterContract.Presenter { + private static final int MIN_INPUT_LENGTH = 6; @Override - public void register() { - if (isViewAttached()) { - getView().showLoading(); - getModule().register(getView().getUserInfo(), new OnResultObjectCallBack() { - @Override - public void onSuccess(boolean success, int code, String msg, Object tag, User response) { + public void register(String userName, String password, String passwordConfirm) { - } - - @Override - public void onFailure(Object tag, Exception e) { - - } - - @Override - public void onCompleted() { + if (userName.length() < MIN_INPUT_LENGTH || password.length() < MIN_INPUT_LENGTH || + passwordConfirm.length() < MIN_INPUT_LENGTH) { + ToastUtils.show("用户名或密码长度至少6位!"); + return; + } + if (!TextUtils.equals(password, passwordConfirm)) { + ToastUtils.show("两次输入密码不一致!"); + return; + } + showLoading(); + getModel().register(userName, password).subscribe( + user -> { + dismissLoading(); + BaseApplication.i().setUser(user); + EventBusUtils.sendEvent(new Event(EventAction.EVENT_REGISTER_SUCCESS)); + ((Activity) getContext()).finish(); + }, + t -> { + dismissLoading(); + ToastUtils.show(ValidUtils.isValid(t.getMessage()) ? t.getMessage() : "注册失败"); } - }); - } + ); } @Override protected RegisterModel createModule() { - return new RegisterModel(); + return new RegisterModel(getLifecycleOwner()); } @Override diff --git a/module_user/src/main/java/com/wss/module/user/ui/account/mvp/contract/LoginContract.java b/module_user/src/main/java/com/wss/module/user/ui/account/mvp/contract/LoginContract.java index 895a93e..cead5a2 100644 --- a/module_user/src/main/java/com/wss/module/user/ui/account/mvp/contract/LoginContract.java +++ b/module_user/src/main/java/com/wss/module/user/ui/account/mvp/contract/LoginContract.java @@ -1,49 +1,40 @@ package com.wss.module.user.ui.account.mvp.contract; -import com.wss.common.base.mvp.IBaseModel; import com.wss.common.base.mvp.IBaseView; import com.wss.common.bean.User; -import com.wss.common.net.callback.OnResultCallBack; + +import io.reactivex.Observable; /** * Describe:登录契约类 * Created by 吴天强 on 2018/11/21. */ - public interface LoginContract { - interface Model extends IBaseModel { + interface Model { /** * 登录 * - * @param user 用户信息 - * @param callback 回调 + * @param userName 账号 + * @param password 密码 + * @return 用户 */ - void login(User user, OnResultCallBack callback); + Observable login(String userName, String password); } interface View extends IBaseView { - - /** - * 返回用户信息 - */ - User getUserInfo(); - - /** - * 登录成功 - */ - void loginSuccess(User user); - - } interface Presenter { /** * 登录 + * + * @param userName 用户名 + * @param password 密码 */ - void login(); + void login(String userName, String password); } } diff --git a/module_user/src/main/java/com/wss/module/user/ui/account/mvp/contract/RegisterContract.java b/module_user/src/main/java/com/wss/module/user/ui/account/mvp/contract/RegisterContract.java index 1e061dc..272f155 100644 --- a/module_user/src/main/java/com/wss/module/user/ui/account/mvp/contract/RegisterContract.java +++ b/module_user/src/main/java/com/wss/module/user/ui/account/mvp/contract/RegisterContract.java @@ -1,9 +1,9 @@ package com.wss.module.user.ui.account.mvp.contract; -import com.wss.common.base.mvp.IBaseModel; import com.wss.common.base.mvp.IBaseView; import com.wss.common.bean.User; -import com.wss.common.net.callback.OnResultCallBack; + +import io.reactivex.Observable; /** * Describe:注册契约类 @@ -12,28 +12,19 @@ public interface RegisterContract { - interface Model extends IBaseModel { + interface Model { /** * 注册 * - * @param user 用户信息 - * @param callback 回调 + * @param userName 用户名 + * @param password 密码 + * @return 用户 */ - void register(User user, OnResultCallBack callback); + Observable register(String userName, String password); } interface View extends IBaseView { - /** - * 返回用户信息 - */ - User getUserInfo(); - - - /** - * 注册成功 - */ - void registerSuccess(User user); } @@ -41,7 +32,11 @@ interface Presenter { /** * 注册 + * + * @param userName 用户名 + * @param password 密码 + * @param passwordConfirm 密码 */ - void register(); + void register(String userName, String password, String passwordConfirm); } } diff --git a/module_user/src/main/java/com/wss/module/user/ui/account/mvp/model/LoginModel.java b/module_user/src/main/java/com/wss/module/user/ui/account/mvp/model/LoginModel.java new file mode 100644 index 0000000..ab090b5 --- /dev/null +++ b/module_user/src/main/java/com/wss/module/user/ui/account/mvp/model/LoginModel.java @@ -0,0 +1,31 @@ +package com.wss.module.user.ui.account.mvp.model; + + +import com.wss.common.base.mvp.BaseModel; +import com.wss.common.bean.User; +import com.wss.common.net.Api; +import com.wss.common.net.NetworkManage; +import com.wss.common.net.request.RequestParam; +import com.wss.module.user.ui.account.mvp.contract.LoginContract; + +import androidx.lifecycle.LifecycleOwner; +import io.reactivex.Observable; + +/** + * Describe:登录Module + * Created by 吴天强 on 2018/11/13. + */ +public class LoginModel extends BaseModel implements LoginContract.Model { + + public LoginModel(LifecycleOwner lifecycleOwner) { + super(lifecycleOwner); + } + + @Override + public Observable login(String userName, String password) { + RequestParam param = new RequestParam(); + param.addParameter("username", userName); + param.addParameter("password", password); + return NetworkManage.createPostForm().request(getLifecycleOwner(), Api.LOGIN, param, User.class); + } +} diff --git a/module_user/src/main/java/com/wss/module/user/ui/account/mvp/model/RegisterModel.java b/module_user/src/main/java/com/wss/module/user/ui/account/mvp/model/RegisterModel.java new file mode 100644 index 0000000..60aa447 --- /dev/null +++ b/module_user/src/main/java/com/wss/module/user/ui/account/mvp/model/RegisterModel.java @@ -0,0 +1,31 @@ +package com.wss.module.user.ui.account.mvp.model; + +import com.wss.common.base.mvp.BaseModel; +import com.wss.common.bean.User; +import com.wss.common.net.Api; +import com.wss.common.net.NetworkManage; +import com.wss.common.net.request.RequestParam; +import com.wss.module.user.ui.account.mvp.contract.RegisterContract; + +import androidx.lifecycle.LifecycleOwner; +import io.reactivex.Observable; + +/** + * Describe:注册Module + * Created by 吴天强 on 2018/11/13. + */ +public class RegisterModel extends BaseModel implements RegisterContract.Model { + + + public RegisterModel(LifecycleOwner lifecycleOwner) { + super(lifecycleOwner); + } + @Override + public Observable register(String userName, String password) { + RequestParam param = new RequestParam(); + param.addParameter("username", userName); + param.addParameter("password", password); + param.addParameter("repassword", password); + return NetworkManage.createPostForm().request(getLifecycleOwner(), Api.REGISTER, param, User.class); + } +} diff --git a/module_user/src/main/java/com/wss/module/user/ui/main/UserMainActivity.java b/module_user/src/main/java/com/wss/module/user/ui/main/UserMainActivity.java index a0bbf6c..0a47da5 100644 --- a/module_user/src/main/java/com/wss/module/user/ui/main/UserMainActivity.java +++ b/module_user/src/main/java/com/wss/module/user/ui/main/UserMainActivity.java @@ -7,7 +7,6 @@ * Describe:该类主要用于组件模式下作为程序入口类使用,集成模式下无需考虑 * Created by 吴天强 on 2018/11/21. */ - public class UserMainActivity extends BaseActivity { @Override protected int getLayoutId() { diff --git a/module_user/src/main/java/com/wss/module/user/ui/main/fragment/UserFragment.java b/module_user/src/main/java/com/wss/module/user/ui/main/fragment/UserFragment.java index 157ebde..dbb6e7a 100644 --- a/module_user/src/main/java/com/wss/module/user/ui/main/fragment/UserFragment.java +++ b/module_user/src/main/java/com/wss/module/user/ui/main/fragment/UserFragment.java @@ -7,17 +7,16 @@ import android.widget.TextView; import com.alibaba.android.arouter.facade.annotation.Route; +import com.wss.common.base.BaseApplication; import com.wss.common.base.BaseMvpFragment; -import com.wss.common.bean.AppInfo; import com.wss.common.bean.Event; import com.wss.common.bean.User; import com.wss.common.constants.ARouterConfig; import com.wss.common.constants.EventAction; -import com.wss.common.manage.UpdateManager; -import com.wss.common.net.Api; -import com.wss.common.utils.ActivityToActivity; +import com.wss.common.manage.ActivityToActivity; import com.wss.common.utils.ImageUtils; -import com.wss.common.utils.UserInfoUtils; +import com.wss.common.utils.Utils; +import com.wss.common.widget.MultipleItemView; import com.wss.common.widget.dialog.AppDialog; import com.wss.module.user.R; import com.wss.module.user.R2; @@ -36,7 +35,7 @@ @Route(path = ARouterConfig.USER_MAIN_FRAGMENT) public class UserFragment extends BaseMvpFragment implements UserContract.View { - public static final String URL = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1542110989472&di=e206dfdad3d1197025ddc03bca0b013c&imgtype=0&src=https%3A%2F%2Fround-lake.dustinice.workers.dev%3A443%2Fhttp%2Fwww.pig66.com%2Fuploadfile%2F2017%2F1209%2F20171209121323978.png"; + private static final String URL = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1597207810717&di=4498f60a4b64fb7a436943bb420c5e1e&imgtype=0&src=https%3A%2F%2Fround-lake.dustinice.workers.dev%3A443%2Fhttp%2Fhbimg.b0.upaiyun.com%2F5bb3acc1916253d3228ab37879d910bfcbe1a7ce1df00a-ld0gg1_fw658"; @BindView(R2.id.iv_bg) ImageView ivBg; @@ -59,24 +58,30 @@ public class UserFragment extends BaseMvpFragment implements User @BindView(R2.id.tv_email) TextView tvEmail; + @BindView(R2.id.miv_check) + MultipleItemView mivVersion; @Override - protected void initView() { + protected int getLayoutId() { + return R.layout.user_fragment_user; + } + @Override + protected void initView() { ImageUtils.loadImageBlur(ivBg, URL); ImageUtils.loadImageCircle(ivHead, URL); - displayInfo(); + refreshPage(); + mivVersion.setRightText(String.format("当前版本:V%s", Utils.getVersionName())); } - private void displayInfo() { - User user = UserInfoUtils.getUser(); - if (UserInfoUtils.isLogged()) { + private void refreshPage() { + if (BaseApplication.i().isLogged()) { + User user = BaseApplication.i().getUser(); llLogged.setVisibility(View.VISIBLE); tvLoginOut.setVisibility(View.VISIBLE); tvLogin.setVisibility(View.GONE); tvName.setText(user.getUsername()); tvEmail.setText(TextUtils.isEmpty(user.getEmail()) ? "暂无邮箱" : user.getEmail()); - } else { llLogged.setVisibility(View.GONE); tvLogin.setVisibility(View.VISIBLE); @@ -84,11 +89,6 @@ private void displayInfo() { } } - @Override - protected int getLayoutId() { - return R.layout.user_fragment_user; - } - @OnClick({R2.id.miv_order, R2.id.miv_check, R2.id.tv_login, R2.id.miv_collection, R2.id.tv_login_out, R2.id.miv_about}) @@ -96,96 +96,61 @@ public void onViewClicked(View view) { int i = view.getId(); if (i == R.id.tv_login) { //去登录 - ActivityToActivity.toActivity(mContext, LoginActivity.class); + ActivityToActivity.toActivity(context, LoginActivity.class); } else if (i == R.id.miv_collection) { //我的收藏 - if (checkLogin()) { - ActivityToActivity.toActivity(ARouterConfig.WAN_COLLECTION); - } + } else if (i == R.id.miv_order) { //我的订单 - if (checkLogin()) { - ActivityToActivity.toActivity(ARouterConfig.MAIN_ORDER_LIST); - } } else if (i == R.id.miv_about) { //关于 - ActivityToActivity.toActivity(mContext, AboutActivity.class); - + ActivityToActivity.toActivity(context, AboutActivity.class); } else if (i == R.id.miv_check) { - presenter.checkUpdate(); - + getPresenter().checkUpdate(); } else if (i == R.id.tv_login_out) { - new AppDialog(mContext) + new AppDialog.Builder(context) .setContent("是否确定退出?") - .setRightButton(new AppDialog.OnButtonClickListener() { - @Override - public void onClick(String val) { - //退出登录 - UserInfoUtils.cleanUser(); - displayInfo(); - } + .setRightButton(val -> { + BaseApplication.i().setUser(null); + refreshPage(); }) + .create() .show(); } } - + /** + * 检查登录 + * + * @return boolean + */ private boolean checkLogin() { - if (!UserInfoUtils.isLogged()) { - new AppDialog(mContext) - .setContent("请您先登录") - .setRightButton(new AppDialog.OnButtonClickListener() { - @Override - public void onClick(String val) { - ActivityToActivity.toActivity(mContext, LoginActivity.class); - } - }) - .show(); - return false; + if (BaseApplication.i().isLogged()) { + return true; } - return true; + new AppDialog.Builder(context) + .setContent("请您先登录") + .setRightButton(val -> ActivityToActivity.toActivity(context, LoginActivity.class)) + .create() + .show(); + return false; } @Override public void onEventBus(Event event) { super.onEventBus(event); - if (TextUtils.equals(event.getAction(), EventAction.EVENT_LOGIN_SUCCESS)) { - displayInfo(); + if (EventAction.EVENT_LOGIN_SUCCESS.equals(event.getAction()) || + EventAction.EVENT_REGISTER_SUCCESS.equals(event.getAction())) { + //登录成功、注册成功刷新页面 + refreshPage(); } } @Override - protected boolean regEvent() { + protected boolean registerEventBus() { return true; } - - @Override - public void needUpdate(AppInfo appInfo) { - String context = "版本更新!"; - if (appInfo != null && !TextUtils.isEmpty(appInfo.getDescribe())) { - context = appInfo.getDescribe(); - } - new AppDialog(mContext) - .setTitle("提示更新") - .setContent(context) - .setRightButton("更新", new AppDialog.OnButtonClickListener() { - @Override - public void onClick(String val) { - UpdateManager.getInstance(mContext).download(Api.DOWNLOAD_APK); - } - }) - .show(); - } - - @Override - public void isLastVersion() { - new AppDialog(mContext) - .setContent("当前已是最新版本") - .setSingleButton("确定") - .show(); - } - @Override protected UserPresenter createPresenter() { return new UserPresenter(); diff --git a/module_user/src/main/java/com/wss/module/user/ui/main/mvp/UserModel.java b/module_user/src/main/java/com/wss/module/user/ui/main/mvp/UserModel.java deleted file mode 100644 index 4eb9045..0000000 --- a/module_user/src/main/java/com/wss/module/user/ui/main/mvp/UserModel.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.wss.module.user.ui.main.mvp; - -import com.wss.common.net.Api; -import com.wss.common.net.HttpUtils; -import com.wss.common.net.RequestParam; -import com.wss.common.net.callback.OnResultCallBack; -import com.wss.common.utils.Utils; -import com.wss.module.user.ui.main.mvp.contract.UserContract; - -/** - * Describe:我的Module - * Created by 吴天强 on 2018/11/21. - */ - -public class UserModel implements UserContract.Model { - - @Override - public void checkUpdate(OnResultCallBack callback) { - RequestParam param = new RequestParam(); - param.addParameter("versionCode", Utils.getVersionCode()); - HttpUtils.getInstance() - .getRequest(Api.CHECK_UPDATE, param, callback); - } -} diff --git a/module_user/src/main/java/com/wss/module/user/ui/main/mvp/UserPresenter.java b/module_user/src/main/java/com/wss/module/user/ui/main/mvp/UserPresenter.java index 2649156..3751351 100644 --- a/module_user/src/main/java/com/wss/module/user/ui/main/mvp/UserPresenter.java +++ b/module_user/src/main/java/com/wss/module/user/ui/main/mvp/UserPresenter.java @@ -1,51 +1,33 @@ package com.wss.module.user.ui.main.mvp; +import android.os.Handler; + import com.wss.common.base.mvp.BasePresenter; -import com.wss.common.bean.AppInfo; -import com.wss.common.constants.Constants; -import com.wss.common.net.callback.OnResultObjectCallBack; import com.wss.common.utils.ToastUtils; import com.wss.module.user.ui.main.mvp.contract.UserContract; +import com.wss.module.user.ui.main.mvp.model.UserModel; /** * Describe:我的Presenter * Created by 吴天强 on 2018/11/21. */ -public class UserPresenter extends BasePresenter +public class UserPresenter extends BasePresenter implements UserContract.Presenter { @Override public void checkUpdate() { - if (isViewAttached()) { - getView().showLoading(); - getModule().checkUpdate(new OnResultObjectCallBack() { - @Override - public void onSuccess(boolean success, int code, String msg, Object tag, AppInfo response) { - if (code == 1000 || response != null) { - //需要更新 - getView().needUpdate(response); - } else { - getView().isLastVersion(); - } - } - - @Override - public void onFailure(Object tag, Exception e) { - ToastUtils.showToast(getContext(), Constants.ERROR_MESSAGE); - } - - @Override - public void onCompleted() { - getView().dismissLoading(); - } - }); - } + showLoading(); + new Handler().postDelayed(() -> { + dismissLoading(); + ToastUtils.show("已是最新版本~"); + }, 1200); + } @Override - protected UserContract.Model createModule() { - return new UserModel(); + protected UserModel createModule() { + return new UserModel(getLifecycleOwner()); } @Override diff --git a/module_user/src/main/java/com/wss/module/user/ui/main/mvp/contract/UserContract.java b/module_user/src/main/java/com/wss/module/user/ui/main/mvp/contract/UserContract.java index 54982dd..2cbc679 100644 --- a/module_user/src/main/java/com/wss/module/user/ui/main/mvp/contract/UserContract.java +++ b/module_user/src/main/java/com/wss/module/user/ui/main/mvp/contract/UserContract.java @@ -1,9 +1,6 @@ package com.wss.module.user.ui.main.mvp.contract; -import com.wss.common.base.mvp.IBaseModel; import com.wss.common.base.mvp.IBaseView; -import com.wss.common.bean.AppInfo; -import com.wss.common.net.callback.OnResultCallBack; /** * Describe:契约类 @@ -12,28 +9,12 @@ public interface UserContract { - interface Model extends IBaseModel { - /** - * 检查更新 - * - * @param callback 回调函数 - */ - void checkUpdate(OnResultCallBack callback); + interface Model { + } interface View extends IBaseView { - /** - * 需要更新 - * - * @param appInfo appInfo - */ - void needUpdate(AppInfo appInfo); - - /** - * 已经是最新版本 - */ - void isLastVersion(); } interface Presenter { diff --git a/module_user/src/main/java/com/wss/module/user/ui/main/mvp/model/UserModel.java b/module_user/src/main/java/com/wss/module/user/ui/main/mvp/model/UserModel.java new file mode 100644 index 0000000..bf3f469 --- /dev/null +++ b/module_user/src/main/java/com/wss/module/user/ui/main/mvp/model/UserModel.java @@ -0,0 +1,17 @@ +package com.wss.module.user.ui.main.mvp.model; + +import com.wss.common.base.mvp.BaseModel; +import com.wss.module.user.ui.main.mvp.contract.UserContract; + +import androidx.lifecycle.LifecycleOwner; + +/** + * Describe:我的Module + * Created by 吴天强 on 2018/11/21. + */ +public class UserModel extends BaseModel implements UserContract.Model { + + public UserModel(LifecycleOwner lifecycleOwner) { + super(lifecycleOwner); + } +} diff --git a/module_user/src/main/module/AndroidManifest.xml b/module_user/src/main/module/AndroidManifest.xml index e53447f..a7a0fb1 100644 --- a/module_user/src/main/module/AndroidManifest.xml +++ b/module_user/src/main/module/AndroidManifest.xml @@ -1,5 +1,5 @@ + package="com.wss.module.people"> diff --git a/module_user/src/main/res/layout/user_activity_login.xml b/module_user/src/main/res/layout/user_activity_login.xml index 578b236..b63bbc4 100644 --- a/module_user/src/main/res/layout/user_activity_login.xml +++ b/module_user/src/main/res/layout/user_activity_login.xml @@ -78,14 +78,14 @@ android:text="登录" android:textColor="@color/black" app:defaultBgResource="@drawable/corner_gray_shape" - app:pressBgResource="@drawable/bg_of_orange_gradient" /> + app:pressBgResource="@drawable/bg_of_orange_gradient_radius" /> diff --git a/module_user/src/main/res/layout/user_activity_register.xml b/module_user/src/main/res/layout/user_activity_register.xml index d51d90b..b429ec7 100644 --- a/module_user/src/main/res/layout/user_activity_register.xml +++ b/module_user/src/main/res/layout/user_activity_register.xml @@ -101,6 +101,6 @@ android:text="注册" android:textColor="@color/black" app:defaultBgResource="@drawable/corner_gray_shape" - app:pressBgResource="@drawable/bg_of_orange_gradient" /> + app:pressBgResource="@drawable/bg_of_orange_gradient_radius" /> diff --git a/module_user/src/main/res/layout/user_activity_user_main.xml b/module_user/src/main/res/layout/user_activity_user_main.xml index bfeb43e..cb0d465 100644 --- a/module_user/src/main/res/layout/user_activity_user_main.xml +++ b/module_user/src/main/res/layout/user_activity_user_main.xml @@ -8,7 +8,7 @@ diff --git a/module_wan_android/README.txt b/module_wan_android/README.txt new file mode 100644 index 0000000..714edb3 --- /dev/null +++ b/module_wan_android/README.txt @@ -0,0 +1,11 @@ +玩android模块 + +为防止同名资源文件被覆盖,则采用如下方式来规避 +1.该module的资源命名必须以[wan_]打头 + 如:wan_icon_close,wan_img_bg,wan_shape_round_4 + +2.该module的布局文件命名必须以[wan_]打头 + 如:wan_activity_main,wan_fragment_main,wan_item_of_user_list + +3.涉及到跨module跳转的Activity、Fragment需要在common_base模块的ARouterConfig中配置跳转的Path + diff --git a/module_wan_android/build.gradle b/module_wan_android/build.gradle index 6e61b46..cebc78f 100644 --- a/module_wan_android/build.gradle +++ b/module_wan_android/build.gradle @@ -50,6 +50,10 @@ android { } } } + compileOptions { + targetCompatibility rootProject.ext.versions.javaSDKVersion + sourceCompatibility rootProject.ext.versions.javaSDKVersion + } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) @@ -57,8 +61,8 @@ dependencies { implementation project(':common_base') //Arouter路由 - annotationProcessor rootProject.ext.dependencies["arouter_compiler"] + annotationProcessor rootProject.ext.dependencies["arouterCompiler"] //黄油刀 - annotationProcessor rootProject.ext.dependencies["butterknife_compiler"] + annotationProcessor rootProject.ext.dependencies["butterknifeCompiler"] } diff --git a/module_wan_android/src/main/AndroidManifest.xml b/module_wan_android/src/main/AndroidManifest.xml index e3b480a..6f6b900 100644 --- a/module_wan_android/src/main/AndroidManifest.xml +++ b/module_wan_android/src/main/AndroidManifest.xml @@ -3,12 +3,11 @@ - - + + - diff --git a/module_wan_android/src/main/java/com/wss/module/wan/bean/Article.java b/module_wan_android/src/main/java/com/wss/module/wan/bean/Article.java index edccc81..876d1a4 100644 --- a/module_wan_android/src/main/java/com/wss/module/wan/bean/Article.java +++ b/module_wan_android/src/main/java/com/wss/module/wan/bean/Article.java @@ -66,7 +66,7 @@ public class Article extends BaseBean { @Getter @Setter - public class ArticleTag extends BaseBean { + private static class ArticleTag extends BaseBean { private String name; private String url; diff --git a/module_wan_android/src/main/java/com/wss/module/wan/bean/BannerInfo.java b/module_wan_android/src/main/java/com/wss/module/wan/bean/BannerInfo.java index 5abb321..683da83 100644 --- a/module_wan_android/src/main/java/com/wss/module/wan/bean/BannerInfo.java +++ b/module_wan_android/src/main/java/com/wss/module/wan/bean/BannerInfo.java @@ -2,11 +2,15 @@ import com.wss.common.base.bean.BaseBean; +import lombok.Getter; +import lombok.Setter; + /** * Describe:Banner实体类 * Created by 吴天强 on 2018/10/17. */ - +@Getter +@Setter public class BannerInfo extends BaseBean { @@ -30,67 +34,4 @@ public class BannerInfo extends BaseBean { private int type; private String url; - public void setDesc(String desc) { - this.desc = desc; - } - - public void setId(int id) { - this.id = id; - } - - public void setImagePath(String imagePath) { - this.imagePath = imagePath; - } - - public void setIsVisible(int isVisible) { - this.isVisible = isVisible; - } - - public void setOrder(int order) { - this.order = order; - } - - public void setTitle(String title) { - this.title = title; - } - - public void setType(int type) { - this.type = type; - } - - public void setUrl(String url) { - this.url = url; - } - - public String getDesc() { - return desc; - } - - public int getId() { - return id; - } - - public String getImagePath() { - return imagePath; - } - - public int getIsVisible() { - return isVisible; - } - - public int getOrder() { - return order; - } - - public String getTitle() { - return title; - } - - public int getType() { - return type; - } - - public String getUrl() { - return url; - } } diff --git a/module_wan_android/src/main/java/com/wss/module/wan/ui/collection/CollectionActivity.java b/module_wan_android/src/main/java/com/wss/module/wan/ui/collection/CollectionActivity.java index 0fd099e..6bf62e3 100644 --- a/module_wan_android/src/main/java/com/wss/module/wan/ui/collection/CollectionActivity.java +++ b/module_wan_android/src/main/java/com/wss/module/wan/ui/collection/CollectionActivity.java @@ -1,29 +1,30 @@ package com.wss.module.wan.ui.collection; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.view.View; - import com.alibaba.android.arouter.facade.annotation.Route; -import com.wss.common.base.RefreshListActivity; +import com.scwang.smartrefresh.layout.api.RefreshLayout; +import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener; +import com.wss.common.base.BaseRefreshListActivity; import com.wss.common.constants.ARouterConfig; -import com.wss.common.utils.ActivityToActivity; +import com.wss.common.manage.ActivityToActivity; import com.wss.common.utils.ToastUtils; -import com.wss.module.wan.R; +import com.wss.common.widget.manager.ScrollSpeedLinearLayoutManger; import com.wss.module.wan.bean.Article; -import com.wss.module.wan.ui.collection.mvp.contract.CollectionContract; import com.wss.module.wan.ui.collection.mvp.CollectionPresenter; +import com.wss.module.wan.ui.collection.mvp.contract.CollectionContract; import com.wss.module.wan.ui.project.adapter.ProjectListAdapter; import java.util.ArrayList; import java.util.List; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + /** * Describe:我的收藏 * Created by 吴天强 on 2018/11/16. */ @Route(path = ARouterConfig.WAN_COLLECTION) -public class CollectionActivity extends RefreshListActivity implements CollectionContract.View { +public class CollectionActivity extends BaseRefreshListActivity implements CollectionContract.View { private int page = 0; @@ -32,26 +33,27 @@ public class CollectionActivity extends RefreshListActivity @Override protected void initView() { super.initView(); - setTitleText("我的收藏"); - presenter.getCollectionList(); + setCenterText("我的收藏"); + getPresenter().getCollectionList(); + getRefreshLayout().setEnableAutoLoadMore(true); } @Override - public void onRefresh() { - page = 0; - collectionList.clear(); - presenter.start(); - } - - @Override - public void onLoadMore() { - page++; - presenter.getCollectionList(); - } - - @Override - public void onItemClick(View view, int position) { - ActivityToActivity.toWebView(mContext, collectionList.get(position).getLink()); + protected OnRefreshLoadMoreListener createRefreshListener() { + return new OnRefreshLoadMoreListener() { + @Override + public void onLoadMore(@NonNull RefreshLayout refreshLayout) { + getPresenter().getCollectionList(); + } + + @Override + public void onRefresh(@NonNull RefreshLayout refreshLayout) { + page = 0; + collectionList.clear(); + getPresenter().getCollectionList(); + getRefreshLayout().setEnableLoadMore(true); + } + }; } @Override @@ -61,12 +63,14 @@ protected CollectionPresenter createPresenter() { @Override protected RecyclerView.LayoutManager getLayoutManager() { - return new LinearLayoutManager(mContext); + return new ScrollSpeedLinearLayoutManger(context); } + @Override protected RecyclerView.Adapter createAdapter() { - return new ProjectListAdapter(mContext, collectionList, R.layout.wan_item_of_project_list, this); + return new ProjectListAdapter(context, collectionList, + ((data, position) -> ActivityToActivity.toWebView(context, collectionList.get(position).getLink()))); } @Override @@ -75,18 +79,24 @@ public int getPage() { } @Override - public void collectionList(List
collections) { + public void refreshCollectionList(List
collections) { + int position = this.collectionList.size(); this.collectionList.addAll(collections); - adapter.notifyDataSetChanged(); + getAdapter().notifyDataSetChanged(); + if (page > 0) { + //向下滚动一点 + getRecyclerView().smoothScrollToPosition(position + 3); + } + page++; } @Override public void onEmpty(Object tag) { - super.onEmpty(tag); if (page == 0) { showEmptyView("您还没有收藏任何东西"); } else { - ToastUtils.showToast(mContext, "暂无更多收藏~"); + ToastUtils.show("暂无更多收藏~"); + getRefreshLayout().setEnableLoadMore(false); } } @@ -96,7 +106,7 @@ public void onError(Object tag, String msg) { if (page == 0) { showEmptyView(msg); } else { - ToastUtils.showToast(mContext, msg); + ToastUtils.show(context, msg); } } } diff --git a/module_wan_android/src/main/java/com/wss/module/wan/ui/collection/mvp/CollectionModel.java b/module_wan_android/src/main/java/com/wss/module/wan/ui/collection/mvp/CollectionModel.java deleted file mode 100644 index ce64d79..0000000 --- a/module_wan_android/src/main/java/com/wss/module/wan/ui/collection/mvp/CollectionModel.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.wss.module.wan.ui.collection.mvp; - -import com.wss.common.net.Api; -import com.wss.common.net.HttpUtils; -import com.wss.common.net.callback.OnResultCallBack; -import com.wss.module.wan.ui.collection.mvp.contract.CollectionContract; - -/** - * Describe:收藏Module - * Created by 吴天强 on 2018/11/16. - */ - -public class CollectionModel implements CollectionContract.Model { - - - @Override - public void getCollectionList(int page, OnResultCallBack callback) { - HttpUtils.getInstance() - .getRequest(String.format(Api.COLLECTION_LIST, page), callback); - } -} diff --git a/module_wan_android/src/main/java/com/wss/module/wan/ui/collection/mvp/CollectionPresenter.java b/module_wan_android/src/main/java/com/wss/module/wan/ui/collection/mvp/CollectionPresenter.java index ec24c89..5d8b26b 100644 --- a/module_wan_android/src/main/java/com/wss/module/wan/ui/collection/mvp/CollectionPresenter.java +++ b/module_wan_android/src/main/java/com/wss/module/wan/ui/collection/mvp/CollectionPresenter.java @@ -1,11 +1,11 @@ package com.wss.module.wan.ui.collection.mvp; -import com.alibaba.fastjson.JSON; import com.wss.common.base.mvp.BasePresenter; -import com.wss.common.constants.Constants; -import com.wss.common.net.callback.OnResultStringCallBack; +import com.wss.common.utils.JsonUtils; +import com.wss.common.utils.ValidUtils; import com.wss.module.wan.bean.Article; import com.wss.module.wan.ui.collection.mvp.contract.CollectionContract; +import com.wss.module.wan.ui.collection.mvp.model.CollectionModel; import java.util.List; @@ -13,51 +13,34 @@ * Describe:收藏Presenter * Created by 吴天强 on 2018/11/16. */ - -public class CollectionPresenter extends BasePresenter +public class CollectionPresenter extends BasePresenter implements CollectionContract.Presenter { - @Override public void getCollectionList() { - if (isViewAttached()) { - getView().showLoading(); - getModule().getCollectionList(getView().getPage(), new OnResultStringCallBack() { - @Override - public void onSuccess(boolean success, int code, String msg, Object tag, String response) { - if (code == Constants.SUCCESS_CODE) { - List
articleList = JSON.parseArray(JSON.parseObject(response).getString("datas"), Article.class); - if (articleList == null || articleList.size() < 1) { - getView().onEmpty(tag); - } else { - getView().collectionList(articleList); - } + showLoading(); + getModel().getCollectionList(getView().getPage()).subscribe( + string -> { + dismissLoading(); + List
list = JsonUtils.getList(JsonUtils.getString(string, "datas"), Article.class); + if (ValidUtils.isValid(list)) { + getView().refreshCollectionList(list); } else { - getView().onError(tag, msg); + getView().onEmpty(""); } - } - - @Override - public void onFailure(Object tag, Exception e) { - getView().onError(tag, Constants.ERROR_MESSAGE); - } - - @Override - public void onCompleted() { - getView().dismissLoading(); - } - }); - } + }, + t -> getView().onError("", t.getMessage()) + ); } + @Override protected CollectionModel createModule() { - return new CollectionModel(); + return new CollectionModel(getLifecycleOwner()); } @Override public void start() { getCollectionList(); } - } diff --git a/module_wan_android/src/main/java/com/wss/module/wan/ui/collection/mvp/contract/CollectionContract.java b/module_wan_android/src/main/java/com/wss/module/wan/ui/collection/mvp/contract/CollectionContract.java index 647a5eb..82cfe28 100644 --- a/module_wan_android/src/main/java/com/wss/module/wan/ui/collection/mvp/contract/CollectionContract.java +++ b/module_wan_android/src/main/java/com/wss/module/wan/ui/collection/mvp/contract/CollectionContract.java @@ -1,12 +1,12 @@ package com.wss.module.wan.ui.collection.mvp.contract; -import com.wss.common.base.mvp.IBaseModel; import com.wss.common.base.mvp.IBaseView; -import com.wss.common.net.callback.OnResultCallBack; import com.wss.module.wan.bean.Article; import java.util.List; +import io.reactivex.Observable; + /** * Describe:收藏契约类 * Created by 吴天强 on 2018/11/21. @@ -14,19 +14,21 @@ public interface CollectionContract { - interface Model extends IBaseModel { + interface Model { /** * 获取收藏列表 * - * @param page 分页 - * @param callback 回调 + * @param page 分页 + * @return string */ - void getCollectionList(int page, OnResultCallBack callback); + Observable getCollectionList(int page); } interface View extends IBaseView { /** * 获取分页 + * + * @return page */ int getPage(); @@ -35,7 +37,7 @@ interface View extends IBaseView { * * @param collections collections */ - void collectionList(List
collections); + void refreshCollectionList(List
collections); } interface Presenter { diff --git a/module_wan_android/src/main/java/com/wss/module/wan/ui/collection/mvp/model/CollectionModel.java b/module_wan_android/src/main/java/com/wss/module/wan/ui/collection/mvp/model/CollectionModel.java new file mode 100644 index 0000000..42db3bc --- /dev/null +++ b/module_wan_android/src/main/java/com/wss/module/wan/ui/collection/mvp/model/CollectionModel.java @@ -0,0 +1,27 @@ +package com.wss.module.wan.ui.collection.mvp.model; + +import com.wss.common.base.mvp.BaseModel; +import com.wss.common.net.Api; +import com.wss.common.net.NetworkManage; +import com.wss.module.wan.ui.collection.mvp.contract.CollectionContract; + +import androidx.lifecycle.LifecycleOwner; +import io.reactivex.Observable; + +/** + * Describe:收藏Module + * Created by 吴天强 on 2018/11/16. + */ +public class CollectionModel extends BaseModel implements CollectionContract.Model { + + + public CollectionModel(LifecycleOwner lifecycleOwner) { + super(lifecycleOwner); + } + + + @Override + public Observable getCollectionList(int page) { + return NetworkManage.createGet().request(getLifecycleOwner(), String.format(Api.COLLECTION_LIST, page)); + } +} diff --git a/module_wan_android/src/main/java/com/wss/module/wan/ui/main/WanMainActivity.java b/module_wan_android/src/main/java/com/wss/module/wan/ui/main/WanMainActivity.java index b46e05a..d2ad2ef 100644 --- a/module_wan_android/src/main/java/com/wss/module/wan/ui/main/WanMainActivity.java +++ b/module_wan_android/src/main/java/com/wss/module/wan/ui/main/WanMainActivity.java @@ -7,7 +7,6 @@ * Describe:该类主要用于组件模式下作为程序入口类使用,集成模式下无需考虑 * Created by 吴天强 on 2018/11/21. */ - public class WanMainActivity extends BaseActivity { diff --git a/module_wan_android/src/main/java/com/wss/module/wan/ui/main/adapter/ArticleAdapter.java b/module_wan_android/src/main/java/com/wss/module/wan/ui/main/adapter/ArticleAdapter.java index 16384cf..1445f5a 100644 --- a/module_wan_android/src/main/java/com/wss/module/wan/ui/main/adapter/ArticleAdapter.java +++ b/module_wan_android/src/main/java/com/wss/module/wan/ui/main/adapter/ArticleAdapter.java @@ -2,10 +2,9 @@ import android.content.Context; import android.text.TextUtils; -import android.view.View; import com.wss.common.base.adapter.BaseListAdapter; -import com.wss.common.listener.OnListItemClickListener; +import com.wss.common.base.adapter.listener.OnListItemClickListener; import com.wss.module.wan.R; import com.wss.module.wan.bean.Article; @@ -22,13 +21,12 @@ public class ArticleAdapter extends BaseListAdapter
{ private OnTagClickListener listener; - public void setOnTagListener(OnTagClickListener listener) { this.listener = listener; } - public ArticleAdapter(Context context, List
items, int layoutResId, OnListItemClickListener listener) { - super(context, items, layoutResId, listener); + public ArticleAdapter(Context context, List
items, OnListItemClickListener
listener) { + super(context, items, R.layout.wan_item_of_article_list, listener); } @Override @@ -42,12 +40,9 @@ public void onBindData(SuperViewHolder holder, int viewType, final int layoutPos if (!TextUtils.isEmpty(data.getSuperChapterName())) { holder.setText(R.id.tv_type2, data.getSuperChapterName()); } - holder.findViewById(R.id.iv_collection).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (listener != null) { - listener.onCollectionClick(layoutPosition); - } + holder.findViewById(R.id.iv_collection).setOnClickListener(v -> { + if (listener != null) { + listener.onCollectionClick(layoutPosition); } }); } @@ -57,7 +52,11 @@ public void onClick(View v) { */ public interface OnTagClickListener { - //收藏按钮被点击 + /** + * 收藏按钮被点击 + * + * @param position pos + */ void onCollectionClick(int position); } } diff --git a/module_wan_android/src/main/java/com/wss/module/wan/ui/main/adapter/HomeRcyAdapter.java b/module_wan_android/src/main/java/com/wss/module/wan/ui/main/adapter/HomeMenuAdapter.java similarity index 61% rename from module_wan_android/src/main/java/com/wss/module/wan/ui/main/adapter/HomeRcyAdapter.java rename to module_wan_android/src/main/java/com/wss/module/wan/ui/main/adapter/HomeMenuAdapter.java index 8c4b92f..85503cf 100644 --- a/module_wan_android/src/main/java/com/wss/module/wan/ui/main/adapter/HomeRcyAdapter.java +++ b/module_wan_android/src/main/java/com/wss/module/wan/ui/main/adapter/HomeMenuAdapter.java @@ -3,8 +3,8 @@ import android.content.Context; import com.wss.common.base.adapter.BaseListAdapter; +import com.wss.common.base.adapter.listener.OnListItemClickListener; import com.wss.common.bean.Template; -import com.wss.common.listener.OnListItemClickListener; import com.wss.module.wan.R; import org.byteam.superadapter.SuperViewHolder; @@ -12,15 +12,14 @@ import java.util.List; /** - * Describe:首页适配器 + * Describe:首页菜单适配器 * Created by 吴天强 on 2018/10/18. */ +public class HomeMenuAdapter extends BaseListAdapter