Commit 8705e211a14efa5eb0a1195105084887e6c1b3d0

Authored by 简柏林
0 parents

首次提交

Showing 32 changed files with 4731 additions and 0 deletions

Too many changes to show.

To preserve performance only 32 of 737 files are displayed.

  1 +.gradle
  2 +.idea
  3 +.cxx
  4 +.externalNativeBuild
  5 +build
  6 +captures
  7 +
  8 +._*
  9 +*.iml
  10 +.DS_Store
  11 +local.properties
\ No newline at end of file
... ...
No preview for this file type
  1 +apply plugin: 'com.android.application'
  2 +apply plugin: 'android-aspectjx'
  3 +apply from: '../common.gradle'
  4 +
  5 +// Android 代码规范文档:https://github.com/getActivity/AndroidCodeStandard
  6 +android {
  7 + sourceSets {
  8 + main {
  9 + // res 资源目录配置
  10 + jniLibs.srcDirs = ['src/main/libs']
  11 + res.srcDirs(
  12 + 'src/main/res',
  13 + 'src/main/res-sw',
  14 + )
  15 + }
  16 + }
  17 + // 资源目录存放指引:https://developer.android.google.cn/guide/topics/resources/providing-resources
  18 + defaultConfig {
  19 +
  20 + // 无痛修改包名:https://www.jianshu.com/p/17327e191d2e
  21 + applicationId 'com.studymachine.www'
  22 +
  23 + // 仅保留中文语种的资源
  24 + resConfigs 'zh'
  25 +
  26 + // 仅保留 xxhdpi 图片资源(目前主流分辨率 1920 * 1080)
  27 + resConfigs 'xxhdpi'
  28 +
  29 + // 混淆配置
  30 + proguardFiles 'proguard-sdk.pro', 'proguard-app.pro'
  31 +
  32 + // 日志打印开关
  33 + buildConfigField('boolean', 'LOG_ENABLE', '' + LOG_ENABLE + '')
  34 + // 测试包下的 BuglyId
  35 + buildConfigField('String', 'BUGLY_ID', '"' + BUGLY_ID + '"')
  36 + // 测试服务器的主机地址
  37 + buildConfigField('String', 'HOST_URL', '"' + HOST_URL + '"')
  38 + // 测试oss服务器的主机地址
  39 + buildConfigField('String', 'IMAGER_HOST_URL', '"' + IMAGER_HOST_URL + '"')
  40 + // 测试web的主机地址
  41 + buildConfigField('String', 'WEB_HOST_URL', '"' + WEB_HOST_URL + '"')
  42 +
  43 +
  44 + javaCompileOptions {
  45 + annotationProcessorOptions {
  46 + // EventBus Apt 索引类生成位置
  47 + arguments = [eventBusIndex: applicationId + '.MyEventBusIndex']
  48 + }
  49 + }
  50 + }
  51 +
  52 + // Apk 签名的那些事:https://www.jianshu.com/p/a1f8e5896aa2
  53 + signingConfigs {
  54 + config {
  55 + storeFile file(StoreFile)
  56 + storePassword StorePassword
  57 + keyAlias KeyAlias
  58 + keyPassword KeyPassword
  59 + v1SigningEnabled true
  60 + v2SigningEnabled true
  61 + }
  62 + release {
  63 + storeFile file(StoreFile)
  64 + storePassword StorePassword
  65 + keyAlias KeyAlias
  66 + keyPassword KeyPassword
  67 + v1SigningEnabled true
  68 + v2SigningEnabled false
  69 + }
  70 + }
  71 +
  72 + // 构建配置:https://developer.android.google.cn/studio/build/build-variants
  73 + buildTypes {
  74 +
  75 + debug {
  76 + // 给包名添加后缀
  77 + applicationIdSuffix '.debug'
  78 + // 调试模式开关
  79 + debuggable true
  80 + jniDebuggable true
  81 + // 压缩对齐开关
  82 + zipAlignEnabled false
  83 + // 移除无用的资源
  84 + shrinkResources false
  85 + // 代码混淆开关
  86 + minifyEnabled false
  87 + // 签名信息配置
  88 + signingConfig signingConfigs.config
  89 + // 添加清单占位符
  90 + addManifestPlaceholders([
  91 + 'app_name': '未来猫 Debug 版'
  92 + ])
  93 + // 调试模式下只保留一种架构的 so 库,提升打包速度
  94 + ndk {
  95 + abiFilters 'armeabi-v7a'
  96 + }
  97 + }
  98 +
  99 + preview.initWith(debug)
  100 + preview {
  101 + applicationIdSuffix ''
  102 + // 添加清单占位符
  103 + addManifestPlaceholders([
  104 + 'app_name': '@string/app_name'
  105 + ])
  106 + }
  107 +
  108 + release {
  109 + // 调试模式开关
  110 + debuggable false
  111 + jniDebuggable false
  112 + // 压缩对齐开关
  113 + zipAlignEnabled true
  114 + // 移除无用的资源
  115 + shrinkResources true
  116 + // 代码混淆开关
  117 + minifyEnabled true
  118 + // 签名信息配置
  119 + signingConfig signingConfigs.release
  120 + // 添加清单占位符
  121 + addManifestPlaceholders([
  122 + 'app_name': '@string/app_name'
  123 + ])
  124 + // 仅保留两种架构的 so 库,根据 Bugly 统计得出
  125 + ndk {
  126 + // armeabi:万金油架构平台(占用率:0%)
  127 + // armeabi-v7a:曾经主流的架构平台(占用率:10%)
  128 + // arm64-v8a:目前主流架构平台(占用率:95%)
  129 + abiFilters 'armeabi-v7a'
  130 +// , 'arm64-v8a' 因为swf的原因 不能保留
  131 + }
  132 + }
  133 + }
  134 +
  135 + packagingOptions {
  136 + // 剔除这个包下的所有文件(不会移除签名信息)
  137 + exclude 'META-INF/*******'
  138 + }
  139 +
  140 + // AOP 配置(exclude 和 include 二选一)
  141 + // 需要进行配置,否则就会引发冲突,具体表现为:
  142 + // 第一种:编译不过去,报错:java.util.zip.ZipException:Cause: zip file is empty
  143 + // 第二种:编译能过去,但运行时报错:ClassNotFoundException: Didn't find class on path: DexPathList
  144 + aspectjx {
  145 + // 排除一些第三方库的包名(Gson、 LeakCanary 和 AOP 有冲突)
  146 + // exclude 'androidx', 'com.google', 'com.squareup', 'org.apache', 'com.alipay', 'com.taobao', 'versions.9'
  147 + // 只对以下包名做 AOP 处理
  148 + include android.defaultConfig.applicationId
  149 + }
  150 +
  151 + applicationVariants.all { variant ->
  152 + // apk 输出文件名配置
  153 + variant.outputs.all { output ->
  154 + outputFileName = rootProject.getName() + '_v' + variant.versionName + '_' + variant.buildType.name
  155 + if (variant.buildType.name == buildTypes.release.getName()) {
  156 + outputFileName += '_' + new Date().format('MMdd')
  157 + }
  158 + outputFileName += '.apk'
  159 + }
  160 + }
  161 +}
  162 +
  163 +// 添加构建依赖项:https://developer.android.google.cn/studio/build/dependencies
  164 +// api 与 implementation 的区别:https://www.jianshu.com/p/8962d6ba936e
  165 +dependencies {
  166 + // 基类封装
  167 + implementation project(':library:base')
  168 + // 控件封装
  169 + implementation project(':library:widget')
  170 + // 友盟封装
  171 + implementation project(':library:umeng')
  172 +
  173 + // 依赖 libs 目录下所有的 jar 和 aar 包
  174 + implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
  175 +
  176 +
  177 + //ZXing的精简极速版 https://github.com/jenly1314/ZXingLite
  178 + implementation 'com.github.jenly1314:zxing-lite:2.1.1'
  179 +
  180 + // 快速实现新手引导层的库 https://github.com/huburt-Hu/NewbieGuide
  181 + implementation 'com.github.huburt-Hu:NewbieGuide:v2.4.0'
  182 +
  183 + //日历 https://github.com/huanghaibin-dev/CalendarView
  184 + implementation 'com.haibin:calendarview:3.7.1'
  185 +
  186 + //XPopup:https://github.com/li-xiaojun/XPopup
  187 + implementation 'com.github.li-xiaojun:XPopup:2.7.6'
  188 +
  189 + //官方的flex布局控件
  190 + implementation 'com.google.android:flexbox:1.0.0'
  191 +
  192 + // 权限请求框架:https://github.com/getActivity/XXPermissions
  193 + implementation 'com.github.getActivity:XXPermissions:12.3'
  194 +
  195 + // 标题栏框架:https://github.com/getActivity/TitleBar
  196 + implementation 'com.github.getActivity:TitleBar:9.2'
  197 +
  198 + // 吐司框架:https://github.com/getActivity/ToastUtils
  199 + implementation 'com.github.getActivity:ToastUtils:9.5'
  200 +
  201 + // 网络请求框架:https://github.com/getActivity/EasyHttp
  202 + implementation 'com.github.getActivity:EasyHttp:10.2'
  203 + // OkHttp 框架:https://github.com/square/okhttp
  204 + // noinspection GradleDependency
  205 + implementation 'com.squareup.okhttp3:okhttp:3.12.13'
  206 +
  207 + // Json 解析框架:https://github.com/google/gson
  208 + implementation 'com.google.code.gson:gson:2.8.8'
  209 + // Gson 解析容错:https://github.com/getActivity/GsonFactory
  210 + implementation 'com.github.getActivity:GsonFactory:5.2'
  211 +
  212 + // Shape 框架:https://github.com/getActivity/ShapeView
  213 + implementation 'com.github.getActivity:ShapeView:6.0'
  214 +
  215 + // AOP 插件库:https://mvnrepository.com/artifact/org.aspectj/aspectjrt
  216 + implementation 'org.aspectj:aspectjrt:1.9.6'
  217 +
  218 + // 图片加载框架:https://github.com/bumptech/glide
  219 + // 官方使用文档:https://github.com/Muyangmin/glide-docs-cn
  220 + implementation 'com.github.bumptech.glide:glide:4.12.0'
  221 + annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
  222 +
  223 + // 沉浸式框架:https://github.com/gyf-dev/ImmersionBar
  224 + implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
  225 +
  226 + // 手势 ImageView:https://github.com/Baseflow/PhotoView
  227 + implementation 'com.github.Baseflow:PhotoView:2.3.0'
  228 +
  229 + // Bugly 异常捕捉:https://bugly.qq.com/docs/user-guide/instruction-manual-android/?v=20190418140644
  230 + implementation 'com.tencent.bugly:crashreport:3.4.4'
  231 + implementation 'com.tencent.bugly:nativecrashreport:3.9.2'
  232 +
  233 + // 动画解析库:https://github.com/airbnb/lottie-android
  234 + // 动画资源:https://lottiefiles.com、https://icons8.com/animated-icons
  235 + implementation 'com.airbnb.android:lottie:4.1.0'
  236 +
  237 + // 上拉刷新下拉加载框架:https://github.com/scwang90/SmartRefreshLayout
  238 + implementation 'com.scwang.smart:refresh-layout-kernel:2.0.3'
  239 + implementation 'com.scwang.smart:refresh-header-material:2.0.3'
  240 +
  241 + // 日志打印框架:https://github.com/JakeWharton/timber
  242 + implementation 'com.jakewharton.timber:timber:4.7.1'
  243 +
  244 + // 指示器框架:https://github.com/ongakuer/CircleIndicator
  245 + implementation 'me.relex:circleindicator:2.1.6'
  246 +
  247 + // 腾讯 MMKV:https://github.com/Tencent/MMKV
  248 + implementation 'com.tencent:mmkv-static:1.2.10'
  249 +
  250 + // 内存泄漏监测框架:https://github.com/square/leakcanary
  251 + debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
  252 + previewImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
  253 + // 工具类:https://github.com/Blankj/AndroidUtilCode
  254 + implementation 'com.blankj:utilcodex:1.31.0'
  255 + //eventbus:https://github.com/greenrobot/EventBus
  256 + implementation 'org.greenrobot:eventbus:3.1.1'
  257 + annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1'
  258 + //轮播图:https://github.com/youth5201314/banner
  259 + implementation 'io.github.youth5201314:banner:2.2.1'
  260 + // 轮播图:https://github.com/bingoogolapple/BGABanner-Android
  261 + // 多语种:https://github.com/getActivity/MultiLanguages
  262 + // 悬浮窗:https://github.com/getActivity/XToast
  263 + // 日志输出:https://github.com/getActivity/Logcat
  264 + // 工具类:https://github.com/Blankj/AndroidUtilCode
  265 + // 二维码:https://github.com/bingoogolapple/BGAQRCode-Android
  266 + // 跑马灯:https://github.com/sunfusheng/MarqueeView
  267 + // 对象注解:https://www.jianshu.com/p/f1f888e4a35f
  268 + // 对象存储:https://github.com/leavesC/DoKV
  269 + // 多渠道打包:https://github.com/Meituan-Dianping/walle
  270 + // 设备唯一标识:http://msa-alliance.cn/col.jsp?id=120
  271 + // 嵌套滚动容器:https://github.com/donkingliang/ConsecutiveScroller
  272 + // 隐私调用监控:https://github.com/huage2580/PermissionMonitor
  273 + //RKGlassDevice Glass 设备管理模块
  274 + implementation 'com.rokid.axr:glassdevice-phone:1.0.4'
  275 +}
\ No newline at end of file
... ...
  1 +StoreFile = AppSignature.jks
  2 +StorePassword = 123456
  3 +KeyAlias = study
  4 +KeyPassword = 123456
\ No newline at end of file
... ...
No preview for this file type
  1 +# 忽略警告
  2 +#-ignorewarning
  3 +
  4 +# 混淆保护自己项目的部分代码以及引用的第三方jar包
  5 +#-libraryjars libs/xxxxxxxxx.jar
  6 +
  7 +#swf播放器
  8 +-libraryjars libs/classes.jar
  9 +-keep public class softboy.swfplayer.FileUtils {*;}
  10 +-keep public class air.com.adobe.appentry.AppEntry {*;}
  11 +-keep class a.a.a.a** {*;}
  12 +-keep class air.com.** {*;}
  13 +-keep class android.arch.** {*;}
  14 +-keep class b.** {*;}
  15 +-keep class c.** {*;}
  16 +-keep class com.a.** {*;}
  17 +-keep class com.adobe.** {*;}
  18 +-keep class com.adobe.air** {*;}
  19 +-keep class com.android.** {*;}
  20 +-keep class b.a.** {*;}
  21 +
  22 +# 不混淆这个包下的类
  23 +-keep class com.studymachine.www.http.api.** {
  24 + <fields>;
  25 +}
  26 +-keep class com.studymachine.www.http.response.** {
  27 + <fields>;
  28 +}
  29 +-keep class com.studymachine.www.http.model.** {
  30 + <fields>;
  31 +}
  32 +-keep class com.studymachine.www.domain.** {
  33 + <fields>;
  34 +}
  35 +
  36 +# 不混淆被 Log 注解的方法信息
  37 +-keepclassmembernames class ** {
  38 + @com.studymachine.www.aop.Log <methods>;
  39 +}
\ No newline at end of file
... ...
  1 +# Glide
  2 +-keep public class * implements com.bumptech.glide.module.GlideModule
  3 +-keep class * extends com.bumptech.glide.module.AppGlideModule {
  4 + <init>(...);
  5 +}
  6 +-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
  7 + **[] $VALUES;
  8 + public *;
  9 +}
  10 +-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder {
  11 + *** rewind();
  12 +}
  13 +
  14 +# for DexGuard only
  15 +#-keepresourcexmlelements manifest/application/meta-data@value=GlideModule
  16 +
  17 +# Bugly
  18 +-dontwarn com.tencent.bugly.**
  19 +-keep public class com.tencent.bugly.**{*;}
  20 +
  21 +# AOP
  22 +-adaptclassstrings
  23 +-keepattributes InnerClasses, EnclosingMethod, Signature, *Annotation*
  24 +
  25 +-keepnames @org.aspectj.lang.annotation.Aspect class * {
  26 + public <methods>;
  27 +}
  28 +
  29 +# EventBus
  30 +-keepattributes *Annotation*
  31 +-keepclassmembers class ** {
  32 + @org.greenrobot.eventbus.Subscribe <methods>;
  33 +}
  34 +-keep enum org.greenrobot.eventbus.ThreadMode { *; }
  35 +
  36 +# OkHttp3
  37 +-keepattributes Signature
  38 +-keepattributes *Annotation*
  39 +-keep class okhttp3.** { *; }
  40 +-keep interface okhttp3.** { *; }
  41 +-dontwarn okhttp3.**
  42 +-dontwarn okio.**
  43 +-dontwarn org.conscrypt.**
  44 +
  45 +#腾讯x5
  46 +-dontwarn dalvik.**
  47 +-dontwarn com.tencent.smtt.**
  48 +
  49 +-keep class com.tencent.smtt.** {
  50 + *;
  51 +}
  52 +
  53 +-keep class com.tencent.tbs.** {
  54 + *;
  55 +}
  56 +
  57 +#日历
  58 +-keepclasseswithmembers class * {
  59 + public <init>(android.content.Context);
  60 +}
  61 +
  62 +#swf播放器
  63 +-libraryjars libs/classes.jar
  64 +-keep public class softboy.swfplayer.FileUtils {*;}
  65 +-keep public class air.com.adobe.appentry.AppEntry {*;}
  66 +-keep class a.a.a.a** {*;}
  67 +-keep class air.com.** {*;}
  68 +-keep class android.arch.** {*;}
  69 +-keep class b.** {*;}
  70 +-keep class c.** {*;}
  71 +-keep class com.a.** {*;}
  72 +-keep class com.adobe.** {*;}
  73 +-keep class com.android.** {*;}
  74 +-keep class b.a.** {*;}
\ No newline at end of file
... ...
  1 +{
  2 + "version": 2,
  3 + "artifactType": {
  4 + "type": "APK",
  5 + "kind": "Directory"
  6 + },
  7 + "applicationId": "com.studymachine.www",
  8 + "variantName": "processReleaseResources",
  9 + "elements": [
  10 + {
  11 + "type": "SINGLE",
  12 + "filters": [],
  13 + "versionCode": 204,
  14 + "versionName": "2.0.4",
  15 + "outputFile": "StudyMachine_v2.0.4_release_0901.apk"
  16 + }
  17 + ]
  18 +}
\ No newline at end of file
... ...
  1 +<?xml version="1.0" encoding="utf-8"?><!-- 清单文件合并指引:https://developer.android.google.cn/studio/build/manifest-merge?hl=zh-cn -->
  2 +<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3 + xmlns:tools="http://schemas.android.com/tools"
  4 + package="com.studymachine.www">
  5 +
  6 + <!-- 网络相关 -->
  7 + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  8 + <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
  9 + <uses-permission android:name="android.permission.INTERNET" />
  10 +
  11 + <!-- 外部存储 -->
  12 + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  13 + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  14 +
  15 + <!-- 拍照权限 -->
  16 + <uses-permission android:name="android.permission.CAMERA" />
  17 +
  18 + <!-- 安装权限 -->
  19 + <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
  20 +
  21 + <!-- 定位权限(用于 WebView 定位)-->
  22 + <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  23 + <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  24 + <uses-permission android:name= "android.permission.SYSTEM_ALERT_WINDOW" />
  25 + <uses-permission android:name= "android.permission.SYSTEM_OVERLAY_WINDOW" />
  26 +
  27 + <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  28 + <uses-feature android:name="android.hardware.usb.host" />
  29 +
  30 + <!-- Application 节点详解:https://developer.android.google.cn/guide/topics/manifest/application-element -->
  31 + <!-- Activity 节点详解:https://developer.android.google.cn/guide/topics/manifest/activity-element -->
  32 + <application
  33 + android:name="com.studymachine.www.app.AppApplication"
  34 + android:allowBackup="false"
  35 + android:icon="@mipmap/launcher_ic"
  36 + android:label="${app_name}"
  37 + android:largeHeap="true"
  38 + android:networkSecurityConfig="@xml/network_security_config"
  39 + android:requestLegacyExternalStorage="true"
  40 + android:resizeableActivity="true"
  41 + android:roundIcon="@mipmap/launcher_ic"
  42 + android:supportsRtl="false"
  43 + android:theme="@style/AppTheme"
  44 + android:usesCleartextTraffic="true"
  45 + tools:ignore="AllowBackup,LockedOrientationActivity"
  46 + tools:replace="android:allowBackup,android:supportsRtl"
  47 + android:extractNativeLibs="true"
  48 + >
  49 +
  50 + <service
  51 + android:name="com.tencent.smtt.export.external.DexClassLoaderProviderService"
  52 + android:label="dexopt"
  53 + android:process=":dexopt" />
  54 +
  55 + <!-- 表示当前已经适配了分区存储 -->
  56 + <meta-data
  57 + android:name="ScopedStorage"
  58 + android:value="true" />
  59 +
  60 + <!-- 适配 Android 7.0 文件意图 -->
  61 + <provider
  62 + android:name="androidx.core.content.FileProvider"
  63 + android:authorities="${applicationId}.provider"
  64 + android:exported="false"
  65 + android:grantUriPermissions="true">
  66 + <meta-data
  67 + android:name="android.support.FILE_PROVIDER_PATHS"
  68 + android:resource="@xml/file_paths" />
  69 + </provider>
  70 +
  71 +
  72 + <activity
  73 + android:name=".ui.activity.SwfActivity"
  74 + android:process=":flash"
  75 + android:screenOrientation="landscape"
  76 + android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
  77 + <meta-data
  78 + android:name="namespaceVersion"
  79 + android:value="32" />
  80 + <meta-data
  81 + android:name="autoOrients"
  82 + android:value="true" />
  83 + <meta-data
  84 + android:name="fullScreen"
  85 + android:value="true" />
  86 + <meta-data
  87 + android:name="initialcontent"
  88 + android:value="cached.swf" />
  89 + <meta-data
  90 + android:name="containsVideo"
  91 + android:value="false" />
  92 + <meta-data
  93 + android:name="embeddedFonts"
  94 + android:value="false" />
  95 + <meta-data
  96 + android:name="webContentsDebuggingEnabled"
  97 + android:value="false" />
  98 + <meta-data
  99 + android:name="disableMediaCodec"
  100 + android:value="false" />
  101 +
  102 + <intent-filter>
  103 + <action android:name="android.intent.action.VIEW" />
  104 +
  105 + <category android:name="android.intent.category.BROWSABLE" />
  106 + <category android:name="android.intent.category.DEFAULT" />
  107 +
  108 + <data android:scheme="com.softboy.flashairtest" />
  109 + </intent-filter>
  110 +
  111 + </activity>
  112 +
  113 +
  114 + <!-- 闪屏页 -->
  115 + <activity
  116 + android:name="com.studymachine.www.ui.activity.SplashActivity"
  117 + android:launchMode="singleTop"
  118 + android:screenOrientation="landscape"
  119 + android:theme="@style/SplashTheme">
  120 + <!-- 程序入口 -->
  121 + <intent-filter>
  122 + <action android:name="android.intent.action.MAIN" />
  123 + <action android:name="android.intent.action.VIEW" />
  124 +
  125 + <category android:name="android.intent.category.LAUNCHER" />
  126 + </intent-filter>
  127 + </activity>
  128 +
  129 + <!-- 无网络页 -->
  130 + <activity
  131 + android:name="com.studymachine.www.ui.activity.NoNetworkActivity"
  132 + android:launchMode="singleTop"
  133 + android:screenOrientation="landscape"
  134 + android:theme="@style/TransparentTheme" />
  135 +
  136 + <!-- 外置浏览器界面 -->
  137 + <activity
  138 + android:name="com.studymachine.www.ui.activity.ExternalBrowserActivity"
  139 + android:launchMode="singleTop"
  140 + android:screenOrientation="landscape"
  141 + android:theme="@style/TransparentTheme" />
  142 +
  143 + <!-- 首页 -->
  144 + <activity
  145 + android:name="com.studymachine.www.ui.activity.HomeActivity"
  146 + android:launchMode="singleTask"
  147 + android:screenOrientation="landscape"
  148 + android:windowSoftInputMode="adjustPan" />
  149 +
  150 + <!-- 学情档案详情 -->
  151 + <activity
  152 + android:name="com.studymachine.www.ui.activity.RecordDetailActivity"
  153 + android:launchMode="singleTask"
  154 + android:screenOrientation="landscape"
  155 + android:windowSoftInputMode="adjustPan" />
  156 + <!-- 学情档案 -->
  157 + <activity
  158 + android:name="com.studymachine.www.ui.activity.RecordActivity"
  159 + android:launchMode="singleTask"
  160 + android:screenOrientation="landscape"
  161 + android:windowSoftInputMode="adjustPan" />
  162 +
  163 + <!-- 知识竞技列表 -->
  164 + <activity
  165 + android:name="com.studymachine.www.ui.activity.ArenaListActivity"
  166 + android:launchMode="singleTask"
  167 + android:screenOrientation="landscape"
  168 + android:windowSoftInputMode="adjustPan" />
  169 +
  170 + <!-- ai列表 -->
  171 + <activity
  172 + android:name="com.studymachine.www.ui.activity.AiListActivity"
  173 + android:launchMode="singleTask"
  174 + android:screenOrientation="landscape"
  175 + android:windowSoftInputMode="adjustPan" />
  176 +
  177 + <!-- ai详情 -->
  178 + <activity
  179 + android:name="com.studymachine.www.ui.activity.AiDetailActivity"
  180 + android:configChanges="orientation|screenSize|keyboardHidden"
  181 + android:launchMode="singleTask"
  182 + android:screenOrientation="landscape"
  183 + android:windowSoftInputMode="adjustPan" />
  184 +
  185 + <!-- 精准强化列表 -->
  186 + <activity
  187 + android:name="com.studymachine.www.ui.activity.AccurateListActivity"
  188 + android:launchMode="singleTask"
  189 + android:screenOrientation="landscape"
  190 + android:windowSoftInputMode="adjustPan" />
  191 +
  192 + <!-- 精准强化详情 -->
  193 + <activity
  194 + android:name="com.studymachine.www.ui.activity.AccurateDetailActivity"
  195 + android:launchMode="singleTask"
  196 + android:screenOrientation="landscape"
  197 + android:windowSoftInputMode="adjustPan" />
  198 +
  199 + <!-- 登录页 -->
  200 + <activity
  201 + android:name="com.studymachine.www.ui.activity.LoginActivity"
  202 + android:launchMode="singleTask"
  203 + android:screenOrientation="landscape"
  204 + android:windowSoftInputMode="stateHidden" />
  205 +
  206 + <!-- 注册页 -->
  207 + <activity
  208 + android:name="com.studymachine.www.ui.activity.RegisterActivity"
  209 + android:launchMode="singleTop"
  210 + android:screenOrientation="landscape"
  211 + android:windowSoftInputMode="stateHidden" />
  212 + <!-- 协议-->
  213 + <activity
  214 + android:name="com.studymachine.www.ui.activity.AgreementActivity"
  215 + android:launchMode="singleTop"
  216 + android:screenOrientation="landscape"
  217 + android:windowSoftInputMode="stateHidden" />
  218 + <!-- 注册页 选择年级-->
  219 + <activity
  220 + android:name="com.studymachine.www.ui.activity.RegisterGradeActivity"
  221 + android:launchMode="singleTop"
  222 + android:screenOrientation="landscape"
  223 + android:windowSoftInputMode="stateHidden" />
  224 + <!-- 注册页 选择教材-->
  225 + <activity
  226 + android:name="com.studymachine.www.ui.activity.RegisterTextbookActivity"
  227 + android:launchMode="singleTop"
  228 + android:screenOrientation="landscape"
  229 + android:windowSoftInputMode="stateHidden" />
  230 + <!-- 注册页 公众号二维码-->
  231 + <activity
  232 + android:name="com.studymachine.www.ui.activity.RegisterWechatActivity"
  233 + android:launchMode="singleTop"
  234 + android:screenOrientation="landscape"
  235 + android:windowSoftInputMode="stateHidden" />
  236 + <!-- 注册页 选择虚拟形象-->
  237 + <activity
  238 + android:name="com.studymachine.www.ui.activity.RegisterPersonActivity"
  239 + android:launchMode="singleTop"
  240 + android:screenOrientation="landscape"
  241 + android:windowSoftInputMode="stateHidden">
  242 +
  243 + </activity>
  244 + <!-- 忘记密码 -->
  245 + <activity
  246 + android:name="com.studymachine.www.ui.activity.PasswordForgetActivity"
  247 + android:label="@string/password_forget_title"
  248 + android:launchMode="singleTop"
  249 + android:screenOrientation="landscape"
  250 + android:windowSoftInputMode="stateHidden" />
  251 + <!-- 崩溃展示(必须在独立进程) -->
  252 + <activity
  253 + android:name="com.studymachine.www.ui.activity.CrashActivity"
  254 + android:launchMode="singleTop"
  255 + android:process=":crash"
  256 + android:screenOrientation="landscape" />
  257 +
  258 + <!-- 重启应用(必须在独立进程) -->
  259 + <activity
  260 + android:name="com.studymachine.www.ui.activity.RestartActivity"
  261 + android:launchMode="singleTop"
  262 + android:process=":restart" />
  263 +
  264 + <!-- 个人资料 -->
  265 + <activity
  266 + android:name="com.studymachine.www.ui.activity.PersonalCenterActivity"
  267 + android:launchMode="singleTop"
  268 + android:screenOrientation="landscape" />
  269 +
  270 + <!-- 常见问题 -->
  271 + <activity
  272 + android:name="com.studymachine.www.ui.activity.CommonProblemActivity"
  273 + android:launchMode="singleTop"
  274 + android:screenOrientation="landscape"
  275 + android:theme="@style/TransparentTheme" />
  276 +
  277 + <activity
  278 + android:name="com.studymachine.www.ui.activity.BrowserActivity"
  279 + android:launchMode="singleTop"
  280 + android:screenOrientation="landscape" />
  281 +
  282 + <!-- 拍照选择 -->
  283 + <activity
  284 + android:name="com.studymachine.www.ui.activity.CameraActivity"
  285 + android:launchMode="singleTop"
  286 + android:screenOrientation="portrait" />
  287 +
  288 + <!-- 图片裁剪 -->
  289 + <activity
  290 + android:name="com.studymachine.www.ui.activity.ImageCropActivity"
  291 + android:launchMode="singleTop"
  292 + android:screenOrientation="portrait" />
  293 +
  294 + <!-- 图片选择 -->
  295 + <activity
  296 + android:name="com.studymachine.www.ui.activity.ImageSelectActivity"
  297 + android:label="@string/image_select_title"
  298 + android:launchMode="singleTop"
  299 + android:screenOrientation="portrait" />
  300 +
  301 + <!-- 查看大图 -->
  302 + <activity
  303 + android:name="com.studymachine.www.ui.activity.ImagePreviewActivity"
  304 + android:launchMode="singleTop"
  305 + android:screenOrientation="portrait" />
  306 +
  307 + <!-- 播放视频(自适应方向) -->
  308 + <activity
  309 + android:name="com.studymachine.www.ui.activity.VideoPlayActivity"
  310 + android:launchMode="singleTop"
  311 + android:theme="@style/FullScreenTheme" />
  312 +
  313 + <!-- 播放视频(竖屏方向) -->
  314 + <activity
  315 + android:name="com.studymachine.www.ui.activity.VideoPlayActivity$Portrait"
  316 + android:launchMode="singleTop"
  317 + android:screenOrientation="portrait"
  318 + android:theme="@style/FullScreenTheme" />
  319 +
  320 + <!-- 播放视频(横屏方向) -->
  321 + <activity
  322 + android:name="com.studymachine.www.ui.activity.VideoPlayActivity$Landscape"
  323 + android:launchMode="singleTop"
  324 + android:screenOrientation="landscape"
  325 + android:theme="@style/FullScreenTheme" />
  326 +
  327 + <!-- 选择视频 -->
  328 + <activity
  329 + android:name="com.studymachine.www.ui.activity.VideoSelectActivity"
  330 + android:launchMode="singleTop"
  331 + android:screenOrientation="portrait" />
  332 +
  333 +
  334 + <!-- 微信回调(请注意这个 Activity 放置的包名要和当前项目的包名保持一致,否则将不能正常回调) -->
  335 + <activity
  336 + android:name="com.studymachine.www.wxapi.WXEntryActivity"
  337 + android:configChanges="keyboardHidden|orientation|screenSize"
  338 + android:exported="true"
  339 + android:theme="@android:style/Theme.Translucent.NoTitleBar" />
  340 +
  341 + </application>
  342 +
  343 + <!-- Android 11 软件包可见性适配:https://www.jianshu.com/p/d1ccd425c4ce -->
  344 + <queries>
  345 + <!-- 拍照意图:MediaStore.ACTION_IMAGE_CAPTURE -->
  346 + <intent>
  347 + <action android:name="android.media.action.IMAGE_CAPTURE" />
  348 + </intent>
  349 +
  350 + <!-- 拍摄意图:MediaStore.ACTION_VIDEO_CAPTURE -->
  351 + <intent>
  352 + <action android:name="android.media.action.VIDEO_CAPTURE" />
  353 + </intent>
  354 +
  355 + <!-- 图片裁剪意图 -->
  356 + <intent>
  357 + <action android:name="com.android.camera.action.CROP" />
  358 + </intent>
  359 +
  360 + <!-- 打电话意图:Intent.ACTION_DIAL -->
  361 + <intent>
  362 + <action android:name="android.intent.action.DIAL" />
  363 + </intent>
  364 +
  365 + <!-- 调起分享意图:Intent.ACTION_SEND -->
  366 + <intent>
  367 + <action android:name="android.intent.action.SEND" />
  368 + </intent>
  369 +
  370 + <!-- 调起其他页面意图:Intent.ACTION_VIEW -->
  371 + <intent>
  372 + <action android:name="android.intent.action.VIEW" />
  373 + </intent>
  374 +
  375 + <!-- 调起系统文件选择器:Intent.ACTION_GET_CONTENT -->
  376 + <intent>
  377 + <action android:name="android.intent.action.GET_CONTENT" />
  378 + </intent>
  379 + </queries>
  380 +
  381 +</manifest>
\ No newline at end of file
... ...
  1 +<?xml version="1.0" encoding="utf-8" standalone="no" ?>
  2 +<!--
  3 + Usage:
  4 +
  5 + To localize the description, use the following format for the description element.
  6 + <description>
  7 + <text xml:lang="en">English App description goes here</text>
  8 + <text xml:lang="fr">French App description goes here</text>
  9 + <text xml:lang="ja">Japanese App description goes here</text>
  10 + </description>
  11 +
  12 + To localize the name, use the following format for the name element.
  13 + <name>
  14 + <text xml:lang="en">English App name goes here</text>
  15 + <text xml:lang="fr">French App name goes here</text>
  16 + <text xml:lang="ja">Japanese App name goes here</text>
  17 + </name>
  18 +-->
  19 +<application xmlns="http://ns.adobe.com/air/application/3.8">
  20 + <id>issess</id>
  21 + <versionNumber>1.0.0</versionNumber>
  22 + <versionLabel>1.0.0</versionLabel>
  23 + <filename>cached</filename>
  24 + <description/>
  25 + <name>cached</name>
  26 + <copyright/>
  27 + <initialWindow>
  28 + <content>cached.swf</content>
  29 + <systemChrome>standard</systemChrome>
  30 + <transparent>false</transparent>
  31 + <visible>true</visible>
  32 + <fullScreen>true</fullScreen>
  33 +
  34 + <renderMode>gpu</renderMode>
  35 + <autoOrients>true</autoOrients></initialWindow>
  36 + <icon/>
  37 + <customUpdateUI>false</customUpdateUI>
  38 + <allowBrowserInvocation>false</allowBrowserInvocation>
  39 + <android>
  40 + <manifestAdditions><![CDATA[<manifest>
  41 +</manifest>]]></manifestAdditions>
  42 + </android>
  43 +</application>
\ No newline at end of file
... ...
No preview for this file type
  1 +<!DOCTYPE html>
  2 +<html lang="en">
  3 +<head>
  4 + <meta charset="UTF-8"/>
  5 + <title></title>
  6 +</head>
  7 +<link rel="stylesheet" href="./quill.bubble.css">
  8 +<link rel="stylesheet" href="./quill.core.css">
  9 +<link rel="stylesheet" href="./quill.snow.css">
  10 +<body>
  11 +<div class="ql-editor" id="ql-editor" style="color:#FFF;">
  12 +</div>
  13 +<script>
  14 + const data = studyMachine.getSingPageData()
  15 + const content = document.getElementById("ql-editor")
  16 + content.innerHTML = data
  17 +</script>
  18 +</body>
  19 +</html>
... ...
  1 +/*!
  2 + * Quill Editor v1.3.7
  3 + * https://quilljs.com/
  4 + * Copyright (c) 2014, Jason Chen
  5 + * Copyright (c) 2013, salesforce.com
  6 + */
  7 +.ql-container {
  8 + box-sizing: border-box;
  9 + font-family: Helvetica, Arial, sans-serif;
  10 + font-size: 13px;
  11 + height: 100%;
  12 + margin: 0px;
  13 + position: relative;
  14 +}
  15 +.ql-container.ql-disabled .ql-tooltip {
  16 + visibility: hidden;
  17 +}
  18 +.ql-container.ql-disabled .ql-editor ul[data-checked] > li::before {
  19 + pointer-events: none;
  20 +}
  21 +.ql-clipboard {
  22 + left: -100000px;
  23 + height: 1px;
  24 + overflow-y: hidden;
  25 + position: absolute;
  26 + top: 50%;
  27 +}
  28 +.ql-clipboard p {
  29 + margin: 0;
  30 + padding: 0;
  31 +}
  32 +.ql-editor {
  33 + box-sizing: border-box;
  34 + line-height: 1.42;
  35 + height: 100%;
  36 + outline: none;
  37 + overflow-y: auto;
  38 + padding: 12px 15px;
  39 + tab-size: 4;
  40 + -moz-tab-size: 4;
  41 + text-align: left;
  42 + white-space: pre-wrap;
  43 + word-wrap: break-word;
  44 +}
  45 +.ql-editor > * {
  46 + cursor: text;
  47 +}
  48 +.ql-editor p,
  49 +.ql-editor ol,
  50 +.ql-editor ul,
  51 +.ql-editor pre,
  52 +.ql-editor blockquote,
  53 +.ql-editor h1,
  54 +.ql-editor h2,
  55 +.ql-editor h3,
  56 +.ql-editor h4,
  57 +.ql-editor h5,
  58 +.ql-editor h6 {
  59 + margin: 0;
  60 + padding: 0;
  61 + counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
  62 +}
  63 +.ql-editor ol,
  64 +.ql-editor ul {
  65 + padding-left: 1.5em;
  66 +}
  67 +.ql-editor ol > li,
  68 +.ql-editor ul > li {
  69 + list-style-type: none;
  70 +}
  71 +.ql-editor ul > li::before {
  72 + content: '\2022';
  73 +}
  74 +.ql-editor ul[data-checked=true],
  75 +.ql-editor ul[data-checked=false] {
  76 + pointer-events: none;
  77 +}
  78 +.ql-editor ul[data-checked=true] > li *,
  79 +.ql-editor ul[data-checked=false] > li * {
  80 + pointer-events: all;
  81 +}
  82 +.ql-editor ul[data-checked=true] > li::before,
  83 +.ql-editor ul[data-checked=false] > li::before {
  84 + color: #777;
  85 + cursor: pointer;
  86 + pointer-events: all;
  87 +}
  88 +.ql-editor ul[data-checked=true] > li::before {
  89 + content: '\2611';
  90 +}
  91 +.ql-editor ul[data-checked=false] > li::before {
  92 + content: '\2610';
  93 +}
  94 +.ql-editor li::before {
  95 + display: inline-block;
  96 + white-space: nowrap;
  97 + width: 1.2em;
  98 +}
  99 +.ql-editor li:not(.ql-direction-rtl)::before {
  100 + margin-left: -1.5em;
  101 + margin-right: 0.3em;
  102 + text-align: right;
  103 +}
  104 +.ql-editor li.ql-direction-rtl::before {
  105 + margin-left: 0.3em;
  106 + margin-right: -1.5em;
  107 +}
  108 +.ql-editor ol li:not(.ql-direction-rtl),
  109 +.ql-editor ul li:not(.ql-direction-rtl) {
  110 + padding-left: 1.5em;
  111 +}
  112 +.ql-editor ol li.ql-direction-rtl,
  113 +.ql-editor ul li.ql-direction-rtl {
  114 + padding-right: 1.5em;
  115 +}
  116 +.ql-editor ol li {
  117 + counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
  118 + counter-increment: list-0;
  119 +}
  120 +.ql-editor ol li:before {
  121 + content: counter(list-0, decimal) '. ';
  122 +}
  123 +.ql-editor ol li.ql-indent-1 {
  124 + counter-increment: list-1;
  125 +}
  126 +.ql-editor ol li.ql-indent-1:before {
  127 + content: counter(list-1, lower-alpha) '. ';
  128 +}
  129 +.ql-editor ol li.ql-indent-1 {
  130 + counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
  131 +}
  132 +.ql-editor ol li.ql-indent-2 {
  133 + counter-increment: list-2;
  134 +}
  135 +.ql-editor ol li.ql-indent-2:before {
  136 + content: counter(list-2, lower-roman) '. ';
  137 +}
  138 +.ql-editor ol li.ql-indent-2 {
  139 + counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9;
  140 +}
  141 +.ql-editor ol li.ql-indent-3 {
  142 + counter-increment: list-3;
  143 +}
  144 +.ql-editor ol li.ql-indent-3:before {
  145 + content: counter(list-3, decimal) '. ';
  146 +}
  147 +.ql-editor ol li.ql-indent-3 {
  148 + counter-reset: list-4 list-5 list-6 list-7 list-8 list-9;
  149 +}
  150 +.ql-editor ol li.ql-indent-4 {
  151 + counter-increment: list-4;
  152 +}
  153 +.ql-editor ol li.ql-indent-4:before {
  154 + content: counter(list-4, lower-alpha) '. ';
  155 +}
  156 +.ql-editor ol li.ql-indent-4 {
  157 + counter-reset: list-5 list-6 list-7 list-8 list-9;
  158 +}
  159 +.ql-editor ol li.ql-indent-5 {
  160 + counter-increment: list-5;
  161 +}
  162 +.ql-editor ol li.ql-indent-5:before {
  163 + content: counter(list-5, lower-roman) '. ';
  164 +}
  165 +.ql-editor ol li.ql-indent-5 {
  166 + counter-reset: list-6 list-7 list-8 list-9;
  167 +}
  168 +.ql-editor ol li.ql-indent-6 {
  169 + counter-increment: list-6;
  170 +}
  171 +.ql-editor ol li.ql-indent-6:before {
  172 + content: counter(list-6, decimal) '. ';
  173 +}
  174 +.ql-editor ol li.ql-indent-6 {
  175 + counter-reset: list-7 list-8 list-9;
  176 +}
  177 +.ql-editor ol li.ql-indent-7 {
  178 + counter-increment: list-7;
  179 +}
  180 +.ql-editor ol li.ql-indent-7:before {
  181 + content: counter(list-7, lower-alpha) '. ';
  182 +}
  183 +.ql-editor ol li.ql-indent-7 {
  184 + counter-reset: list-8 list-9;
  185 +}
  186 +.ql-editor ol li.ql-indent-8 {
  187 + counter-increment: list-8;
  188 +}
  189 +.ql-editor ol li.ql-indent-8:before {
  190 + content: counter(list-8, lower-roman) '. ';
  191 +}
  192 +.ql-editor ol li.ql-indent-8 {
  193 + counter-reset: list-9;
  194 +}
  195 +.ql-editor ol li.ql-indent-9 {
  196 + counter-increment: list-9;
  197 +}
  198 +.ql-editor ol li.ql-indent-9:before {
  199 + content: counter(list-9, decimal) '. ';
  200 +}
  201 +.ql-editor .ql-indent-1:not(.ql-direction-rtl) {
  202 + padding-left: 3em;
  203 +}
  204 +.ql-editor li.ql-indent-1:not(.ql-direction-rtl) {
  205 + padding-left: 4.5em;
  206 +}
  207 +.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right {
  208 + padding-right: 3em;
  209 +}
  210 +.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right {
  211 + padding-right: 4.5em;
  212 +}
  213 +.ql-editor .ql-indent-2:not(.ql-direction-rtl) {
  214 + padding-left: 6em;
  215 +}
  216 +.ql-editor li.ql-indent-2:not(.ql-direction-rtl) {
  217 + padding-left: 7.5em;
  218 +}
  219 +.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right {
  220 + padding-right: 6em;
  221 +}
  222 +.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right {
  223 + padding-right: 7.5em;
  224 +}
  225 +.ql-editor .ql-indent-3:not(.ql-direction-rtl) {
  226 + padding-left: 9em;
  227 +}
  228 +.ql-editor li.ql-indent-3:not(.ql-direction-rtl) {
  229 + padding-left: 10.5em;
  230 +}
  231 +.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right {
  232 + padding-right: 9em;
  233 +}
  234 +.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right {
  235 + padding-right: 10.5em;
  236 +}
  237 +.ql-editor .ql-indent-4:not(.ql-direction-rtl) {
  238 + padding-left: 12em;
  239 +}
  240 +.ql-editor li.ql-indent-4:not(.ql-direction-rtl) {
  241 + padding-left: 13.5em;
  242 +}
  243 +.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right {
  244 + padding-right: 12em;
  245 +}
  246 +.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right {
  247 + padding-right: 13.5em;
  248 +}
  249 +.ql-editor .ql-indent-5:not(.ql-direction-rtl) {
  250 + padding-left: 15em;
  251 +}
  252 +.ql-editor li.ql-indent-5:not(.ql-direction-rtl) {
  253 + padding-left: 16.5em;
  254 +}
  255 +.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right {
  256 + padding-right: 15em;
  257 +}
  258 +.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right {
  259 + padding-right: 16.5em;
  260 +}
  261 +.ql-editor .ql-indent-6:not(.ql-direction-rtl) {
  262 + padding-left: 18em;
  263 +}
  264 +.ql-editor li.ql-indent-6:not(.ql-direction-rtl) {
  265 + padding-left: 19.5em;
  266 +}
  267 +.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right {
  268 + padding-right: 18em;
  269 +}
  270 +.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right {
  271 + padding-right: 19.5em;
  272 +}
  273 +.ql-editor .ql-indent-7:not(.ql-direction-rtl) {
  274 + padding-left: 21em;
  275 +}
  276 +.ql-editor li.ql-indent-7:not(.ql-direction-rtl) {
  277 + padding-left: 22.5em;
  278 +}
  279 +.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right {
  280 + padding-right: 21em;
  281 +}
  282 +.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right {
  283 + padding-right: 22.5em;
  284 +}
  285 +.ql-editor .ql-indent-8:not(.ql-direction-rtl) {
  286 + padding-left: 24em;
  287 +}
  288 +.ql-editor li.ql-indent-8:not(.ql-direction-rtl) {
  289 + padding-left: 25.5em;
  290 +}
  291 +.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right {
  292 + padding-right: 24em;
  293 +}
  294 +.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right {
  295 + padding-right: 25.5em;
  296 +}
  297 +.ql-editor .ql-indent-9:not(.ql-direction-rtl) {
  298 + padding-left: 27em;
  299 +}
  300 +.ql-editor li.ql-indent-9:not(.ql-direction-rtl) {
  301 + padding-left: 28.5em;
  302 +}
  303 +.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right {
  304 + padding-right: 27em;
  305 +}
  306 +.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right {
  307 + padding-right: 28.5em;
  308 +}
  309 +.ql-editor .ql-video {
  310 + display: block;
  311 + max-width: 100%;
  312 +}
  313 +.ql-editor .ql-video.ql-align-center {
  314 + margin: 0 auto;
  315 +}
  316 +.ql-editor .ql-video.ql-align-right {
  317 + margin: 0 0 0 auto;
  318 +}
  319 +.ql-editor .ql-bg-black {
  320 + background-color: #000;
  321 +}
  322 +.ql-editor .ql-bg-red {
  323 + background-color: #e60000;
  324 +}
  325 +.ql-editor .ql-bg-orange {
  326 + background-color: #f90;
  327 +}
  328 +.ql-editor .ql-bg-yellow {
  329 + background-color: #ff0;
  330 +}
  331 +.ql-editor .ql-bg-green {
  332 + background-color: #008a00;
  333 +}
  334 +.ql-editor .ql-bg-blue {
  335 + background-color: #06c;
  336 +}
  337 +.ql-editor .ql-bg-purple {
  338 + background-color: #93f;
  339 +}
  340 +.ql-editor .ql-color-white {
  341 + color: #fff;
  342 +}
  343 +.ql-editor .ql-color-red {
  344 + color: #e60000;
  345 +}
  346 +.ql-editor .ql-color-orange {
  347 + color: #f90;
  348 +}
  349 +.ql-editor .ql-color-yellow {
  350 + color: #ff0;
  351 +}
  352 +.ql-editor .ql-color-green {
  353 + color: #008a00;
  354 +}
  355 +.ql-editor .ql-color-blue {
  356 + color: #06c;
  357 +}
  358 +.ql-editor .ql-color-purple {
  359 + color: #93f;
  360 +}
  361 +.ql-editor .ql-font-serif {
  362 + font-family: Georgia, Times New Roman, serif;
  363 +}
  364 +.ql-editor .ql-font-monospace {
  365 + font-family: Monaco, Courier New, monospace;
  366 +}
  367 +.ql-editor .ql-size-small {
  368 + font-size: 0.75em;
  369 +}
  370 +.ql-editor .ql-size-large {
  371 + font-size: 1.5em;
  372 +}
  373 +.ql-editor .ql-size-huge {
  374 + font-size: 2.5em;
  375 +}
  376 +.ql-editor .ql-direction-rtl {
  377 + direction: rtl;
  378 + text-align: inherit;
  379 +}
  380 +.ql-editor .ql-align-center {
  381 + text-align: center;
  382 +}
  383 +.ql-editor .ql-align-justify {
  384 + text-align: justify;
  385 +}
  386 +.ql-editor .ql-align-right {
  387 + text-align: right;
  388 +}
  389 +.ql-editor.ql-blank::before {
  390 + color: rgba(0,0,0,0.6);
  391 + content: attr(data-placeholder);
  392 + font-style: italic;
  393 + left: 15px;
  394 + pointer-events: none;
  395 + position: absolute;
  396 + right: 15px;
  397 +}
  398 +.ql-bubble.ql-toolbar:after,
  399 +.ql-bubble .ql-toolbar:after {
  400 + clear: both;
  401 + content: '';
  402 + display: table;
  403 +}
  404 +.ql-bubble.ql-toolbar button,
  405 +.ql-bubble .ql-toolbar button {
  406 + background: none;
  407 + border: none;
  408 + cursor: pointer;
  409 + display: inline-block;
  410 + float: left;
  411 + height: 24px;
  412 + padding: 3px 5px;
  413 + width: 28px;
  414 +}
  415 +.ql-bubble.ql-toolbar button svg,
  416 +.ql-bubble .ql-toolbar button svg {
  417 + float: left;
  418 + height: 100%;
  419 +}
  420 +.ql-bubble.ql-toolbar button:active:hover,
  421 +.ql-bubble .ql-toolbar button:active:hover {
  422 + outline: none;
  423 +}
  424 +.ql-bubble.ql-toolbar input.ql-image[type=file],
  425 +.ql-bubble .ql-toolbar input.ql-image[type=file] {
  426 + display: none;
  427 +}
  428 +.ql-bubble.ql-toolbar button:hover,
  429 +.ql-bubble .ql-toolbar button:hover,
  430 +.ql-bubble.ql-toolbar button:focus,
  431 +.ql-bubble .ql-toolbar button:focus,
  432 +.ql-bubble.ql-toolbar button.ql-active,
  433 +.ql-bubble .ql-toolbar button.ql-active,
  434 +.ql-bubble.ql-toolbar .ql-picker-label:hover,
  435 +.ql-bubble .ql-toolbar .ql-picker-label:hover,
  436 +.ql-bubble.ql-toolbar .ql-picker-label.ql-active,
  437 +.ql-bubble .ql-toolbar .ql-picker-label.ql-active,
  438 +.ql-bubble.ql-toolbar .ql-picker-item:hover,
  439 +.ql-bubble .ql-toolbar .ql-picker-item:hover,
  440 +.ql-bubble.ql-toolbar .ql-picker-item.ql-selected,
  441 +.ql-bubble .ql-toolbar .ql-picker-item.ql-selected {
  442 + color: #fff;
  443 +}
  444 +.ql-bubble.ql-toolbar button:hover .ql-fill,
  445 +.ql-bubble .ql-toolbar button:hover .ql-fill,
  446 +.ql-bubble.ql-toolbar button:focus .ql-fill,
  447 +.ql-bubble .ql-toolbar button:focus .ql-fill,
  448 +.ql-bubble.ql-toolbar button.ql-active .ql-fill,
  449 +.ql-bubble .ql-toolbar button.ql-active .ql-fill,
  450 +.ql-bubble.ql-toolbar .ql-picker-label:hover .ql-fill,
  451 +.ql-bubble .ql-toolbar .ql-picker-label:hover .ql-fill,
  452 +.ql-bubble.ql-toolbar .ql-picker-label.ql-active .ql-fill,
  453 +.ql-bubble .ql-toolbar .ql-picker-label.ql-active .ql-fill,
  454 +.ql-bubble.ql-toolbar .ql-picker-item:hover .ql-fill,
  455 +.ql-bubble .ql-toolbar .ql-picker-item:hover .ql-fill,
  456 +.ql-bubble.ql-toolbar .ql-picker-item.ql-selected .ql-fill,
  457 +.ql-bubble .ql-toolbar .ql-picker-item.ql-selected .ql-fill,
  458 +.ql-bubble.ql-toolbar button:hover .ql-stroke.ql-fill,
  459 +.ql-bubble .ql-toolbar button:hover .ql-stroke.ql-fill,
  460 +.ql-bubble.ql-toolbar button:focus .ql-stroke.ql-fill,
  461 +.ql-bubble .ql-toolbar button:focus .ql-stroke.ql-fill,
  462 +.ql-bubble.ql-toolbar button.ql-active .ql-stroke.ql-fill,
  463 +.ql-bubble .ql-toolbar button.ql-active .ql-stroke.ql-fill,
  464 +.ql-bubble.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,
  465 +.ql-bubble .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,
  466 +.ql-bubble.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,
  467 +.ql-bubble .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,
  468 +.ql-bubble.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,
  469 +.ql-bubble .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,
  470 +.ql-bubble.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill,
  471 +.ql-bubble .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill {
  472 + fill: #fff;
  473 +}
  474 +.ql-bubble.ql-toolbar button:hover .ql-stroke,
  475 +.ql-bubble .ql-toolbar button:hover .ql-stroke,
  476 +.ql-bubble.ql-toolbar button:focus .ql-stroke,
  477 +.ql-bubble .ql-toolbar button:focus .ql-stroke,
  478 +.ql-bubble.ql-toolbar button.ql-active .ql-stroke,
  479 +.ql-bubble .ql-toolbar button.ql-active .ql-stroke,
  480 +.ql-bubble.ql-toolbar .ql-picker-label:hover .ql-stroke,
  481 +.ql-bubble .ql-toolbar .ql-picker-label:hover .ql-stroke,
  482 +.ql-bubble.ql-toolbar .ql-picker-label.ql-active .ql-stroke,
  483 +.ql-bubble .ql-toolbar .ql-picker-label.ql-active .ql-stroke,
  484 +.ql-bubble.ql-toolbar .ql-picker-item:hover .ql-stroke,
  485 +.ql-bubble .ql-toolbar .ql-picker-item:hover .ql-stroke,
  486 +.ql-bubble.ql-toolbar .ql-picker-item.ql-selected .ql-stroke,
  487 +.ql-bubble .ql-toolbar .ql-picker-item.ql-selected .ql-stroke,
  488 +.ql-bubble.ql-toolbar button:hover .ql-stroke-miter,
  489 +.ql-bubble .ql-toolbar button:hover .ql-stroke-miter,
  490 +.ql-bubble.ql-toolbar button:focus .ql-stroke-miter,
  491 +.ql-bubble .ql-toolbar button:focus .ql-stroke-miter,
  492 +.ql-bubble.ql-toolbar button.ql-active .ql-stroke-miter,
  493 +.ql-bubble .ql-toolbar button.ql-active .ql-stroke-miter,
  494 +.ql-bubble.ql-toolbar .ql-picker-label:hover .ql-stroke-miter,
  495 +.ql-bubble .ql-toolbar .ql-picker-label:hover .ql-stroke-miter,
  496 +.ql-bubble.ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,
  497 +.ql-bubble .ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,
  498 +.ql-bubble.ql-toolbar .ql-picker-item:hover .ql-stroke-miter,
  499 +.ql-bubble .ql-toolbar .ql-picker-item:hover .ql-stroke-miter,
  500 +.ql-bubble.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter,
  501 +.ql-bubble .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter {
  502 + stroke: #fff;
  503 +}
  504 +@media (pointer: coarse) {
  505 + .ql-bubble.ql-toolbar button:hover:not(.ql-active),
  506 + .ql-bubble .ql-toolbar button:hover:not(.ql-active) {
  507 + color: #ccc;
  508 + }
  509 + .ql-bubble.ql-toolbar button:hover:not(.ql-active) .ql-fill,
  510 + .ql-bubble .ql-toolbar button:hover:not(.ql-active) .ql-fill,
  511 + .ql-bubble.ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill,
  512 + .ql-bubble .ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill {
  513 + fill: #ccc;
  514 + }
  515 + .ql-bubble.ql-toolbar button:hover:not(.ql-active) .ql-stroke,
  516 + .ql-bubble .ql-toolbar button:hover:not(.ql-active) .ql-stroke,
  517 + .ql-bubble.ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter,
  518 + .ql-bubble .ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter {
  519 + stroke: #ccc;
  520 + }
  521 +}
  522 +.ql-bubble {
  523 + box-sizing: border-box;
  524 +}
  525 +.ql-bubble * {
  526 + box-sizing: border-box;
  527 +}
  528 +.ql-bubble .ql-hidden {
  529 + display: none;
  530 +}
  531 +.ql-bubble .ql-out-bottom,
  532 +.ql-bubble .ql-out-top {
  533 + visibility: hidden;
  534 +}
  535 +.ql-bubble .ql-tooltip {
  536 + position: absolute;
  537 + transform: translateY(10px);
  538 +}
  539 +.ql-bubble .ql-tooltip a {
  540 + cursor: pointer;
  541 + text-decoration: none;
  542 +}
  543 +.ql-bubble .ql-tooltip.ql-flip {
  544 + transform: translateY(-10px);
  545 +}
  546 +.ql-bubble .ql-formats {
  547 + display: inline-block;
  548 + vertical-align: middle;
  549 +}
  550 +.ql-bubble .ql-formats:after {
  551 + clear: both;
  552 + content: '';
  553 + display: table;
  554 +}
  555 +.ql-bubble .ql-stroke {
  556 + fill: none;
  557 + stroke: #ccc;
  558 + stroke-linecap: round;
  559 + stroke-linejoin: round;
  560 + stroke-width: 2;
  561 +}
  562 +.ql-bubble .ql-stroke-miter {
  563 + fill: none;
  564 + stroke: #ccc;
  565 + stroke-miterlimit: 10;
  566 + stroke-width: 2;
  567 +}
  568 +.ql-bubble .ql-fill,
  569 +.ql-bubble .ql-stroke.ql-fill {
  570 + fill: #ccc;
  571 +}
  572 +.ql-bubble .ql-empty {
  573 + fill: none;
  574 +}
  575 +.ql-bubble .ql-even {
  576 + fill-rule: evenodd;
  577 +}
  578 +.ql-bubble .ql-thin,
  579 +.ql-bubble .ql-stroke.ql-thin {
  580 + stroke-width: 1;
  581 +}
  582 +.ql-bubble .ql-transparent {
  583 + opacity: 0.4;
  584 +}
  585 +.ql-bubble .ql-direction svg:last-child {
  586 + display: none;
  587 +}
  588 +.ql-bubble .ql-direction.ql-active svg:last-child {
  589 + display: inline;
  590 +}
  591 +.ql-bubble .ql-direction.ql-active svg:first-child {
  592 + display: none;
  593 +}
  594 +.ql-bubble .ql-editor h1 {
  595 + font-size: 2em;
  596 +}
  597 +.ql-bubble .ql-editor h2 {
  598 + font-size: 1.5em;
  599 +}
  600 +.ql-bubble .ql-editor h3 {
  601 + font-size: 1.17em;
  602 +}
  603 +.ql-bubble .ql-editor h4 {
  604 + font-size: 1em;
  605 +}
  606 +.ql-bubble .ql-editor h5 {
  607 + font-size: 0.83em;
  608 +}
  609 +.ql-bubble .ql-editor h6 {
  610 + font-size: 0.67em;
  611 +}
  612 +.ql-bubble .ql-editor a {
  613 + text-decoration: underline;
  614 +}
  615 +.ql-bubble .ql-editor blockquote {
  616 + border-left: 4px solid #ccc;
  617 + margin-bottom: 5px;
  618 + margin-top: 5px;
  619 + padding-left: 16px;
  620 +}
  621 +.ql-bubble .ql-editor code,
  622 +.ql-bubble .ql-editor pre {
  623 + background-color: #f0f0f0;
  624 + border-radius: 3px;
  625 +}
  626 +.ql-bubble .ql-editor pre {
  627 + white-space: pre-wrap;
  628 + margin-bottom: 5px;
  629 + margin-top: 5px;
  630 + padding: 5px 10px;
  631 +}
  632 +.ql-bubble .ql-editor code {
  633 + font-size: 85%;
  634 + padding: 2px 4px;
  635 +}
  636 +.ql-bubble .ql-editor pre.ql-syntax {
  637 + background-color: #23241f;
  638 + color: #f8f8f2;
  639 + overflow: visible;
  640 +}
  641 +.ql-bubble .ql-editor img {
  642 + max-width: 100%;
  643 +}
  644 +.ql-bubble .ql-picker {
  645 + color: #ccc;
  646 + display: inline-block;
  647 + float: left;
  648 + font-size: 14px;
  649 + font-weight: 500;
  650 + height: 24px;
  651 + position: relative;
  652 + vertical-align: middle;
  653 +}
  654 +.ql-bubble .ql-picker-label {
  655 + cursor: pointer;
  656 + display: inline-block;
  657 + height: 100%;
  658 + padding-left: 8px;
  659 + padding-right: 2px;
  660 + position: relative;
  661 + width: 100%;
  662 +}
  663 +.ql-bubble .ql-picker-label::before {
  664 + display: inline-block;
  665 + line-height: 22px;
  666 +}
  667 +.ql-bubble .ql-picker-options {
  668 + background-color: #444;
  669 + display: none;
  670 + min-width: 100%;
  671 + padding: 4px 8px;
  672 + position: absolute;
  673 + white-space: nowrap;
  674 +}
  675 +.ql-bubble .ql-picker-options .ql-picker-item {
  676 + cursor: pointer;
  677 + display: block;
  678 + padding-bottom: 5px;
  679 + padding-top: 5px;
  680 +}
  681 +.ql-bubble .ql-picker.ql-expanded .ql-picker-label {
  682 + color: #777;
  683 + z-index: 2;
  684 +}
  685 +.ql-bubble .ql-picker.ql-expanded .ql-picker-label .ql-fill {
  686 + fill: #777;
  687 +}
  688 +.ql-bubble .ql-picker.ql-expanded .ql-picker-label .ql-stroke {
  689 + stroke: #777;
  690 +}
  691 +.ql-bubble .ql-picker.ql-expanded .ql-picker-options {
  692 + display: block;
  693 + margin-top: -1px;
  694 + top: 100%;
  695 + z-index: 1;
  696 +}
  697 +.ql-bubble .ql-color-picker,
  698 +.ql-bubble .ql-icon-picker {
  699 + width: 28px;
  700 +}
  701 +.ql-bubble .ql-color-picker .ql-picker-label,
  702 +.ql-bubble .ql-icon-picker .ql-picker-label {
  703 + padding: 2px 4px;
  704 +}
  705 +.ql-bubble .ql-color-picker .ql-picker-label svg,
  706 +.ql-bubble .ql-icon-picker .ql-picker-label svg {
  707 + right: 4px;
  708 +}
  709 +.ql-bubble .ql-icon-picker .ql-picker-options {
  710 + padding: 4px 0px;
  711 +}
  712 +.ql-bubble .ql-icon-picker .ql-picker-item {
  713 + height: 24px;
  714 + width: 24px;
  715 + padding: 2px 4px;
  716 +}
  717 +.ql-bubble .ql-color-picker .ql-picker-options {
  718 + padding: 3px 5px;
  719 + width: 152px;
  720 +}
  721 +.ql-bubble .ql-color-picker .ql-picker-item {
  722 + border: 1px solid transparent;
  723 + float: left;
  724 + height: 16px;
  725 + margin: 2px;
  726 + padding: 0px;
  727 + width: 16px;
  728 +}
  729 +.ql-bubble .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg {
  730 + position: absolute;
  731 + margin-top: -9px;
  732 + right: 0;
  733 + top: 50%;
  734 + width: 18px;
  735 +}
  736 +.ql-bubble .ql-picker.ql-header .ql-picker-label[data-label]:not([data-label=''])::before,
  737 +.ql-bubble .ql-picker.ql-font .ql-picker-label[data-label]:not([data-label=''])::before,
  738 +.ql-bubble .ql-picker.ql-size .ql-picker-label[data-label]:not([data-label=''])::before,
  739 +.ql-bubble .ql-picker.ql-header .ql-picker-item[data-label]:not([data-label=''])::before,
  740 +.ql-bubble .ql-picker.ql-font .ql-picker-item[data-label]:not([data-label=''])::before,
  741 +.ql-bubble .ql-picker.ql-size .ql-picker-item[data-label]:not([data-label=''])::before {
  742 + content: attr(data-label);
  743 +}
  744 +.ql-bubble .ql-picker.ql-header {
  745 + width: 98px;
  746 +}
  747 +.ql-bubble .ql-picker.ql-header .ql-picker-label::before,
  748 +.ql-bubble .ql-picker.ql-header .ql-picker-item::before {
  749 + content: 'Normal';
  750 +}
  751 +.ql-bubble .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
  752 +.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
  753 + content: 'Heading 1';
  754 +}
  755 +.ql-bubble .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
  756 +.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
  757 + content: 'Heading 2';
  758 +}
  759 +.ql-bubble .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
  760 +.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
  761 + content: 'Heading 3';
  762 +}
  763 +.ql-bubble .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
  764 +.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
  765 + content: 'Heading 4';
  766 +}
  767 +.ql-bubble .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
  768 +.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
  769 + content: 'Heading 5';
  770 +}
  771 +.ql-bubble .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
  772 +.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
  773 + content: 'Heading 6';
  774 +}
  775 +.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
  776 + font-size: 2em;
  777 +}
  778 +.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
  779 + font-size: 1.5em;
  780 +}
  781 +.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
  782 + font-size: 1.17em;
  783 +}
  784 +.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
  785 + font-size: 1em;
  786 +}
  787 +.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
  788 + font-size: 0.83em;
  789 +}
  790 +.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
  791 + font-size: 0.67em;
  792 +}
  793 +.ql-bubble .ql-picker.ql-font {
  794 + width: 108px;
  795 +}
  796 +.ql-bubble .ql-picker.ql-font .ql-picker-label::before,
  797 +.ql-bubble .ql-picker.ql-font .ql-picker-item::before {
  798 + content: 'Sans Serif';
  799 +}
  800 +.ql-bubble .ql-picker.ql-font .ql-picker-label[data-value=serif]::before,
  801 +.ql-bubble .ql-picker.ql-font .ql-picker-item[data-value=serif]::before {
  802 + content: 'Serif';
  803 +}
  804 +.ql-bubble .ql-picker.ql-font .ql-picker-label[data-value=monospace]::before,
  805 +.ql-bubble .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before {
  806 + content: 'Monospace';
  807 +}
  808 +.ql-bubble .ql-picker.ql-font .ql-picker-item[data-value=serif]::before {
  809 + font-family: Georgia, Times New Roman, serif;
  810 +}
  811 +.ql-bubble .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before {
  812 + font-family: Monaco, Courier New, monospace;
  813 +}
  814 +.ql-bubble .ql-picker.ql-size {
  815 + width: 98px;
  816 +}
  817 +.ql-bubble .ql-picker.ql-size .ql-picker-label::before,
  818 +.ql-bubble .ql-picker.ql-size .ql-picker-item::before {
  819 + content: 'Normal';
  820 +}
  821 +.ql-bubble .ql-picker.ql-size .ql-picker-label[data-value=small]::before,
  822 +.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=small]::before {
  823 + content: 'Small';
  824 +}
  825 +.ql-bubble .ql-picker.ql-size .ql-picker-label[data-value=large]::before,
  826 +.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=large]::before {
  827 + content: 'Large';
  828 +}
  829 +.ql-bubble .ql-picker.ql-size .ql-picker-label[data-value=huge]::before,
  830 +.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=huge]::before {
  831 + content: 'Huge';
  832 +}
  833 +.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=small]::before {
  834 + font-size: 10px;
  835 +}
  836 +.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=large]::before {
  837 + font-size: 18px;
  838 +}
  839 +.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=huge]::before {
  840 + font-size: 32px;
  841 +}
  842 +.ql-bubble .ql-color-picker.ql-background .ql-picker-item {
  843 + background-color: #fff;
  844 +}
  845 +.ql-bubble .ql-color-picker.ql-color .ql-picker-item {
  846 + background-color: #000;
  847 +}
  848 +.ql-bubble .ql-toolbar .ql-formats {
  849 + margin: 8px 12px 8px 0px;
  850 +}
  851 +.ql-bubble .ql-toolbar .ql-formats:first-child {
  852 + margin-left: 12px;
  853 +}
  854 +.ql-bubble .ql-color-picker svg {
  855 + margin: 1px;
  856 +}
  857 +.ql-bubble .ql-color-picker .ql-picker-item.ql-selected,
  858 +.ql-bubble .ql-color-picker .ql-picker-item:hover {
  859 + border-color: #fff;
  860 +}
  861 +.ql-bubble .ql-tooltip {
  862 + background-color: #444;
  863 + border-radius: 25px;
  864 + color: #fff;
  865 +}
  866 +.ql-bubble .ql-tooltip-arrow {
  867 + border-left: 6px solid transparent;
  868 + border-right: 6px solid transparent;
  869 + content: " ";
  870 + display: block;
  871 + left: 50%;
  872 + margin-left: -6px;
  873 + position: absolute;
  874 +}
  875 +.ql-bubble .ql-tooltip:not(.ql-flip) .ql-tooltip-arrow {
  876 + border-bottom: 6px solid #444;
  877 + top: -6px;
  878 +}
  879 +.ql-bubble .ql-tooltip.ql-flip .ql-tooltip-arrow {
  880 + border-top: 6px solid #444;
  881 + bottom: -6px;
  882 +}
  883 +.ql-bubble .ql-tooltip.ql-editing .ql-tooltip-editor {
  884 + display: block;
  885 +}
  886 +.ql-bubble .ql-tooltip.ql-editing .ql-formats {
  887 + visibility: hidden;
  888 +}
  889 +.ql-bubble .ql-tooltip-editor {
  890 + display: none;
  891 +}
  892 +.ql-bubble .ql-tooltip-editor input[type=text] {
  893 + background: transparent;
  894 + border: none;
  895 + color: #fff;
  896 + font-size: 13px;
  897 + height: 100%;
  898 + outline: none;
  899 + padding: 10px 20px;
  900 + position: absolute;
  901 + width: 100%;
  902 +}
  903 +.ql-bubble .ql-tooltip-editor a {
  904 + top: 10px;
  905 + position: absolute;
  906 + right: 20px;
  907 +}
  908 +.ql-bubble .ql-tooltip-editor a:before {
  909 + color: #ccc;
  910 + content: "\D7";
  911 + font-size: 16px;
  912 + font-weight: bold;
  913 +}
  914 +.ql-container.ql-bubble:not(.ql-disabled) a {
  915 + position: relative;
  916 + white-space: nowrap;
  917 +}
  918 +.ql-container.ql-bubble:not(.ql-disabled) a::before {
  919 + background-color: #444;
  920 + border-radius: 15px;
  921 + top: -5px;
  922 + font-size: 12px;
  923 + color: #fff;
  924 + content: attr(href);
  925 + font-weight: normal;
  926 + overflow: hidden;
  927 + padding: 5px 15px;
  928 + text-decoration: none;
  929 + z-index: 1;
  930 +}
  931 +.ql-container.ql-bubble:not(.ql-disabled) a::after {
  932 + border-top: 6px solid #444;
  933 + border-left: 6px solid transparent;
  934 + border-right: 6px solid transparent;
  935 + top: 0;
  936 + content: " ";
  937 + height: 0;
  938 + width: 0;
  939 +}
  940 +.ql-container.ql-bubble:not(.ql-disabled) a::before,
  941 +.ql-container.ql-bubble:not(.ql-disabled) a::after {
  942 + left: 0;
  943 + margin-left: 50%;
  944 + position: absolute;
  945 + transform: translate(-50%, -100%);
  946 + transition: visibility 0s ease 200ms;
  947 + visibility: hidden;
  948 +}
  949 +.ql-container.ql-bubble:not(.ql-disabled) a:hover::before,
  950 +.ql-container.ql-bubble:not(.ql-disabled) a:hover::after {
  951 + visibility: visible;
  952 +}
... ...
  1 +/*!
  2 + * Quill Editor v1.3.7
  3 + * https://quilljs.com/
  4 + * Copyright (c) 2014, Jason Chen
  5 + * Copyright (c) 2013, salesforce.com
  6 + */
  7 +.ql-container {
  8 + box-sizing: border-box;
  9 + font-family: Helvetica, Arial, sans-serif;
  10 + font-size: 13px;
  11 + height: 100%;
  12 + margin: 0px;
  13 + position: relative;
  14 +}
  15 +.ql-container.ql-disabled .ql-tooltip {
  16 + visibility: hidden;
  17 +}
  18 +.ql-container.ql-disabled .ql-editor ul[data-checked] > li::before {
  19 + pointer-events: none;
  20 +}
  21 +.ql-clipboard {
  22 + left: -100000px;
  23 + height: 1px;
  24 + overflow-y: hidden;
  25 + position: absolute;
  26 + top: 50%;
  27 +}
  28 +.ql-clipboard p {
  29 + margin: 0;
  30 + padding: 0;
  31 +}
  32 +.ql-editor {
  33 + box-sizing: border-box;
  34 + line-height: 1.42;
  35 + height: 100%;
  36 + outline: none;
  37 + overflow-y: auto;
  38 + padding: 12px 15px;
  39 + tab-size: 4;
  40 + -moz-tab-size: 4;
  41 + text-align: left;
  42 + white-space: pre-wrap;
  43 + word-wrap: break-word;
  44 +}
  45 +.ql-editor > * {
  46 + cursor: text;
  47 +}
  48 +.ql-editor p,
  49 +.ql-editor ol,
  50 +.ql-editor ul,
  51 +.ql-editor pre,
  52 +.ql-editor blockquote,
  53 +.ql-editor h1,
  54 +.ql-editor h2,
  55 +.ql-editor h3,
  56 +.ql-editor h4,
  57 +.ql-editor h5,
  58 +.ql-editor h6 {
  59 + margin: 0;
  60 + padding: 0;
  61 + counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
  62 +}
  63 +.ql-editor ol,
  64 +.ql-editor ul {
  65 + padding-left: 1.5em;
  66 +}
  67 +.ql-editor ol > li,
  68 +.ql-editor ul > li {
  69 + list-style-type: none;
  70 +}
  71 +.ql-editor ul > li::before {
  72 + content: '\2022';
  73 +}
  74 +.ql-editor ul[data-checked=true],
  75 +.ql-editor ul[data-checked=false] {
  76 + pointer-events: none;
  77 +}
  78 +.ql-editor ul[data-checked=true] > li *,
  79 +.ql-editor ul[data-checked=false] > li * {
  80 + pointer-events: all;
  81 +}
  82 +.ql-editor ul[data-checked=true] > li::before,
  83 +.ql-editor ul[data-checked=false] > li::before {
  84 + color: #777;
  85 + cursor: pointer;
  86 + pointer-events: all;
  87 +}
  88 +.ql-editor ul[data-checked=true] > li::before {
  89 + content: '\2611';
  90 +}
  91 +.ql-editor ul[data-checked=false] > li::before {
  92 + content: '\2610';
  93 +}
  94 +.ql-editor li::before {
  95 + display: inline-block;
  96 + white-space: nowrap;
  97 + width: 1.2em;
  98 +}
  99 +.ql-editor li:not(.ql-direction-rtl)::before {
  100 + margin-left: -1.5em;
  101 + margin-right: 0.3em;
  102 + text-align: right;
  103 +}
  104 +.ql-editor li.ql-direction-rtl::before {
  105 + margin-left: 0.3em;
  106 + margin-right: -1.5em;
  107 +}
  108 +.ql-editor ol li:not(.ql-direction-rtl),
  109 +.ql-editor ul li:not(.ql-direction-rtl) {
  110 + padding-left: 1.5em;
  111 +}
  112 +.ql-editor ol li.ql-direction-rtl,
  113 +.ql-editor ul li.ql-direction-rtl {
  114 + padding-right: 1.5em;
  115 +}
  116 +.ql-editor ol li {
  117 + counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
  118 + counter-increment: list-0;
  119 +}
  120 +.ql-editor ol li:before {
  121 + content: counter(list-0, decimal) '. ';
  122 +}
  123 +.ql-editor ol li.ql-indent-1 {
  124 + counter-increment: list-1;
  125 +}
  126 +.ql-editor ol li.ql-indent-1:before {
  127 + content: counter(list-1, lower-alpha) '. ';
  128 +}
  129 +.ql-editor ol li.ql-indent-1 {
  130 + counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
  131 +}
  132 +.ql-editor ol li.ql-indent-2 {
  133 + counter-increment: list-2;
  134 +}
  135 +.ql-editor ol li.ql-indent-2:before {
  136 + content: counter(list-2, lower-roman) '. ';
  137 +}
  138 +.ql-editor ol li.ql-indent-2 {
  139 + counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9;
  140 +}
  141 +.ql-editor ol li.ql-indent-3 {
  142 + counter-increment: list-3;
  143 +}
  144 +.ql-editor ol li.ql-indent-3:before {
  145 + content: counter(list-3, decimal) '. ';
  146 +}
  147 +.ql-editor ol li.ql-indent-3 {
  148 + counter-reset: list-4 list-5 list-6 list-7 list-8 list-9;
  149 +}
  150 +.ql-editor ol li.ql-indent-4 {
  151 + counter-increment: list-4;
  152 +}
  153 +.ql-editor ol li.ql-indent-4:before {
  154 + content: counter(list-4, lower-alpha) '. ';
  155 +}
  156 +.ql-editor ol li.ql-indent-4 {
  157 + counter-reset: list-5 list-6 list-7 list-8 list-9;
  158 +}
  159 +.ql-editor ol li.ql-indent-5 {
  160 + counter-increment: list-5;
  161 +}
  162 +.ql-editor ol li.ql-indent-5:before {
  163 + content: counter(list-5, lower-roman) '. ';
  164 +}
  165 +.ql-editor ol li.ql-indent-5 {
  166 + counter-reset: list-6 list-7 list-8 list-9;
  167 +}
  168 +.ql-editor ol li.ql-indent-6 {
  169 + counter-increment: list-6;
  170 +}
  171 +.ql-editor ol li.ql-indent-6:before {
  172 + content: counter(list-6, decimal) '. ';
  173 +}
  174 +.ql-editor ol li.ql-indent-6 {
  175 + counter-reset: list-7 list-8 list-9;
  176 +}
  177 +.ql-editor ol li.ql-indent-7 {
  178 + counter-increment: list-7;
  179 +}
  180 +.ql-editor ol li.ql-indent-7:before {
  181 + content: counter(list-7, lower-alpha) '. ';
  182 +}
  183 +.ql-editor ol li.ql-indent-7 {
  184 + counter-reset: list-8 list-9;
  185 +}
  186 +.ql-editor ol li.ql-indent-8 {
  187 + counter-increment: list-8;
  188 +}
  189 +.ql-editor ol li.ql-indent-8:before {
  190 + content: counter(list-8, lower-roman) '. ';
  191 +}
  192 +.ql-editor ol li.ql-indent-8 {
  193 + counter-reset: list-9;
  194 +}
  195 +.ql-editor ol li.ql-indent-9 {
  196 + counter-increment: list-9;
  197 +}
  198 +.ql-editor ol li.ql-indent-9:before {
  199 + content: counter(list-9, decimal) '. ';
  200 +}
  201 +.ql-editor .ql-indent-1:not(.ql-direction-rtl) {
  202 + padding-left: 3em;
  203 +}
  204 +.ql-editor li.ql-indent-1:not(.ql-direction-rtl) {
  205 + padding-left: 4.5em;
  206 +}
  207 +.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right {
  208 + padding-right: 3em;
  209 +}
  210 +.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right {
  211 + padding-right: 4.5em;
  212 +}
  213 +.ql-editor .ql-indent-2:not(.ql-direction-rtl) {
  214 + padding-left: 6em;
  215 +}
  216 +.ql-editor li.ql-indent-2:not(.ql-direction-rtl) {
  217 + padding-left: 7.5em;
  218 +}
  219 +.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right {
  220 + padding-right: 6em;
  221 +}
  222 +.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right {
  223 + padding-right: 7.5em;
  224 +}
  225 +.ql-editor .ql-indent-3:not(.ql-direction-rtl) {
  226 + padding-left: 9em;
  227 +}
  228 +.ql-editor li.ql-indent-3:not(.ql-direction-rtl) {
  229 + padding-left: 10.5em;
  230 +}
  231 +.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right {
  232 + padding-right: 9em;
  233 +}
  234 +.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right {
  235 + padding-right: 10.5em;
  236 +}
  237 +.ql-editor .ql-indent-4:not(.ql-direction-rtl) {
  238 + padding-left: 12em;
  239 +}
  240 +.ql-editor li.ql-indent-4:not(.ql-direction-rtl) {
  241 + padding-left: 13.5em;
  242 +}
  243 +.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right {
  244 + padding-right: 12em;
  245 +}
  246 +.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right {
  247 + padding-right: 13.5em;
  248 +}
  249 +.ql-editor .ql-indent-5:not(.ql-direction-rtl) {
  250 + padding-left: 15em;
  251 +}
  252 +.ql-editor li.ql-indent-5:not(.ql-direction-rtl) {
  253 + padding-left: 16.5em;
  254 +}
  255 +.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right {
  256 + padding-right: 15em;
  257 +}
  258 +.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right {
  259 + padding-right: 16.5em;
  260 +}
  261 +.ql-editor .ql-indent-6:not(.ql-direction-rtl) {
  262 + padding-left: 18em;
  263 +}
  264 +.ql-editor li.ql-indent-6:not(.ql-direction-rtl) {
  265 + padding-left: 19.5em;
  266 +}
  267 +.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right {
  268 + padding-right: 18em;
  269 +}
  270 +.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right {
  271 + padding-right: 19.5em;
  272 +}
  273 +.ql-editor .ql-indent-7:not(.ql-direction-rtl) {
  274 + padding-left: 21em;
  275 +}
  276 +.ql-editor li.ql-indent-7:not(.ql-direction-rtl) {
  277 + padding-left: 22.5em;
  278 +}
  279 +.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right {
  280 + padding-right: 21em;
  281 +}
  282 +.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right {
  283 + padding-right: 22.5em;
  284 +}
  285 +.ql-editor .ql-indent-8:not(.ql-direction-rtl) {
  286 + padding-left: 24em;
  287 +}
  288 +.ql-editor li.ql-indent-8:not(.ql-direction-rtl) {
  289 + padding-left: 25.5em;
  290 +}
  291 +.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right {
  292 + padding-right: 24em;
  293 +}
  294 +.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right {
  295 + padding-right: 25.5em;
  296 +}
  297 +.ql-editor .ql-indent-9:not(.ql-direction-rtl) {
  298 + padding-left: 27em;
  299 +}
  300 +.ql-editor li.ql-indent-9:not(.ql-direction-rtl) {
  301 + padding-left: 28.5em;
  302 +}
  303 +.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right {
  304 + padding-right: 27em;
  305 +}
  306 +.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right {
  307 + padding-right: 28.5em;
  308 +}
  309 +.ql-editor .ql-video {
  310 + display: block;
  311 + max-width: 100%;
  312 +}
  313 +.ql-editor .ql-video.ql-align-center {
  314 + margin: 0 auto;
  315 +}
  316 +.ql-editor .ql-video.ql-align-right {
  317 + margin: 0 0 0 auto;
  318 +}
  319 +.ql-editor .ql-bg-black {
  320 + background-color: #000;
  321 +}
  322 +.ql-editor .ql-bg-red {
  323 + background-color: #e60000;
  324 +}
  325 +.ql-editor .ql-bg-orange {
  326 + background-color: #f90;
  327 +}
  328 +.ql-editor .ql-bg-yellow {
  329 + background-color: #ff0;
  330 +}
  331 +.ql-editor .ql-bg-green {
  332 + background-color: #008a00;
  333 +}
  334 +.ql-editor .ql-bg-blue {
  335 + background-color: #06c;
  336 +}
  337 +.ql-editor .ql-bg-purple {
  338 + background-color: #93f;
  339 +}
  340 +.ql-editor .ql-color-white {
  341 + color: #fff;
  342 +}
  343 +.ql-editor .ql-color-red {
  344 + color: #e60000;
  345 +}
  346 +.ql-editor .ql-color-orange {
  347 + color: #f90;
  348 +}
  349 +.ql-editor .ql-color-yellow {
  350 + color: #ff0;
  351 +}
  352 +.ql-editor .ql-color-green {
  353 + color: #008a00;
  354 +}
  355 +.ql-editor .ql-color-blue {
  356 + color: #06c;
  357 +}
  358 +.ql-editor .ql-color-purple {
  359 + color: #93f;
  360 +}
  361 +.ql-editor .ql-font-serif {
  362 + font-family: Georgia, Times New Roman, serif;
  363 +}
  364 +.ql-editor .ql-font-monospace {
  365 + font-family: Monaco, Courier New, monospace;
  366 +}
  367 +.ql-editor .ql-size-small {
  368 + font-size: 0.75em;
  369 +}
  370 +.ql-editor .ql-size-large {
  371 + font-size: 1.5em;
  372 +}
  373 +.ql-editor .ql-size-huge {
  374 + font-size: 2.5em;
  375 +}
  376 +.ql-editor .ql-direction-rtl {
  377 + direction: rtl;
  378 + text-align: inherit;
  379 +}
  380 +.ql-editor .ql-align-center {
  381 + text-align: center;
  382 +}
  383 +.ql-editor .ql-align-justify {
  384 + text-align: justify;
  385 +}
  386 +.ql-editor .ql-align-right {
  387 + text-align: right;
  388 +}
  389 +.ql-editor.ql-blank::before {
  390 + color: rgba(0,0,0,0.6);
  391 + content: attr(data-placeholder);
  392 + font-style: italic;
  393 + left: 15px;
  394 + pointer-events: none;
  395 + position: absolute;
  396 + right: 15px;
  397 +}
... ...
  1 +/*!
  2 + * Quill Editor v1.3.7
  3 + * https://quilljs.com/
  4 + * Copyright (c) 2014, Jason Chen
  5 + * Copyright (c) 2013, salesforce.com
  6 + */
  7 +.ql-container {
  8 + box-sizing: border-box;
  9 + font-family: Helvetica, Arial, sans-serif;
  10 + font-size: 13px;
  11 + height: 100%;
  12 + margin: 0px;
  13 + position: relative;
  14 +}
  15 +.ql-container.ql-disabled .ql-tooltip {
  16 + visibility: hidden;
  17 +}
  18 +.ql-container.ql-disabled .ql-editor ul[data-checked] > li::before {
  19 + pointer-events: none;
  20 +}
  21 +.ql-clipboard {
  22 + left: -100000px;
  23 + height: 1px;
  24 + overflow-y: hidden;
  25 + position: absolute;
  26 + top: 50%;
  27 +}
  28 +.ql-clipboard p {
  29 + margin: 0;
  30 + padding: 0;
  31 +}
  32 +.ql-editor {
  33 + box-sizing: border-box;
  34 + line-height: 1.42;
  35 + height: 100%;
  36 + outline: none;
  37 + overflow-y: auto;
  38 + padding: 12px 15px;
  39 + tab-size: 4;
  40 + -moz-tab-size: 4;
  41 + text-align: left;
  42 + white-space: pre-wrap;
  43 + word-wrap: break-word;
  44 +}
  45 +.ql-editor > * {
  46 + cursor: text;
  47 +}
  48 +.ql-editor p,
  49 +.ql-editor ol,
  50 +.ql-editor ul,
  51 +.ql-editor pre,
  52 +.ql-editor blockquote,
  53 +.ql-editor h1,
  54 +.ql-editor h2,
  55 +.ql-editor h3,
  56 +.ql-editor h4,
  57 +.ql-editor h5,
  58 +.ql-editor h6 {
  59 + margin: 0;
  60 + padding: 0;
  61 + counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
  62 +}
  63 +.ql-editor ol,
  64 +.ql-editor ul {
  65 + padding-left: 1.5em;
  66 +}
  67 +.ql-editor ol > li,
  68 +.ql-editor ul > li {
  69 + list-style-type: none;
  70 +}
  71 +.ql-editor ul > li::before {
  72 + content: '\2022';
  73 +}
  74 +.ql-editor ul[data-checked=true],
  75 +.ql-editor ul[data-checked=false] {
  76 + pointer-events: none;
  77 +}
  78 +.ql-editor ul[data-checked=true] > li *,
  79 +.ql-editor ul[data-checked=false] > li * {
  80 + pointer-events: all;
  81 +}
  82 +.ql-editor ul[data-checked=true] > li::before,
  83 +.ql-editor ul[data-checked=false] > li::before {
  84 + color: #777;
  85 + cursor: pointer;
  86 + pointer-events: all;
  87 +}
  88 +.ql-editor ul[data-checked=true] > li::before {
  89 + content: '\2611';
  90 +}
  91 +.ql-editor ul[data-checked=false] > li::before {
  92 + content: '\2610';
  93 +}
  94 +.ql-editor li::before {
  95 + display: inline-block;
  96 + white-space: nowrap;
  97 + width: 1.2em;
  98 +}
  99 +.ql-editor li:not(.ql-direction-rtl)::before {
  100 + margin-left: -1.5em;
  101 + margin-right: 0.3em;
  102 + text-align: right;
  103 +}
  104 +.ql-editor li.ql-direction-rtl::before {
  105 + margin-left: 0.3em;
  106 + margin-right: -1.5em;
  107 +}
  108 +.ql-editor ol li:not(.ql-direction-rtl),
  109 +.ql-editor ul li:not(.ql-direction-rtl) {
  110 + padding-left: 1.5em;
  111 +}
  112 +.ql-editor ol li.ql-direction-rtl,
  113 +.ql-editor ul li.ql-direction-rtl {
  114 + padding-right: 1.5em;
  115 +}
  116 +.ql-editor ol li {
  117 + counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
  118 + counter-increment: list-0;
  119 +}
  120 +.ql-editor ol li:before {
  121 + content: counter(list-0, decimal) '. ';
  122 +}
  123 +.ql-editor ol li.ql-indent-1 {
  124 + counter-increment: list-1;
  125 +}
  126 +.ql-editor ol li.ql-indent-1:before {
  127 + content: counter(list-1, lower-alpha) '. ';
  128 +}
  129 +.ql-editor ol li.ql-indent-1 {
  130 + counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
  131 +}
  132 +.ql-editor ol li.ql-indent-2 {
  133 + counter-increment: list-2;
  134 +}
  135 +.ql-editor ol li.ql-indent-2:before {
  136 + content: counter(list-2, lower-roman) '. ';
  137 +}
  138 +.ql-editor ol li.ql-indent-2 {
  139 + counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9;
  140 +}
  141 +.ql-editor ol li.ql-indent-3 {
  142 + counter-increment: list-3;
  143 +}
  144 +.ql-editor ol li.ql-indent-3:before {
  145 + content: counter(list-3, decimal) '. ';
  146 +}
  147 +.ql-editor ol li.ql-indent-3 {
  148 + counter-reset: list-4 list-5 list-6 list-7 list-8 list-9;
  149 +}
  150 +.ql-editor ol li.ql-indent-4 {
  151 + counter-increment: list-4;
  152 +}
  153 +.ql-editor ol li.ql-indent-4:before {
  154 + content: counter(list-4, lower-alpha) '. ';
  155 +}
  156 +.ql-editor ol li.ql-indent-4 {
  157 + counter-reset: list-5 list-6 list-7 list-8 list-9;
  158 +}
  159 +.ql-editor ol li.ql-indent-5 {
  160 + counter-increment: list-5;
  161 +}
  162 +.ql-editor ol li.ql-indent-5:before {
  163 + content: counter(list-5, lower-roman) '. ';
  164 +}
  165 +.ql-editor ol li.ql-indent-5 {
  166 + counter-reset: list-6 list-7 list-8 list-9;
  167 +}
  168 +.ql-editor ol li.ql-indent-6 {
  169 + counter-increment: list-6;
  170 +}
  171 +.ql-editor ol li.ql-indent-6:before {
  172 + content: counter(list-6, decimal) '. ';
  173 +}
  174 +.ql-editor ol li.ql-indent-6 {
  175 + counter-reset: list-7 list-8 list-9;
  176 +}
  177 +.ql-editor ol li.ql-indent-7 {
  178 + counter-increment: list-7;
  179 +}
  180 +.ql-editor ol li.ql-indent-7:before {
  181 + content: counter(list-7, lower-alpha) '. ';
  182 +}
  183 +.ql-editor ol li.ql-indent-7 {
  184 + counter-reset: list-8 list-9;
  185 +}
  186 +.ql-editor ol li.ql-indent-8 {
  187 + counter-increment: list-8;
  188 +}
  189 +.ql-editor ol li.ql-indent-8:before {
  190 + content: counter(list-8, lower-roman) '. ';
  191 +}
  192 +.ql-editor ol li.ql-indent-8 {
  193 + counter-reset: list-9;
  194 +}
  195 +.ql-editor ol li.ql-indent-9 {
  196 + counter-increment: list-9;
  197 +}
  198 +.ql-editor ol li.ql-indent-9:before {
  199 + content: counter(list-9, decimal) '. ';
  200 +}
  201 +.ql-editor .ql-indent-1:not(.ql-direction-rtl) {
  202 + padding-left: 3em;
  203 +}
  204 +.ql-editor li.ql-indent-1:not(.ql-direction-rtl) {
  205 + padding-left: 4.5em;
  206 +}
  207 +.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right {
  208 + padding-right: 3em;
  209 +}
  210 +.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right {
  211 + padding-right: 4.5em;
  212 +}
  213 +.ql-editor .ql-indent-2:not(.ql-direction-rtl) {
  214 + padding-left: 6em;
  215 +}
  216 +.ql-editor li.ql-indent-2:not(.ql-direction-rtl) {
  217 + padding-left: 7.5em;
  218 +}
  219 +.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right {
  220 + padding-right: 6em;
  221 +}
  222 +.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right {
  223 + padding-right: 7.5em;
  224 +}
  225 +.ql-editor .ql-indent-3:not(.ql-direction-rtl) {
  226 + padding-left: 9em;
  227 +}
  228 +.ql-editor li.ql-indent-3:not(.ql-direction-rtl) {
  229 + padding-left: 10.5em;
  230 +}
  231 +.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right {
  232 + padding-right: 9em;
  233 +}
  234 +.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right {
  235 + padding-right: 10.5em;
  236 +}
  237 +.ql-editor .ql-indent-4:not(.ql-direction-rtl) {
  238 + padding-left: 12em;
  239 +}
  240 +.ql-editor li.ql-indent-4:not(.ql-direction-rtl) {
  241 + padding-left: 13.5em;
  242 +}
  243 +.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right {
  244 + padding-right: 12em;
  245 +}
  246 +.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right {
  247 + padding-right: 13.5em;
  248 +}
  249 +.ql-editor .ql-indent-5:not(.ql-direction-rtl) {
  250 + padding-left: 15em;
  251 +}
  252 +.ql-editor li.ql-indent-5:not(.ql-direction-rtl) {
  253 + padding-left: 16.5em;
  254 +}
  255 +.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right {
  256 + padding-right: 15em;
  257 +}
  258 +.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right {
  259 + padding-right: 16.5em;
  260 +}
  261 +.ql-editor .ql-indent-6:not(.ql-direction-rtl) {
  262 + padding-left: 18em;
  263 +}
  264 +.ql-editor li.ql-indent-6:not(.ql-direction-rtl) {
  265 + padding-left: 19.5em;
  266 +}
  267 +.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right {
  268 + padding-right: 18em;
  269 +}
  270 +.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right {
  271 + padding-right: 19.5em;
  272 +}
  273 +.ql-editor .ql-indent-7:not(.ql-direction-rtl) {
  274 + padding-left: 21em;
  275 +}
  276 +.ql-editor li.ql-indent-7:not(.ql-direction-rtl) {
  277 + padding-left: 22.5em;
  278 +}
  279 +.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right {
  280 + padding-right: 21em;
  281 +}
  282 +.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right {
  283 + padding-right: 22.5em;
  284 +}
  285 +.ql-editor .ql-indent-8:not(.ql-direction-rtl) {
  286 + padding-left: 24em;
  287 +}
  288 +.ql-editor li.ql-indent-8:not(.ql-direction-rtl) {
  289 + padding-left: 25.5em;
  290 +}
  291 +.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right {
  292 + padding-right: 24em;
  293 +}
  294 +.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right {
  295 + padding-right: 25.5em;
  296 +}
  297 +.ql-editor .ql-indent-9:not(.ql-direction-rtl) {
  298 + padding-left: 27em;
  299 +}
  300 +.ql-editor li.ql-indent-9:not(.ql-direction-rtl) {
  301 + padding-left: 28.5em;
  302 +}
  303 +.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right {
  304 + padding-right: 27em;
  305 +}
  306 +.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right {
  307 + padding-right: 28.5em;
  308 +}
  309 +.ql-editor .ql-video {
  310 + display: block;
  311 + max-width: 100%;
  312 +}
  313 +.ql-editor .ql-video.ql-align-center {
  314 + margin: 0 auto;
  315 +}
  316 +.ql-editor .ql-video.ql-align-right {
  317 + margin: 0 0 0 auto;
  318 +}
  319 +.ql-editor .ql-bg-black {
  320 + background-color: #000;
  321 +}
  322 +.ql-editor .ql-bg-red {
  323 + background-color: #e60000;
  324 +}
  325 +.ql-editor .ql-bg-orange {
  326 + background-color: #f90;
  327 +}
  328 +.ql-editor .ql-bg-yellow {
  329 + background-color: #ff0;
  330 +}
  331 +.ql-editor .ql-bg-green {
  332 + background-color: #008a00;
  333 +}
  334 +.ql-editor .ql-bg-blue {
  335 + background-color: #06c;
  336 +}
  337 +.ql-editor .ql-bg-purple {
  338 + background-color: #93f;
  339 +}
  340 +.ql-editor .ql-color-white {
  341 + color: #fff;
  342 +}
  343 +.ql-editor .ql-color-red {
  344 + color: #e60000;
  345 +}
  346 +.ql-editor .ql-color-orange {
  347 + color: #f90;
  348 +}
  349 +.ql-editor .ql-color-yellow {
  350 + color: #ff0;
  351 +}
  352 +.ql-editor .ql-color-green {
  353 + color: #008a00;
  354 +}
  355 +.ql-editor .ql-color-blue {
  356 + color: #06c;
  357 +}
  358 +.ql-editor .ql-color-purple {
  359 + color: #93f;
  360 +}
  361 +.ql-editor .ql-font-serif {
  362 + font-family: Georgia, Times New Roman, serif;
  363 +}
  364 +.ql-editor .ql-font-monospace {
  365 + font-family: Monaco, Courier New, monospace;
  366 +}
  367 +.ql-editor .ql-size-small {
  368 + font-size: 0.75em;
  369 +}
  370 +.ql-editor .ql-size-large {
  371 + font-size: 1.5em;
  372 +}
  373 +.ql-editor .ql-size-huge {
  374 + font-size: 2.5em;
  375 +}
  376 +.ql-editor .ql-direction-rtl {
  377 + direction: rtl;
  378 + text-align: inherit;
  379 +}
  380 +.ql-editor .ql-align-center {
  381 + text-align: center;
  382 +}
  383 +.ql-editor .ql-align-justify {
  384 + text-align: justify;
  385 +}
  386 +.ql-editor .ql-align-right {
  387 + text-align: right;
  388 +}
  389 +.ql-editor.ql-blank::before {
  390 + color: rgba(0,0,0,0.6);
  391 + content: attr(data-placeholder);
  392 + font-style: italic;
  393 + left: 15px;
  394 + pointer-events: none;
  395 + position: absolute;
  396 + right: 15px;
  397 +}
  398 +.ql-snow.ql-toolbar:after,
  399 +.ql-snow .ql-toolbar:after {
  400 + clear: both;
  401 + content: '';
  402 + display: table;
  403 +}
  404 +.ql-snow.ql-toolbar button,
  405 +.ql-snow .ql-toolbar button {
  406 + background: none;
  407 + border: none;
  408 + cursor: pointer;
  409 + display: inline-block;
  410 + float: left;
  411 + height: 24px;
  412 + padding: 3px 5px;
  413 + width: 28px;
  414 +}
  415 +.ql-snow.ql-toolbar button svg,
  416 +.ql-snow .ql-toolbar button svg {
  417 + float: left;
  418 + height: 100%;
  419 +}
  420 +.ql-snow.ql-toolbar button:active:hover,
  421 +.ql-snow .ql-toolbar button:active:hover {
  422 + outline: none;
  423 +}
  424 +.ql-snow.ql-toolbar input.ql-image[type=file],
  425 +.ql-snow .ql-toolbar input.ql-image[type=file] {
  426 + display: none;
  427 +}
  428 +.ql-snow.ql-toolbar button:hover,
  429 +.ql-snow .ql-toolbar button:hover,
  430 +.ql-snow.ql-toolbar button:focus,
  431 +.ql-snow .ql-toolbar button:focus,
  432 +.ql-snow.ql-toolbar button.ql-active,
  433 +.ql-snow .ql-toolbar button.ql-active,
  434 +.ql-snow.ql-toolbar .ql-picker-label:hover,
  435 +.ql-snow .ql-toolbar .ql-picker-label:hover,
  436 +.ql-snow.ql-toolbar .ql-picker-label.ql-active,
  437 +.ql-snow .ql-toolbar .ql-picker-label.ql-active,
  438 +.ql-snow.ql-toolbar .ql-picker-item:hover,
  439 +.ql-snow .ql-toolbar .ql-picker-item:hover,
  440 +.ql-snow.ql-toolbar .ql-picker-item.ql-selected,
  441 +.ql-snow .ql-toolbar .ql-picker-item.ql-selected {
  442 + color: #06c;
  443 +}
  444 +.ql-snow.ql-toolbar button:hover .ql-fill,
  445 +.ql-snow .ql-toolbar button:hover .ql-fill,
  446 +.ql-snow.ql-toolbar button:focus .ql-fill,
  447 +.ql-snow .ql-toolbar button:focus .ql-fill,
  448 +.ql-snow.ql-toolbar button.ql-active .ql-fill,
  449 +.ql-snow .ql-toolbar button.ql-active .ql-fill,
  450 +.ql-snow.ql-toolbar .ql-picker-label:hover .ql-fill,
  451 +.ql-snow .ql-toolbar .ql-picker-label:hover .ql-fill,
  452 +.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-fill,
  453 +.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-fill,
  454 +.ql-snow.ql-toolbar .ql-picker-item:hover .ql-fill,
  455 +.ql-snow .ql-toolbar .ql-picker-item:hover .ql-fill,
  456 +.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-fill,
  457 +.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-fill,
  458 +.ql-snow.ql-toolbar button:hover .ql-stroke.ql-fill,
  459 +.ql-snow .ql-toolbar button:hover .ql-stroke.ql-fill,
  460 +.ql-snow.ql-toolbar button:focus .ql-stroke.ql-fill,
  461 +.ql-snow .ql-toolbar button:focus .ql-stroke.ql-fill,
  462 +.ql-snow.ql-toolbar button.ql-active .ql-stroke.ql-fill,
  463 +.ql-snow .ql-toolbar button.ql-active .ql-stroke.ql-fill,
  464 +.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,
  465 +.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,
  466 +.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,
  467 +.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,
  468 +.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,
  469 +.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,
  470 +.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill,
  471 +.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill {
  472 + fill: #06c;
  473 +}
  474 +.ql-snow.ql-toolbar button:hover .ql-stroke,
  475 +.ql-snow .ql-toolbar button:hover .ql-stroke,
  476 +.ql-snow.ql-toolbar button:focus .ql-stroke,
  477 +.ql-snow .ql-toolbar button:focus .ql-stroke,
  478 +.ql-snow.ql-toolbar button.ql-active .ql-stroke,
  479 +.ql-snow .ql-toolbar button.ql-active .ql-stroke,
  480 +.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke,
  481 +.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke,
  482 +.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke,
  483 +.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke,
  484 +.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke,
  485 +.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke,
  486 +.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke,
  487 +.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke,
  488 +.ql-snow.ql-toolbar button:hover .ql-stroke-miter,
  489 +.ql-snow .ql-toolbar button:hover .ql-stroke-miter,
  490 +.ql-snow.ql-toolbar button:focus .ql-stroke-miter,
  491 +.ql-snow .ql-toolbar button:focus .ql-stroke-miter,
  492 +.ql-snow.ql-toolbar button.ql-active .ql-stroke-miter,
  493 +.ql-snow .ql-toolbar button.ql-active .ql-stroke-miter,
  494 +.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke-miter,
  495 +.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke-miter,
  496 +.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,
  497 +.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,
  498 +.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke-miter,
  499 +.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke-miter,
  500 +.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter,
  501 +.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter {
  502 + stroke: #06c;
  503 +}
  504 +@media (pointer: coarse) {
  505 + .ql-snow.ql-toolbar button:hover:not(.ql-active),
  506 + .ql-snow .ql-toolbar button:hover:not(.ql-active) {
  507 + color: #444;
  508 + }
  509 + .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-fill,
  510 + .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-fill,
  511 + .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill,
  512 + .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill {
  513 + fill: #444;
  514 + }
  515 + .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke,
  516 + .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke,
  517 + .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter,
  518 + .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter {
  519 + stroke: #444;
  520 + }
  521 +}
  522 +.ql-snow {
  523 + box-sizing: border-box;
  524 +}
  525 +.ql-snow * {
  526 + box-sizing: border-box;
  527 +}
  528 +.ql-snow .ql-hidden {
  529 + display: none;
  530 +}
  531 +.ql-snow .ql-out-bottom,
  532 +.ql-snow .ql-out-top {
  533 + visibility: hidden;
  534 +}
  535 +.ql-snow .ql-tooltip {
  536 + position: absolute;
  537 + transform: translateY(10px);
  538 +}
  539 +.ql-snow .ql-tooltip a {
  540 + cursor: pointer;
  541 + text-decoration: none;
  542 +}
  543 +.ql-snow .ql-tooltip.ql-flip {
  544 + transform: translateY(-10px);
  545 +}
  546 +.ql-snow .ql-formats {
  547 + display: inline-block;
  548 + vertical-align: middle;
  549 +}
  550 +.ql-snow .ql-formats:after {
  551 + clear: both;
  552 + content: '';
  553 + display: table;
  554 +}
  555 +.ql-snow .ql-stroke {
  556 + fill: none;
  557 + stroke: #444;
  558 + stroke-linecap: round;
  559 + stroke-linejoin: round;
  560 + stroke-width: 2;
  561 +}
  562 +.ql-snow .ql-stroke-miter {
  563 + fill: none;
  564 + stroke: #444;
  565 + stroke-miterlimit: 10;
  566 + stroke-width: 2;
  567 +}
  568 +.ql-snow .ql-fill,
  569 +.ql-snow .ql-stroke.ql-fill {
  570 + fill: #444;
  571 +}
  572 +.ql-snow .ql-empty {
  573 + fill: none;
  574 +}
  575 +.ql-snow .ql-even {
  576 + fill-rule: evenodd;
  577 +}
  578 +.ql-snow .ql-thin,
  579 +.ql-snow .ql-stroke.ql-thin {
  580 + stroke-width: 1;
  581 +}
  582 +.ql-snow .ql-transparent {
  583 + opacity: 0.4;
  584 +}
  585 +.ql-snow .ql-direction svg:last-child {
  586 + display: none;
  587 +}
  588 +.ql-snow .ql-direction.ql-active svg:last-child {
  589 + display: inline;
  590 +}
  591 +.ql-snow .ql-direction.ql-active svg:first-child {
  592 + display: none;
  593 +}
  594 +.ql-snow .ql-editor h1 {
  595 + font-size: 2em;
  596 +}
  597 +.ql-snow .ql-editor h2 {
  598 + font-size: 1.5em;
  599 +}
  600 +.ql-snow .ql-editor h3 {
  601 + font-size: 1.17em;
  602 +}
  603 +.ql-snow .ql-editor h4 {
  604 + font-size: 1em;
  605 +}
  606 +.ql-snow .ql-editor h5 {
  607 + font-size: 0.83em;
  608 +}
  609 +.ql-snow .ql-editor h6 {
  610 + font-size: 0.67em;
  611 +}
  612 +.ql-snow .ql-editor a {
  613 + text-decoration: underline;
  614 +}
  615 +.ql-snow .ql-editor blockquote {
  616 + border-left: 4px solid #ccc;
  617 + margin-bottom: 5px;
  618 + margin-top: 5px;
  619 + padding-left: 16px;
  620 +}
  621 +.ql-snow .ql-editor code,
  622 +.ql-snow .ql-editor pre {
  623 + background-color: #f0f0f0;
  624 + border-radius: 3px;
  625 +}
  626 +.ql-snow .ql-editor pre {
  627 + white-space: pre-wrap;
  628 + margin-bottom: 5px;
  629 + margin-top: 5px;
  630 + padding: 5px 10px;
  631 +}
  632 +.ql-snow .ql-editor code {
  633 + font-size: 85%;
  634 + padding: 2px 4px;
  635 +}
  636 +.ql-snow .ql-editor pre.ql-syntax {
  637 + background-color: #23241f;
  638 + color: #f8f8f2;
  639 + overflow: visible;
  640 +}
  641 +.ql-snow .ql-editor img {
  642 + max-width: 100%;
  643 +}
  644 +.ql-snow .ql-picker {
  645 + color: #444;
  646 + display: inline-block;
  647 + float: left;
  648 + font-size: 14px;
  649 + font-weight: 500;
  650 + height: 24px;
  651 + position: relative;
  652 + vertical-align: middle;
  653 +}
  654 +.ql-snow .ql-picker-label {
  655 + cursor: pointer;
  656 + display: inline-block;
  657 + height: 100%;
  658 + padding-left: 8px;
  659 + padding-right: 2px;
  660 + position: relative;
  661 + width: 100%;
  662 +}
  663 +.ql-snow .ql-picker-label::before {
  664 + display: inline-block;
  665 + line-height: 22px;
  666 +}
  667 +.ql-snow .ql-picker-options {
  668 + background-color: #fff;
  669 + display: none;
  670 + min-width: 100%;
  671 + padding: 4px 8px;
  672 + position: absolute;
  673 + white-space: nowrap;
  674 +}
  675 +.ql-snow .ql-picker-options .ql-picker-item {
  676 + cursor: pointer;
  677 + display: block;
  678 + padding-bottom: 5px;
  679 + padding-top: 5px;
  680 +}
  681 +.ql-snow .ql-picker.ql-expanded .ql-picker-label {
  682 + color: #ccc;
  683 + z-index: 2;
  684 +}
  685 +.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-fill {
  686 + fill: #ccc;
  687 +}
  688 +.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-stroke {
  689 + stroke: #ccc;
  690 +}
  691 +.ql-snow .ql-picker.ql-expanded .ql-picker-options {
  692 + display: block;
  693 + margin-top: -1px;
  694 + top: 100%;
  695 + z-index: 1;
  696 +}
  697 +.ql-snow .ql-color-picker,
  698 +.ql-snow .ql-icon-picker {
  699 + width: 28px;
  700 +}
  701 +.ql-snow .ql-color-picker .ql-picker-label,
  702 +.ql-snow .ql-icon-picker .ql-picker-label {
  703 + padding: 2px 4px;
  704 +}
  705 +.ql-snow .ql-color-picker .ql-picker-label svg,
  706 +.ql-snow .ql-icon-picker .ql-picker-label svg {
  707 + right: 4px;
  708 +}
  709 +.ql-snow .ql-icon-picker .ql-picker-options {
  710 + padding: 4px 0px;
  711 +}
  712 +.ql-snow .ql-icon-picker .ql-picker-item {
  713 + height: 24px;
  714 + width: 24px;
  715 + padding: 2px 4px;
  716 +}
  717 +.ql-snow .ql-color-picker .ql-picker-options {
  718 + padding: 3px 5px;
  719 + width: 152px;
  720 +}
  721 +.ql-snow .ql-color-picker .ql-picker-item {
  722 + border: 1px solid transparent;
  723 + float: left;
  724 + height: 16px;
  725 + margin: 2px;
  726 + padding: 0px;
  727 + width: 16px;
  728 +}
  729 +.ql-snow .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg {
  730 + position: absolute;
  731 + margin-top: -9px;
  732 + right: 0;
  733 + top: 50%;
  734 + width: 18px;
  735 +}
  736 +.ql-snow .ql-picker.ql-header .ql-picker-label[data-label]:not([data-label=''])::before,
  737 +.ql-snow .ql-picker.ql-font .ql-picker-label[data-label]:not([data-label=''])::before,
  738 +.ql-snow .ql-picker.ql-size .ql-picker-label[data-label]:not([data-label=''])::before,
  739 +.ql-snow .ql-picker.ql-header .ql-picker-item[data-label]:not([data-label=''])::before,
  740 +.ql-snow .ql-picker.ql-font .ql-picker-item[data-label]:not([data-label=''])::before,
  741 +.ql-snow .ql-picker.ql-size .ql-picker-item[data-label]:not([data-label=''])::before {
  742 + content: attr(data-label);
  743 +}
  744 +.ql-snow .ql-picker.ql-header {
  745 + width: 98px;
  746 +}
  747 +.ql-snow .ql-picker.ql-header .ql-picker-label::before,
  748 +.ql-snow .ql-picker.ql-header .ql-picker-item::before {
  749 + content: 'Normal';
  750 +}
  751 +.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
  752 +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
  753 + content: 'Heading 1';
  754 +}
  755 +.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
  756 +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
  757 + content: 'Heading 2';
  758 +}
  759 +.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
  760 +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
  761 + content: 'Heading 3';
  762 +}
  763 +.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
  764 +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
  765 + content: 'Heading 4';
  766 +}
  767 +.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
  768 +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
  769 + content: 'Heading 5';
  770 +}
  771 +.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
  772 +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
  773 + content: 'Heading 6';
  774 +}
  775 +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
  776 + font-size: 2em;
  777 +}
  778 +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
  779 + font-size: 1.5em;
  780 +}
  781 +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
  782 + font-size: 1.17em;
  783 +}
  784 +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
  785 + font-size: 1em;
  786 +}
  787 +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
  788 + font-size: 0.83em;
  789 +}
  790 +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
  791 + font-size: 0.67em;
  792 +}
  793 +.ql-snow .ql-picker.ql-font {
  794 + width: 108px;
  795 +}
  796 +.ql-snow .ql-picker.ql-font .ql-picker-label::before,
  797 +.ql-snow .ql-picker.ql-font .ql-picker-item::before {
  798 + content: 'Sans Serif';
  799 +}
  800 +.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=serif]::before,
  801 +.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before {
  802 + content: 'Serif';
  803 +}
  804 +.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=monospace]::before,
  805 +.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before {
  806 + content: 'Monospace';
  807 +}
  808 +.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before {
  809 + font-family: Georgia, Times New Roman, serif;
  810 +}
  811 +.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before {
  812 + font-family: Monaco, Courier New, monospace;
  813 +}
  814 +.ql-snow .ql-picker.ql-size {
  815 + width: 98px;
  816 +}
  817 +.ql-snow .ql-picker.ql-size .ql-picker-label::before,
  818 +.ql-snow .ql-picker.ql-size .ql-picker-item::before {
  819 + content: 'Normal';
  820 +}
  821 +.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=small]::before,
  822 +.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before {
  823 + content: 'Small';
  824 +}
  825 +.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=large]::before,
  826 +.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before {
  827 + content: 'Large';
  828 +}
  829 +.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=huge]::before,
  830 +.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before {
  831 + content: 'Huge';
  832 +}
  833 +.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before {
  834 + font-size: 10px;
  835 +}
  836 +.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before {
  837 + font-size: 18px;
  838 +}
  839 +.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before {
  840 + font-size: 32px;
  841 +}
  842 +.ql-snow .ql-color-picker.ql-background .ql-picker-item {
  843 + background-color: #fff;
  844 +}
  845 +.ql-snow .ql-color-picker.ql-color .ql-picker-item {
  846 + background-color: #000;
  847 +}
  848 +.ql-toolbar.ql-snow {
  849 + border: 1px solid #ccc;
  850 + box-sizing: border-box;
  851 + font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;
  852 + padding: 8px;
  853 +}
  854 +.ql-toolbar.ql-snow .ql-formats {
  855 + margin-right: 15px;
  856 +}
  857 +.ql-toolbar.ql-snow .ql-picker-label {
  858 + border: 1px solid transparent;
  859 +}
  860 +.ql-toolbar.ql-snow .ql-picker-options {
  861 + border: 1px solid transparent;
  862 + box-shadow: rgba(0,0,0,0.2) 0 2px 8px;
  863 +}
  864 +.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-label {
  865 + border-color: #ccc;
  866 +}
  867 +.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-options {
  868 + border-color: #ccc;
  869 +}
  870 +.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item.ql-selected,
  871 +.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item:hover {
  872 + border-color: #000;
  873 +}
  874 +.ql-toolbar.ql-snow + .ql-container.ql-snow {
  875 + border-top: 0px;
  876 +}
  877 +.ql-snow .ql-tooltip {
  878 + background-color: #fff;
  879 + border: 1px solid #ccc;
  880 + box-shadow: 0px 0px 5px #ddd;
  881 + color: #444;
  882 + padding: 5px 12px;
  883 + white-space: nowrap;
  884 +}
  885 +.ql-snow .ql-tooltip::before {
  886 + content: "Visit URL:";
  887 + line-height: 26px;
  888 + margin-right: 8px;
  889 +}
  890 +.ql-snow .ql-tooltip input[type=text] {
  891 + display: none;
  892 + border: 1px solid #ccc;
  893 + font-size: 13px;
  894 + height: 26px;
  895 + margin: 0px;
  896 + padding: 3px 5px;
  897 + width: 170px;
  898 +}
  899 +.ql-snow .ql-tooltip a.ql-preview {
  900 + display: inline-block;
  901 + max-width: 200px;
  902 + overflow-x: hidden;
  903 + text-overflow: ellipsis;
  904 + vertical-align: top;
  905 +}
  906 +.ql-snow .ql-tooltip a.ql-action::after {
  907 + border-right: 1px solid #ccc;
  908 + content: 'Edit';
  909 + margin-left: 16px;
  910 + padding-right: 8px;
  911 +}
  912 +.ql-snow .ql-tooltip a.ql-remove::before {
  913 + content: 'Remove';
  914 + margin-left: 8px;
  915 +}
  916 +.ql-snow .ql-tooltip a {
  917 + line-height: 26px;
  918 +}
  919 +.ql-snow .ql-tooltip.ql-editing a.ql-preview,
  920 +.ql-snow .ql-tooltip.ql-editing a.ql-remove {
  921 + display: none;
  922 +}
  923 +.ql-snow .ql-tooltip.ql-editing input[type=text] {
  924 + display: inline-block;
  925 +}
  926 +.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
  927 + border-right: 0px;
  928 + content: 'Save';
  929 + padding-right: 0px;
  930 +}
  931 +.ql-snow .ql-tooltip[data-mode=link]::before {
  932 + content: "Enter link:";
  933 +}
  934 +.ql-snow .ql-tooltip[data-mode=formula]::before {
  935 + content: "Enter formula:";
  936 +}
  937 +.ql-snow .ql-tooltip[data-mode=video]::before {
  938 + content: "Enter video:";
  939 +}
  940 +.ql-snow a {
  941 + color: #06c;
  942 +}
  943 +.ql-container.ql-snow {
  944 + border: 1px solid #ccc;
  945 +}
... ...
  1 +package cn.com.nobook;
  2 +
  3 +public class FileChooser {
  4 +
  5 + static {
  6 + System.loadLibrary("serial_port");
  7 + }
  8 + public static native void open(String file);
  9 +
  10 + public static native void colse();
  11 +}
... ...
  1 +package com.studymachine.www.action;
  2 +
  3 +import android.content.Context;
  4 +import android.graphics.drawable.Drawable;
  5 +import android.net.ConnectivityManager;
  6 +import android.net.NetworkInfo;
  7 +
  8 +import androidx.annotation.DrawableRes;
  9 +import androidx.annotation.RawRes;
  10 +import androidx.annotation.StringRes;
  11 +import androidx.core.content.ContextCompat;
  12 +
  13 +import com.studymachine.www.R;
  14 +import com.studymachine.www.widget.StatusLayout;
  15 +
  16 +/**
  17 + * time : 2019/12/08
  18 + * desc : 状态布局意图
  19 + */
  20 +public interface StatusAction {
  21 +
  22 + /**
  23 + * 获取状态布局
  24 + */
  25 + StatusLayout getStatusLayout();
  26 +
  27 + /**
  28 + * 显示加载中
  29 + */
  30 + default void showLoading() {
  31 + showLoading(R.raw.loading);
  32 + }
  33 +
  34 + default void showLoading(@RawRes int id) {
  35 + StatusLayout layout = getStatusLayout();
  36 + layout.show();
  37 + layout.setAnimResource(id);
  38 + layout.setHint("");
  39 + layout.setOnRetryListener(null);
  40 + }
  41 +
  42 + /**
  43 + * 显示加载完成
  44 + */
  45 + default void showComplete() {
  46 + StatusLayout layout = getStatusLayout();
  47 + if (layout == null || !layout.isShow()) {
  48 + return;
  49 + }
  50 + layout.hide();
  51 + }
  52 +
  53 + /**
  54 + * 显示空提示
  55 + */
  56 + default void showEmpty() {
  57 + showLayout(R.drawable.common_status_empty, R.string.status_layout_no_data, null);
  58 + }
  59 +
  60 + /**
  61 + * 显示错误提示
  62 + */
  63 + default void showError(StatusLayout.OnRetryListener listener) {
  64 + StatusLayout layout = getStatusLayout();
  65 + Context context = layout.getContext();
  66 + ConnectivityManager manager = ContextCompat.getSystemService(context, ConnectivityManager.class);
  67 + if (manager != null) {
  68 + NetworkInfo info = manager.getActiveNetworkInfo();
  69 + // 判断网络是否连接
  70 + if (info == null || !info.isConnected()) {
  71 + showLayout(R.drawable.status_network_ic, R.string.status_layout_error_network, listener);
  72 + return;
  73 + }
  74 + }
  75 + showLayout(R.drawable.status_error_ic, R.string.status_layout_error_request, listener);
  76 + }
  77 +
  78 + /**
  79 + * 显示自定义提示
  80 + */
  81 + default void showLayout(@DrawableRes int drawableId, @StringRes int stringId, StatusLayout.OnRetryListener listener) {
  82 + StatusLayout layout = getStatusLayout();
  83 + Context context = layout.getContext();
  84 + showLayout(ContextCompat.getDrawable(context, drawableId), context.getString(stringId), listener);
  85 + }
  86 +
  87 + default void showLayout(Drawable drawable, CharSequence hint, StatusLayout.OnRetryListener listener) {
  88 + StatusLayout layout = getStatusLayout();
  89 + layout.show();
  90 + layout.setIcon(drawable);
  91 + layout.setHint(hint);
  92 + layout.setOnRetryListener(listener);
  93 + }
  94 +}
\ No newline at end of file
... ...
  1 +package com.studymachine.www.action;
  2 +
  3 +import android.graphics.drawable.Drawable;
  4 +import android.view.View;
  5 +import android.view.ViewGroup;
  6 +
  7 +import androidx.annotation.Nullable;
  8 +import androidx.annotation.StringRes;
  9 +
  10 +import com.hjq.bar.OnTitleBarListener;
  11 +import com.hjq.bar.TitleBar;
  12 +
  13 +/**
  14 + * time : 2019/12/08
  15 + * desc : 标题栏意图
  16 + */
  17 +public interface TitleBarAction extends OnTitleBarListener {
  18 +
  19 + @Nullable
  20 + TitleBar getTitleBar();
  21 +
  22 + /**
  23 + * 左项被点击
  24 + *
  25 + * @param view 被点击的左项View
  26 + */
  27 + @Override
  28 + default void onLeftClick(View view) {}
  29 +
  30 + /**
  31 + * 标题被点击
  32 + *
  33 + * @param view 被点击的标题View
  34 + */
  35 + @Override
  36 + default void onTitleClick(View view) {}
  37 +
  38 + /**
  39 + * 右项被点击
  40 + *
  41 + * @param view 被点击的右项View
  42 + */
  43 + @Override
  44 + default void onRightClick(View view) {}
  45 +
  46 + /**
  47 + * 设置标题栏的标题
  48 + */
  49 + default void setTitle(@StringRes int id) {
  50 + if (getTitleBar() != null) {
  51 + setTitle(getTitleBar().getResources().getString(id));
  52 + }
  53 + }
  54 +
  55 + /**
  56 + * 设置标题栏的标题
  57 + */
  58 + default void setTitle(CharSequence title) {
  59 + if (getTitleBar() != null) {
  60 + getTitleBar().setTitle(title);
  61 + }
  62 + }
  63 +
  64 + /**
  65 + * 设置标题栏的左标题
  66 + */
  67 + default void setLeftTitle(int id) {
  68 + if (getTitleBar() != null) {
  69 + getTitleBar().setLeftTitle(id);
  70 + }
  71 + }
  72 +
  73 + default void setLeftTitle(CharSequence text) {
  74 + if (getTitleBar() != null) {
  75 + getTitleBar().setLeftTitle(text);
  76 + }
  77 + }
  78 +
  79 + default CharSequence getLeftTitle() {
  80 + if (getTitleBar() != null) {
  81 + return getTitleBar().getLeftTitle();
  82 + }
  83 + return "";
  84 + }
  85 +
  86 + /**
  87 + * 设置标题栏的右标题
  88 + */
  89 + default void setRightTitle(int id) {
  90 + if (getTitleBar() != null) {
  91 + getTitleBar().setRightTitle(id);
  92 + }
  93 + }
  94 +
  95 + default void setRightTitle(CharSequence text) {
  96 + if (getTitleBar() != null) {
  97 + getTitleBar().setRightTitle(text);
  98 + }
  99 + }
  100 +
  101 + default CharSequence getRightTitle() {
  102 + if (getTitleBar() != null) {
  103 + return getTitleBar().getRightTitle();
  104 + }
  105 + return "";
  106 + }
  107 +
  108 + /**
  109 + * 设置标题栏的左图标
  110 + */
  111 + default void setLeftIcon(int id) {
  112 + if (getTitleBar() != null) {
  113 + getTitleBar().setLeftIcon(id);
  114 + }
  115 + }
  116 +
  117 + default void setLeftIcon(Drawable drawable) {
  118 + if (getTitleBar() != null) {
  119 + getTitleBar().setLeftIcon(drawable);
  120 + }
  121 + }
  122 +
  123 + @Nullable
  124 + default Drawable getLeftIcon() {
  125 + if (getTitleBar() != null) {
  126 + return getTitleBar().getLeftIcon();
  127 + }
  128 + return null;
  129 + }
  130 +
  131 + /**
  132 + * 设置标题栏的右图标
  133 + */
  134 + default void setRightIcon(int id) {
  135 + if (getTitleBar() != null) {
  136 + getTitleBar().setRightIcon(id);
  137 + }
  138 + }
  139 +
  140 + default void setRightIcon(Drawable drawable) {
  141 + if (getTitleBar() != null) {
  142 + getTitleBar().setRightIcon(drawable);
  143 + }
  144 + }
  145 +
  146 + @Nullable
  147 + default Drawable getRightIcon() {
  148 + if (getTitleBar() != null) {
  149 + return getTitleBar().getRightIcon();
  150 + }
  151 + return null;
  152 + }
  153 +
  154 + /**
  155 + * 递归获取 ViewGroup 中的 TitleBar 对象
  156 + */
  157 + default TitleBar obtainTitleBar(ViewGroup group) {
  158 + if (group == null) {
  159 + return null;
  160 + }
  161 + for (int i = 0; i < group.getChildCount(); i++) {
  162 + View view = group.getChildAt(i);
  163 + if ((view instanceof TitleBar)) {
  164 + return (TitleBar) view;
  165 + }
  166 +
  167 + if (view instanceof ViewGroup) {
  168 + TitleBar titleBar = obtainTitleBar((ViewGroup) view);
  169 + if (titleBar != null) {
  170 + return titleBar;
  171 + }
  172 + }
  173 + }
  174 + return null;
  175 + }
  176 +}
\ No newline at end of file
... ...
  1 +package com.studymachine.www.action;
  2 +
  3 +import androidx.annotation.StringRes;
  4 +
  5 +import com.hjq.toast.ToastUtils;
  6 +
  7 +/**
  8 + * time : 2019/12/08
  9 + * desc : 吐司意图
  10 + */
  11 +public interface ToastAction {
  12 +
  13 + default void toast(CharSequence text) {
  14 + ToastUtils.show(text);
  15 + }
  16 +
  17 + default void toast(@StringRes int id) {
  18 + ToastUtils.show(id);
  19 + }
  20 +
  21 + default void toast(Object object) {
  22 + ToastUtils.show(object);
  23 + }
  24 +}
\ No newline at end of file
... ...
  1 +package com.studymachine.www.aop;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +/**
  9 + * time : 2020/01/11
  10 + * desc : 网络检测注解
  11 + */
  12 +@Retention(RetentionPolicy.RUNTIME)
  13 +@Target(ElementType.METHOD)
  14 +public @interface CheckNet {}
\ No newline at end of file
... ...
  1 +package com.studymachine.www.aop;
  2 +
  3 +import android.app.Activity;
  4 +import android.app.Application;
  5 +import android.net.ConnectivityManager;
  6 +import android.net.NetworkInfo;
  7 +
  8 +import androidx.core.content.ContextCompat;
  9 +import androidx.lifecycle.Lifecycle;
  10 +import androidx.lifecycle.LifecycleOwner;
  11 +
  12 +import com.studymachine.www.R;
  13 +import com.studymachine.www.manager.ActivityManager;
  14 +import com.hjq.toast.ToastUtils;
  15 +import com.studymachine.www.ui.activity.NoNetworkActivity;
  16 +
  17 +import org.aspectj.lang.ProceedingJoinPoint;
  18 +import org.aspectj.lang.annotation.Around;
  19 +import org.aspectj.lang.annotation.Aspect;
  20 +import org.aspectj.lang.annotation.Pointcut;
  21 +
  22 +/**
  23 + * time : 2020/01/11
  24 + * desc : 网络检测切面
  25 + */
  26 +@Aspect
  27 +public class CheckNetAspect {
  28 +
  29 + /**
  30 + * 方法切入点
  31 + */
  32 + @Pointcut("execution(@com.studymachine.www.aop.CheckNet * *(..))")
  33 + public void method() {}
  34 +
  35 + /**
  36 + * 在连接点进行方法替换
  37 + */
  38 + @Around("method() && @annotation(checkNet)")
  39 + public void aroundJoinPoint(ProceedingJoinPoint joinPoint, CheckNet checkNet) throws Throwable {
  40 + Application application = ActivityManager.getInstance().getApplication();
  41 + if (application != null) {
  42 + ConnectivityManager manager = ContextCompat.getSystemService(application, ConnectivityManager.class);
  43 + if (manager != null) {
  44 + NetworkInfo info = manager.getActiveNetworkInfo();
  45 + // 判断网络是否连接
  46 + if (info == null || !info.isConnected()) {
  47 + ToastUtils.show(R.string.common_network_hint);
  48 + Activity topActivity = ActivityManager.getInstance().getTopActivity();
  49 + NoNetworkActivity.start(topActivity);
  50 + return;
  51 + }
  52 + }
  53 + }
  54 + //执行原方法
  55 + joinPoint.proceed();
  56 + }
  57 +}
\ No newline at end of file
... ...
  1 +package com.studymachine.www.aop;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +/**
  9 + * time : 2019/12/06
  10 + * desc : Debug 日志注解
  11 + */
  12 +@Retention(RetentionPolicy.RUNTIME)
  13 +@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
  14 +public @interface Log {
  15 +
  16 + String value() default "AppLog";
  17 +}
\ No newline at end of file
... ...
  1 +package com.studymachine.www.aop;
  2 +
  3 +import android.os.Looper;
  4 +import android.os.Trace;
  5 +
  6 +import androidx.annotation.NonNull;
  7 +
  8 +import org.aspectj.lang.ProceedingJoinPoint;
  9 +import org.aspectj.lang.Signature;
  10 +import org.aspectj.lang.annotation.Around;
  11 +import org.aspectj.lang.annotation.Aspect;
  12 +import org.aspectj.lang.annotation.Pointcut;
  13 +import org.aspectj.lang.reflect.CodeSignature;
  14 +import org.aspectj.lang.reflect.MethodSignature;
  15 +
  16 +import java.util.concurrent.TimeUnit;
  17 +
  18 +import timber.log.Timber;
  19 +
  20 +/**
  21 + * time : 2019/12/06
  22 + * desc : Debug 日志切面
  23 + */
  24 +@Aspect
  25 +public class LogAspect {
  26 +
  27 + /**
  28 + * 构造方法切入点
  29 + */
  30 + @Pointcut("execution(@com.studymachine.www.aop.Log *.new(..))")
  31 + public void constructor() {}
  32 +
  33 + /**
  34 + * 方法切入点
  35 + */
  36 + @Pointcut("execution(@com.studymachine.www.aop.Log * *(..))")
  37 + public void method() {}
  38 +
  39 + /**
  40 + * 在连接点进行方法替换
  41 + */
  42 + @Around("(method() || constructor()) && @annotation(log)")
  43 + public Object aroundJoinPoint(ProceedingJoinPoint joinPoint, Log log) throws Throwable {
  44 + enterMethod(joinPoint, log);
  45 +
  46 + long startNanos = System.nanoTime();
  47 + Object result = joinPoint.proceed();
  48 + long stopNanos = System.nanoTime();
  49 +
  50 + exitMethod(joinPoint, log, result, TimeUnit.NANOSECONDS.toMillis(stopNanos - startNanos));
  51 +
  52 + return result;
  53 + }
  54 +
  55 + /**
  56 + * 方法执行前切入
  57 + */
  58 + private void enterMethod(ProceedingJoinPoint joinPoint, Log log) {
  59 + CodeSignature codeSignature = (CodeSignature) joinPoint.getSignature();
  60 +
  61 + // 方法所在类
  62 + String className = codeSignature.getDeclaringType().getName();
  63 + // 方法名
  64 + String methodName = codeSignature.getName();
  65 + // 方法参数名集合
  66 + String[] parameterNames = codeSignature.getParameterNames();
  67 + // 方法参数值集合
  68 + Object[] parameterValues = joinPoint.getArgs();
  69 +
  70 + //记录并打印方法的信息
  71 + StringBuilder builder = getMethodLogInfo(className, methodName, parameterNames, parameterValues);
  72 +
  73 + log(log.value(), builder.toString());
  74 +
  75 + final String section = builder.substring(2);
  76 + Trace.beginSection(section);
  77 + }
  78 +
  79 + /**
  80 + * 获取方法的日志信息
  81 + *
  82 + * @param className 类名
  83 + * @param methodName 方法名
  84 + * @param parameterNames 方法参数名集合
  85 + * @param parameterValues 方法参数值集合
  86 + */
  87 + @NonNull
  88 + private StringBuilder getMethodLogInfo(String className, String methodName, String[] parameterNames, Object[] parameterValues) {
  89 + StringBuilder builder = new StringBuilder("\u21E2 ");
  90 + builder.append(className)
  91 + .append(".")
  92 + .append(methodName)
  93 + .append('(');
  94 + for (int i = 0; i < parameterValues.length; i++) {
  95 + if (i > 0) {
  96 + builder.append(", ");
  97 + }
  98 + builder.append(parameterNames[i]).append('=');
  99 + builder.append(parameterValues[i].toString());
  100 + }
  101 + builder.append(')');
  102 +
  103 + if (Looper.myLooper() != Looper.getMainLooper()) {
  104 + builder.append(" [Thread:\"").append(Thread.currentThread().getName()).append("\"]");
  105 + }
  106 + return builder;
  107 + }
  108 +
  109 +
  110 + /**
  111 + * 方法执行完毕,切出
  112 + *
  113 + * @param result 方法执行后的结果
  114 + * @param lengthMillis 执行方法所需要的时间
  115 + */
  116 + private void exitMethod(ProceedingJoinPoint joinPoint, Log log, Object result, long lengthMillis) {
  117 + Trace.endSection();
  118 +
  119 + Signature signature = joinPoint.getSignature();
  120 +
  121 + String className = signature.getDeclaringType().getName();
  122 + String methodName = signature.getName();
  123 +
  124 + StringBuilder builder = new StringBuilder("\u21E0 ")
  125 + .append(className)
  126 + .append(".")
  127 + .append(methodName)
  128 + .append(" [")
  129 + .append(lengthMillis)
  130 + .append("ms]");
  131 +
  132 + // 判断方法是否有返回值
  133 + if (signature instanceof MethodSignature && ((MethodSignature) signature).getReturnType() != void.class) {
  134 + builder.append(" = ");
  135 + builder.append(result.toString());
  136 + }
  137 +
  138 + log(log.value(), builder.toString());
  139 + }
  140 +
  141 + private void log(String tag, String msg) {
  142 + Timber.tag(tag);
  143 + Timber.d(msg);
  144 + }
  145 +}
\ No newline at end of file
... ...
  1 +package com.studymachine.www.aop;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +/**
  9 + * time : 2019/12/06
  10 + * desc : 权限申请注解
  11 + */
  12 +@Retention(RetentionPolicy.RUNTIME)
  13 +@Target({ElementType.METHOD})
  14 +public @interface Permissions {
  15 +
  16 + /**
  17 + * 需要申请权限的集合
  18 + */
  19 + String[] value();
  20 +}
\ No newline at end of file
... ...
  1 +package com.studymachine.www.aop;
  2 +
  3 +import android.app.Activity;
  4 +
  5 +import com.studymachine.www.manager.ActivityManager;
  6 +import com.studymachine.www.other.PermissionCallback;
  7 +import com.hjq.permissions.XXPermissions;
  8 +import com.tencent.bugly.crashreport.CrashReport;
  9 +
  10 +import org.aspectj.lang.ProceedingJoinPoint;
  11 +import org.aspectj.lang.annotation.Around;
  12 +import org.aspectj.lang.annotation.Aspect;
  13 +import org.aspectj.lang.annotation.Pointcut;
  14 +
  15 +import java.util.List;
  16 +
  17 +import timber.log.Timber;
  18 +
  19 +/**
  20 + * time : 2019/12/06
  21 + * desc : 权限申请切面
  22 + */
  23 +@Aspect
  24 +public class PermissionsAspect {
  25 +
  26 + /**
  27 + * 方法切入点
  28 + */
  29 + @Pointcut("execution(@com.studymachine.www.aop.Permissions * *(..))")
  30 + public void method() {}
  31 +
  32 + /**
  33 + * 在连接点进行方法替换
  34 + */
  35 + @Around("method() && @annotation(permissions)")
  36 + public void aroundJoinPoint(ProceedingJoinPoint joinPoint, Permissions permissions) {
  37 + Activity activity = null;
  38 +
  39 + // 方法参数值集合
  40 + Object[] parameterValues = joinPoint.getArgs();
  41 + for (Object arg : parameterValues) {
  42 + if (!(arg instanceof Activity)) {
  43 + continue;
  44 + }
  45 + activity = (Activity) arg;
  46 + break;
  47 + }
  48 +
  49 + if (activity == null || activity.isFinishing() || activity.isDestroyed()) {
  50 + activity = ActivityManager.getInstance().getTopActivity();
  51 + }
  52 +
  53 + if (activity == null || activity.isFinishing() || activity.isDestroyed()) {
  54 + Timber.e("The activity has been destroyed and permission requests cannot be made");
  55 + return;
  56 + }
  57 +
  58 + requestPermissions(joinPoint, activity, permissions.value());
  59 + }
  60 +
  61 + private void requestPermissions(ProceedingJoinPoint joinPoint, Activity activity, String[] permissions) {
  62 + XXPermissions.with(activity)
  63 + .permission(permissions)
  64 + .request(new PermissionCallback() {
  65 +
  66 + @Override
  67 + public void onGranted(List<String> permissions, boolean all) {
  68 + if (all) {
  69 + try {
  70 + // 获得权限,执行原方法
  71 + joinPoint.proceed();
  72 + } catch (Throwable e) {
  73 + CrashReport.postCatchedException(e);
  74 + }
  75 + }
  76 + }
  77 + });
  78 + }
  79 +}
\ No newline at end of file
... ...
  1 +package com.studymachine.www.aop;
  2 +
  3 +import java.lang.annotation.ElementType;
  4 +import java.lang.annotation.Retention;
  5 +import java.lang.annotation.RetentionPolicy;
  6 +import java.lang.annotation.Target;
  7 +
  8 +/**
  9 + * time : 2019/12/06
  10 + * desc : 防重复点击注解
  11 + */
  12 +@Retention(RetentionPolicy.RUNTIME)
  13 +@Target(ElementType.METHOD)
  14 +public @interface SingleClick {
  15 +
  16 + /**
  17 + * 快速点击的间隔
  18 + */
  19 + long value() default 1000;
  20 +}
\ No newline at end of file
... ...
  1 +package com.studymachine.www.aop;
  2 +
  3 +import org.aspectj.lang.ProceedingJoinPoint;
  4 +import org.aspectj.lang.annotation.Around;
  5 +import org.aspectj.lang.annotation.Aspect;
  6 +import org.aspectj.lang.annotation.Pointcut;
  7 +import org.aspectj.lang.reflect.CodeSignature;
  8 +
  9 +import timber.log.Timber;
  10 +
  11 +/**
  12 + * time : 2019/12/06
  13 + * desc : 防重复点击切面
  14 + */
  15 +@Aspect
  16 +public class SingleClickAspect {
  17 +
  18 + /** 最近一次点击的时间 */
  19 + private long mLastTime;
  20 +
  21 + /** 最近一次点击的标记 */
  22 + private String mLastTag;
  23 +
  24 + /**
  25 + * 方法切入点
  26 + */
  27 + @Pointcut("execution(@com.studymachine.www.aop.SingleClick * *(..))")
  28 + public void method() {}
  29 +
  30 + /**
  31 + * 在连接点进行方法替换
  32 + */
  33 + @Around("method() && @annotation(singleClick)")
  34 + public void aroundJoinPoint(ProceedingJoinPoint joinPoint, SingleClick singleClick) throws Throwable {
  35 + CodeSignature codeSignature = (CodeSignature) joinPoint.getSignature();
  36 + // 方法所在类
  37 + String className = codeSignature.getDeclaringType().getName();
  38 + // 方法名
  39 + String methodName = codeSignature.getName();
  40 + // 构建方法 TAG
  41 + StringBuilder builder = new StringBuilder(className + "." + methodName);
  42 + builder.append("(");
  43 + Object[] parameterValues = joinPoint.getArgs();
  44 + for (int i = 0; i < parameterValues.length; i++) {
  45 + Object arg = parameterValues[i];
  46 + if (i == 0) {
  47 + builder.append(arg);
  48 + } else {
  49 + builder.append(", ")
  50 + .append(arg);
  51 + }
  52 + }
  53 + builder.append(")");
  54 +
  55 + String tag = builder.toString();
  56 + long currentTimeMillis = System.currentTimeMillis();
  57 + if (currentTimeMillis - mLastTime < singleClick.value() && tag.equals(mLastTag)) {
  58 + Timber.tag("SingleClick");
  59 + Timber.i("%s 毫秒内发生快速点击:%s", singleClick.value(), tag);
  60 + return;
  61 + }
  62 + mLastTime = currentTimeMillis;
  63 + mLastTag = tag;
  64 + // 执行原方法
  65 + joinPoint.proceed();
  66 + }
  67 +}
\ No newline at end of file
... ...
  1 +package com.studymachine.www.app;
  2 +
  3 +import android.content.Intent;
  4 +import android.os.Bundle;
  5 +import android.view.View;
  6 +import android.view.WindowManager;
  7 +
  8 +import androidx.annotation.NonNull;
  9 +import androidx.annotation.Nullable;
  10 +import androidx.annotation.StringRes;
  11 +
  12 +import com.gyf.immersionbar.BarHide;
  13 +import com.gyf.immersionbar.ImmersionBar;
  14 +import com.hjq.bar.TitleBar;
  15 +import com.hjq.base.BaseActivity;
  16 +import com.hjq.base.BaseDialog;
  17 +import com.studymachine.www.R;
  18 +import com.studymachine.www.action.TitleBarAction;
  19 +import com.studymachine.www.action.ToastAction;
  20 +import com.studymachine.www.http.model.HttpData;
  21 +import com.studymachine.www.manager.EventBusManager;
  22 +import com.studymachine.www.other.Tool;
  23 +import com.studymachine.www.ui.activity.HomeActivity;
  24 +import com.studymachine.www.ui.dialog.WaitDialog;
  25 +import com.hjq.http.listener.OnHttpListener;
  26 +
  27 +import org.greenrobot.eventbus.EventBus;
  28 +
  29 +import okhttp3.Call;
  30 +
  31 +/**
  32 + * time : 2018/10/18
  33 + * desc : Activity 业务基类
  34 + */
  35 +public abstract class AppActivity extends BaseActivity
  36 + implements ToastAction, TitleBarAction, OnHttpListener<Object> {
  37 +
  38 + /**
  39 + * 标题栏对象
  40 + */
  41 + private TitleBar mTitleBar;
  42 + /**
  43 + * 状态栏沉浸
  44 + */
  45 + private ImmersionBar mImmersionBar;
  46 +
  47 + /**
  48 + * 加载对话框
  49 + */
  50 + private BaseDialog mDialog;
  51 + /**
  52 + * 对话框数量
  53 + */
  54 + private int mDialogCount;
  55 +
  56 + /**
  57 + * 当前加载对话框是否在显示中
  58 + */
  59 + public boolean isShowDialog() {
  60 + return mDialog != null && mDialog.isShowing();
  61 + }
  62 +
  63 + /**
  64 + * 显示加载对话框
  65 + */
  66 + public void showDialog() {
  67 + if (isFinishing() || isDestroyed()) {
  68 + return;
  69 + }
  70 + mDialogCount++;
  71 + postDelayed(() -> {
  72 + if (mDialogCount <= 0 || isFinishing() || isDestroyed()) {
  73 + return;
  74 + }
  75 +
  76 + if (mDialog == null) {
  77 + mDialog = new WaitDialog.Builder(this)
  78 + .setCancelable(false)
  79 + .create();
  80 + }
  81 + if (!mDialog.isShowing()) {
  82 + mDialog.show();
  83 + }
  84 + }, 300);
  85 + }
  86 +
  87 + /**
  88 + * 隐藏加载对话框
  89 + */
  90 + public void hideDialog() {
  91 + if (isFinishing() || isDestroyed()) {
  92 + return;
  93 + }
  94 +
  95 + if (mDialogCount > 0) {
  96 + mDialogCount--;
  97 + }
  98 +
  99 + if (mDialogCount != 0 || mDialog == null || !mDialog.isShowing()) {
  100 + return;
  101 + }
  102 +
  103 + mDialog.dismiss();
  104 + }
  105 +
  106 + @Override
  107 + protected void initLayout() {
  108 + super.initLayout();
  109 +
  110 + if (getTitleBar() != null) {
  111 + getTitleBar().setOnTitleBarListener(this);
  112 + }
  113 +
  114 + // 初始化沉浸式状态栏
  115 + if (isStatusBarEnabled()) {
  116 + getStatusBarConfig().init();
  117 +
  118 + // 设置标题栏沉浸
  119 + if (getTitleBar() != null) {
  120 + ImmersionBar.setTitleBar(this, getTitleBar());
  121 + }
  122 + }
  123 + //保持常亮
  124 + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
  125 + EventBusManager.register(this);
  126 + }
  127 +
  128 + /**
  129 + * 是否使用沉浸式状态栏
  130 + */
  131 + protected boolean isStatusBarEnabled() {
  132 + return true;
  133 + }
  134 +
  135 + /**
  136 + * 状态栏字体深色模式
  137 + */
  138 + protected boolean isStatusBarDarkFont() {
  139 + return true;
  140 + }
  141 +
  142 + /**
  143 + * 获取状态栏沉浸的配置对象
  144 + */
  145 + @NonNull
  146 + public ImmersionBar getStatusBarConfig() {
  147 + if (mImmersionBar == null) {
  148 + mImmersionBar = createStatusBarConfig();
  149 + }
  150 + return mImmersionBar;
  151 + }
  152 +
  153 + /**
  154 + * 初始化沉浸式状态栏
  155 + */
  156 + @NonNull
  157 + protected ImmersionBar createStatusBarConfig() {
  158 +
  159 + return ImmersionBar.with(this)
  160 + // 隐藏状态栏和导航栏
  161 + .hideBar(BarHide.FLAG_HIDE_BAR);
  162 +// return ImmersionBar.with(this)
  163 +// // 默认状态栏字体颜色为黑色
  164 +// .statusBarDarkFont(isStatusBarDarkFont())
  165 +// // 指定导航栏背景颜色
  166 +// .navigationBarColor(R.color.white)
  167 +// // 状态栏字体和导航栏内容自动变色,必须指定状态栏颜色和导航栏颜色才可以自动变色
  168 +// .autoDarkModeEnable(true, 0.2f);
  169 + }
  170 +
  171 + /**
  172 + * 设置标题栏的标题
  173 + */
  174 + @Override
  175 + public void setTitle(@StringRes int id) {
  176 + setTitle(getString(id));
  177 + }
  178 +
  179 + /**
  180 + * 设置标题栏的标题
  181 + */
  182 + @Override
  183 + public void setTitle(CharSequence title) {
  184 + super.setTitle(title);
  185 + if (getTitleBar() != null) {
  186 + getTitleBar().setTitle(title);
  187 + }
  188 + }
  189 +
  190 + @Override
  191 + @Nullable
  192 + public TitleBar getTitleBar() {
  193 + if (mTitleBar == null) {
  194 + mTitleBar = obtainTitleBar(getContentView());
  195 + }
  196 + return mTitleBar;
  197 + }
  198 +
  199 + @Override
  200 + public void onLeftClick(View view) {
  201 + onBackPressed();
  202 + }
  203 +
  204 + @Override
  205 + public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
  206 + super.startActivityForResult(intent, requestCode, options);
  207 + overridePendingTransition(R.anim.right_in_activity, R.anim.right_out_activity);
  208 + }
  209 +
  210 + @Override
  211 + public void finish() {
  212 + super.finish();
  213 + overridePendingTransition(R.anim.left_in_activity, R.anim.left_out_activity);
  214 + }
  215 +
  216 + /**
  217 + * {@link OnHttpListener}
  218 + */
  219 +
  220 + @Override
  221 + public void onStart(Call call) {
  222 + showDialog();
  223 + }
  224 +
  225 + @Override
  226 + public void onSucceed(Object result) {
  227 + if (result instanceof HttpData) {
  228 + toast(((HttpData<?>) result).getMessage());
  229 + }
  230 + }
  231 +
  232 + @Override
  233 + public void onFail(Exception e) {
  234 + toast(e.getMessage());
  235 + }
  236 +
  237 + @Override
  238 + public void onEnd(Call call) {
  239 + hideDialog();
  240 + }
  241 +
  242 + @Override
  243 + protected void onDestroy() {
  244 + super.onDestroy();
  245 + if (isShowDialog()) {
  246 + hideDialog();
  247 + }
  248 + mDialog = null;
  249 + EventBusManager.unregister(this);
  250 + }
  251 +}
\ No newline at end of file
... ...
  1 +package com.studymachine.www.app;
  2 +
  3 +import android.content.Context;
  4 +import android.view.View;
  5 +
  6 +import androidx.annotation.IntRange;
  7 +import androidx.annotation.LayoutRes;
  8 +import androidx.annotation.NonNull;
  9 +import androidx.annotation.Nullable;
  10 +
  11 +import com.hjq.base.BaseAdapter;
  12 +
  13 +import java.util.ArrayList;
  14 +import java.util.List;
  15 +
  16 +
  17 +/**
  18 + * time : 2018/12/19
  19 + * desc : RecyclerView 适配器业务基类
  20 + */
  21 +public abstract class AppAdapter<T> extends BaseAdapter<BaseAdapter<?>.ViewHolder> {
  22 +
  23 + /** 列表数据 */
  24 + private List<T> mDataSet;
  25 + /** 当前列表的页码,默认为第一页,用于分页加载功能 */
  26 + private int mPageNumber = 1;
  27 + /** 是否是最后一页,默认为false,用于分页加载功能 */
  28 + private boolean mLastPage;
  29 + /** 标记对象 */
  30 + private Object mTag;
  31 +
  32 + public AppAdapter(@NonNull Context context) {
  33 + super(context);
  34 + }
  35 +
  36 + @Override
  37 + public int getItemCount() {
  38 + return getCount();
  39 + }
  40 +
  41 + /**
  42 + * 获取数据总数
  43 + */
  44 + public int getCount() {
  45 + if (mDataSet == null) {
  46 + return 0;
  47 + }
  48 + return mDataSet.size();
  49 + }
  50 +
  51 + /**
  52 + * 设置新的数据
  53 + */
  54 + public void setData(@Nullable List<T> data) {
  55 + mDataSet = data;
  56 + notifyDataSetChanged();
  57 + }
  58 +
  59 + /**
  60 + * 获取当前数据
  61 + */
  62 + @Nullable
  63 + public List<T> getData() {
  64 + return mDataSet;
  65 + }
  66 +
  67 + /**
  68 + * 追加一些数据
  69 + */
  70 + public void addData(List<T> data) {
  71 + if (data == null || data.size() == 0) {
  72 + return;
  73 + }
  74 +
  75 + if (mDataSet == null || mDataSet.size() == 0) {
  76 + setData(data);
  77 + return;
  78 + }
  79 +
  80 + mDataSet.addAll(data);
  81 + notifyItemRangeInserted(mDataSet.size() - data.size(), data.size());
  82 + }
  83 +
  84 + /**
  85 + * 清空当前数据
  86 + */
  87 + public void clearData() {
  88 + if (mDataSet == null || mDataSet.size() == 0) {
  89 + return;
  90 + }
  91 +
  92 + mDataSet.clear();
  93 + notifyDataSetChanged();
  94 + }
  95 +
  96 + /**
  97 + * 是否包含了某个位置上的条目数据
  98 + */
  99 + public boolean containsItem(@IntRange(from = 0) int position) {
  100 + return containsItem(getItem(position));
  101 + }
  102 +
  103 + /**
  104 + * 是否包含某个条目数据
  105 + */
  106 + public boolean containsItem(T item) {
  107 + if (mDataSet == null || item == null) {
  108 + return false;
  109 + }
  110 + return mDataSet.contains(item);
  111 + }
  112 +
  113 + /**
  114 + * 获取某个位置上的数据
  115 + */
  116 + public T getItem(@IntRange(from = 0) int position) {
  117 + if (mDataSet == null) {
  118 + return null;
  119 + }
  120 + return mDataSet.get(position);
  121 + }
  122 +
  123 + /**
  124 + * 更新某个位置上的数据
  125 + */
  126 + public void setItem(@IntRange(from = 0) int position, @NonNull T item) {
  127 + if (mDataSet == null) {
  128 + mDataSet = new ArrayList<>();
  129 + }
  130 + mDataSet.set(position, item);
  131 + notifyItemChanged(position);
  132 + }
  133 +
  134 + /**
  135 + * 添加单条数据
  136 + */
  137 + public void addItem(@NonNull T item) {
  138 + if (mDataSet == null) {
  139 + mDataSet = new ArrayList<>();
  140 + }
  141 + addItem(mDataSet.size(), item);
  142 + }
  143 +
  144 + public void addItem(@IntRange(from = 0) int position, @NonNull T item) {
  145 + if (mDataSet == null) {
  146 + mDataSet = new ArrayList<>();
  147 + }
  148 +
  149 + if (position < mDataSet.size()) {
  150 + mDataSet.add(position, item);
  151 + } else {
  152 + mDataSet.add(item);
  153 + position = mDataSet.size() - 1;
  154 + }
  155 + notifyItemInserted(position);
  156 + }
  157 +
  158 + /**
  159 + * 删除单条数据
  160 + */
  161 + public void removeItem(@NonNull T item) {
  162 + int index = mDataSet.indexOf(item);
  163 + if (index != -1) {
  164 + removeItem(index);
  165 + }
  166 + }
  167 +
  168 + public void removeItem(@IntRange(from = 0) int position) {
  169 + mDataSet.remove(position);
  170 + notifyItemRemoved(position);
  171 + }
  172 +
  173 + /**
  174 + * 获取当前的页码
  175 + */
  176 + public int getPageNumber() {
  177 + return mPageNumber;
  178 + }
  179 +
  180 + /**
  181 + * 设置当前的页码
  182 + */
  183 + public void setPageNumber(@IntRange(from = 0) int number) {
  184 + mPageNumber = number;
  185 + }
  186 +
  187 + /**
  188 + * 当前是否为最后一页
  189 + */
  190 + public boolean isLastPage() {
  191 + return mLastPage;
  192 + }
  193 +
  194 + /**
  195 + * 设置是否为最后一页
  196 + */
  197 + public void setLastPage(boolean last) {
  198 + mLastPage = last;
  199 + }
  200 +
  201 + /**
  202 + * 获取标记
  203 + */
  204 + @Nullable
  205 + public Object getTag() {
  206 + return mTag;
  207 + }
  208 +
  209 + /**
  210 + * 设置标记
  211 + */
  212 + public void setTag(@NonNull Object tag) {
  213 + mTag = tag;
  214 + }
  215 +
  216 + public final class SimpleHolder extends ViewHolder {
  217 +
  218 + public SimpleHolder(@LayoutRes int id) {
  219 + super(id);
  220 + }
  221 +
  222 + public SimpleHolder(View itemView) {
  223 + super(itemView);
  224 + }
  225 +
  226 + @Override
  227 + public void onBindView(int position) {}
  228 + }
  229 +}
\ No newline at end of file
... ...
  1 +package com.studymachine.www.app;
  2 +
  3 +import android.app.Activity;
  4 +import android.app.Application;
  5 +import android.content.Context;
  6 +import android.hardware.usb.UsbDevice;
  7 +import android.net.ConnectivityManager;
  8 +import android.net.Network;
  9 +import android.os.Build;
  10 +
  11 +import androidx.annotation.NonNull;
  12 +import androidx.core.content.ContextCompat;
  13 +import androidx.lifecycle.Lifecycle;
  14 +import androidx.lifecycle.LifecycleOwner;
  15 +import androidx.lifecycle.MutableLiveData;
  16 +
  17 +import com.rokid.axr.phone.glassdevice.RKGlassDevice;
  18 +import com.rokid.axr.phone.glassdevice.callback.OnGlassDeviceConnectListener;
  19 +import com.rokid.axr.phone.glassdevice.hw.GlassSensorListener;
  20 +
  21 +import com.blankj.utilcode.util.NetworkUtils;
  22 +import com.hjq.bar.TitleBar;
  23 +import com.hjq.http.EasyHttp;
  24 +import com.hjq.http.lifecycle.ApplicationLifecycle;
  25 +import com.hjq.http.listener.OnHttpListener;
  26 +import com.studymachine.www.R;
  27 +import com.studymachine.www.aop.Log;
  28 +import com.studymachine.www.http.api.UpdateVersionApi;
  29 +import com.studymachine.www.http.glide.GlideApp;
  30 +import com.studymachine.www.http.model.HttpData;
  31 +import com.studymachine.www.http.model.RequestHandler;
  32 +import com.studymachine.www.http.model.RequestServer;
  33 +import com.studymachine.www.manager.ActivityManager;
  34 +import com.studymachine.www.manager.DictionariesManager;
  35 +import com.studymachine.www.manager.EventBusManager;
  36 +import com.studymachine.www.manager.UserManager;
  37 +import com.studymachine.www.other.AppConfig;
  38 +import com.studymachine.www.other.CrashHandler;
  39 +import com.studymachine.www.other.DebugLoggerTree;
  40 +import com.studymachine.www.other.MaterialHeader;
  41 +import com.studymachine.www.other.SmartBallPulseFooter;
  42 +import com.studymachine.www.other.TitleBarStyle;
  43 +import com.studymachine.www.other.ToastLogInterceptor;
  44 +import com.studymachine.www.other.ToastStyle;
  45 +import com.hjq.gson.factory.GsonFactory;
  46 +import com.hjq.http.EasyConfig;
  47 +import com.hjq.toast.ToastUtils;
  48 +import com.hjq.umeng.UmengClient;
  49 +import com.scwang.smart.refresh.layout.SmartRefreshLayout;
  50 +import com.studymachine.www.ui.activity.NoNetworkActivity;
  51 +import com.studymachine.www.ui.dialog.NoNetworkDialog;
  52 +import com.studymachine.www.ui.dialog.UpdateDialog;
  53 +import com.tencent.bugly.crashreport.CrashReport;
  54 +import com.tencent.mmkv.MMKV;
  55 +import com.tencent.smtt.export.external.TbsCoreSettings;
  56 +import com.tencent.smtt.sdk.QbSdk;
  57 +
  58 +import java.util.HashMap;
  59 +
  60 +import okhttp3.OkHttpClient;
  61 +import timber.log.Timber;
  62 +
  63 +/**
  64 + * desc : 应用入口
  65 + */
  66 +public final class AppApplication extends Application {
  67 +
  68 + @Log("启动耗时")
  69 + @Override
  70 + public void onCreate() {
  71 + super.onCreate();
  72 + initSdk(this);
  73 + initApp();
  74 + }
  75 +
  76 + private void initApp() {
  77 + }
  78 +
  79 + @Override
  80 + protected void attachBaseContext(Context base) {
  81 + super.attachBaseContext(base);
  82 + }
  83 +
  84 + @Override
  85 + public void onLowMemory() {
  86 + super.onLowMemory();
  87 + // 清理所有图片内存缓存
  88 + GlideApp.get(this).onLowMemory();
  89 + }
  90 +
  91 + @Override
  92 + public void onTrimMemory(int level) {
  93 + super.onTrimMemory(level);
  94 + // 根据手机内存剩余情况清理图片内存缓存
  95 + GlideApp.get(this).onTrimMemory(level);
  96 + }
  97 +
  98 +
  99 + /**
  100 + * 初始化一些第三方框架
  101 + */
  102 + public static void initSdk(Application application) {
  103 +
  104 + //初始化x5内核
  105 + initX5app(application);
  106 +
  107 + // 设置标题栏初始化器
  108 + TitleBar.setDefaultStyle(new TitleBarStyle());
  109 +
  110 + // 设置全局的 Header 构建器
  111 + SmartRefreshLayout.setDefaultRefreshHeaderCreator((cx, layout) ->
  112 + new MaterialHeader(application).setColorSchemeColors(ContextCompat.getColor(application, R.color.common_accent_color)));
  113 + // 设置全局的 Footer 构建器
  114 + SmartRefreshLayout.setDefaultRefreshFooterCreator((cx, layout) -> new SmartBallPulseFooter(application));
  115 + // 设置全局初始化器
  116 + SmartRefreshLayout.setDefaultRefreshInitializer((cx, layout) -> {
  117 + // 刷新头部是否跟随内容偏移
  118 + layout.setEnableHeaderTranslationContent(true)
  119 + // 刷新尾部是否跟随内容偏移
  120 + .setEnableFooterTranslationContent(true)
  121 + // 加载更多是否跟随内容偏移
  122 + .setEnableFooterFollowWhenNoMoreData(true)
  123 + // 内容不满一页时是否可以上拉加载更多
  124 + .setEnableLoadMoreWhenContentNotFull(false)
  125 + // 仿苹果越界效果开关
  126 + .setEnableOverScrollDrag(false);
  127 + });
  128 +
  129 + // 初始化吐司
  130 + ToastUtils.init(application, new ToastStyle());
  131 + // 设置调试模式
  132 + ToastUtils.setDebugMode(AppConfig.isDebug());
  133 + // 设置 Toast 拦截器
  134 + ToastUtils.setInterceptor(new ToastLogInterceptor());
  135 +
  136 + // EventBus 事件总线
  137 + EventBusManager.init();
  138 +
  139 + // 本地异常捕捉
  140 + CrashHandler.register(application);
  141 +
  142 + // 友盟统计、登录、分享 SDK
  143 + UmengClient.init(application, AppConfig.isLogEnable());
  144 +
  145 + // Bugly 异常捕捉
  146 + CrashReport.initCrashReport(application, AppConfig.getBuglyId(), AppConfig.isDebug());
  147 +
  148 + // Activity 栈管理初始化
  149 + ActivityManager.getInstance().init(application);
  150 +
  151 + // MMKV 初始化
  152 + MMKV.initialize(application);
  153 + RKGlassDevice.getInstance().init(new OnGlassDeviceConnectListener() {
  154 + @Override
  155 + public void onGlassDeviceConnected(UsbDevice usbDevice) {
  156 + //Glass 设备连接成功
  157 + MutableLiveData<Boolean> connectStatus = new MutableLiveData();
  158 + connectStatus.setValue(true);
  159 + }
  160 +
  161 + @Override
  162 + public void onGlassDeviceDisconnected() {
  163 + //Glass 设备断开连接
  164 + }
  165 + });
  166 + // 网络请求框架初始化
  167 + OkHttpClient okHttpClient = new OkHttpClient.Builder()
  168 + .build();
  169 +
  170 + EasyConfig.with(okHttpClient)
  171 + // 是否打印日志
  172 + .setLogEnabled(AppConfig.isLogEnable())
  173 + // 设置服务器配置
  174 + .setServer(new RequestServer())
  175 + // 设置请求处理策略
  176 + .setHandler(new RequestHandler(application))
  177 + // 设置请求重试次数
  178 + .setRetryCount(1)
  179 + .setInterceptor((api, params, headers) -> {
  180 + // 添加全局请求头
  181 + headers.put("deviceOaid", UmengClient.getDeviceOaid());
  182 + headers.put("versionName", AppConfig.getVersionName());
  183 + headers.put("versionCode", String.valueOf(AppConfig.getVersionCode()));
  184 + headers.put("version", String.valueOf(AppConfig.getVersionCode()));
  185 + headers.put("client", "android");
  186 + headers.put("clienttype", "1");
  187 + headers.put("Authorization", UserManager.getInstance().getToken());
  188 + // 添加全局请求参数
  189 + })
  190 + .into();
  191 +
  192 + // 设置 Json 解析容错监听
  193 + GsonFactory.setJsonCallback((typeToken, fieldName, jsonToken) -> {
  194 + // 上报到 Bugly 错误列表
  195 + CrashReport.postCatchedException(new IllegalArgumentException(
  196 + "类型解析异常:" + typeToken + "#" + fieldName + ",后台返回的类型为:" + jsonToken));
  197 + });
  198 +
  199 + // 初始化日志打印
  200 + if (AppConfig.isLogEnable()) {
  201 + Timber.plant(new DebugLoggerTree());
  202 + }
  203 +
  204 + // 注册网络状态变化监听
  205 + ConnectivityManager connectivityManager = ContextCompat.getSystemService(application, ConnectivityManager.class);
  206 + if (connectivityManager != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
  207 + connectivityManager.registerDefaultNetworkCallback(new ConnectivityManager.NetworkCallback() {
  208 + @Override
  209 + public void onLost(@NonNull Network network) {
  210 + Timber.tag("网络状态").d("网络已断开连接");
  211 + toNoNetworkActivity();
  212 + }
  213 +
  214 + @Override
  215 + public void onUnavailable() {
  216 + Timber.tag("网络状态").d("网络连接超时或者网络连接不可达");
  217 + super.onUnavailable();
  218 + }
  219 +
  220 + @Override
  221 + public void onAvailable(@NonNull Network network) {
  222 + super.onAvailable(network);
  223 + Timber.tag("网络状态").d("网络连接成功");
  224 + boolean isConnected = NetworkUtils.isAvailableByPing();
  225 + Timber.tag("网络状态").d("网络连接:" + (isConnected ? "成功" : "失败"));
  226 + if (!isConnected) {
  227 + toNoNetworkActivity();
  228 + }
  229 + }
  230 + });
  231 + }
  232 + }
  233 +
  234 + private static void toNoNetworkActivity() {
  235 + Timber.tag("网络状态").d("跳转无网络");
  236 + Activity topActivity = ActivityManager.getInstance().getTopActivity();
  237 + if (!(topActivity instanceof LifecycleOwner)) {
  238 + return;
  239 + }
  240 + LifecycleOwner lifecycleOwner = ((LifecycleOwner) topActivity);
  241 + if (lifecycleOwner.getLifecycle().getCurrentState() != Lifecycle.State.RESUMED) {
  242 + return;
  243 + }
  244 + NoNetworkActivity.start(topActivity);
  245 + }
  246 +
  247 +
  248 + public static void initX5app(Context context) {
  249 + //设置非wifi条件下允许下载X5内核
  250 + QbSdk.setDownloadWithoutWifi(true);
  251 + HashMap map = new HashMap();
  252 + map.put(TbsCoreSettings.TBS_SETTINGS_USE_SPEEDY_CLASSLOADER, true);
  253 + map.put(TbsCoreSettings.TBS_SETTINGS_USE_DEXLOADER_SERVICE, true);
  254 + QbSdk.initTbsSettings(map);
  255 + //搜集本地tbs内核信息并上报服务器,服务器返回结果决定使用哪个内核。
  256 + QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() {
  257 + @Override
  258 + public void onCoreInitFinished() {
  259 +
  260 + }
  261 +
  262 + /**
  263 + * 预初始化结束
  264 + * 由于X5内核体积较大,需要依赖网络动态下发,所以当内核不存在的时候,默认会回调false,此时将会使用系统内核代替
  265 + * @param isX5 是否使用X5内核
  266 + */
  267 + @Override
  268 + public void onViewInitFinished(boolean isX5) {
  269 + Timber.d("x5内核%s", (isX5 ? "yes" : "no"));
  270 + }
  271 + };
  272 +
  273 + //x5内核初始化接口
  274 + QbSdk.initX5Environment(context, cb);
  275 + }
  276 +}
\ No newline at end of file
... ...
  1 +package com.studymachine.www.app;
  2 +
  3 +
  4 +import com.hjq.base.BaseFragment;
  5 +import com.studymachine.www.action.ToastAction;
  6 +import com.studymachine.www.http.model.HttpData;
  7 +import com.hjq.http.listener.OnHttpListener;
  8 +import com.studymachine.www.manager.EventBusManager;
  9 +
  10 +import okhttp3.Call;
  11 +
  12 +/**
  13 + * time : 2018/10/18
  14 + * desc : Fragment 业务基类
  15 + */
  16 +public abstract class AppFragment<A extends AppActivity> extends BaseFragment<A>
  17 + implements ToastAction, OnHttpListener<Object> {
  18 +
  19 +
  20 + @Override
  21 + protected void onFragmentResume(boolean first) {
  22 + super.onFragmentResume(first);
  23 + if(first){
  24 + EventBusManager.register(this);
  25 + }
  26 + }
  27 +
  28 + /**
  29 + * 当前加载对话框是否在显示中
  30 + */
  31 + public boolean isShowDialog() {
  32 + A activity = getAttachActivity();
  33 + if (activity == null) {
  34 + return false;
  35 + }
  36 + return activity.isShowDialog();
  37 + }
  38 +
  39 + /**
  40 + * 显示加载对话框
  41 + */
  42 + public void showDialog() {
  43 + A activity = getAttachActivity();
  44 + if (activity == null) {
  45 + return;
  46 + }
  47 + activity.showDialog();
  48 + }
  49 +
  50 + /**
  51 + * 隐藏加载对话框
  52 + */
  53 + public void hideDialog() {
  54 + A activity = getAttachActivity();
  55 + if (activity == null) {
  56 + return;
  57 + }
  58 + activity.hideDialog();
  59 + }
  60 +
  61 + /**
  62 + * {@link OnHttpListener}
  63 + */
  64 +
  65 + @Override
  66 + public void onStart(Call call) {
  67 + showDialog();
  68 + }
  69 +
  70 + @Override
  71 + public void onSucceed(Object result) {
  72 + if (!(result instanceof HttpData)) {
  73 + return;
  74 + }
  75 + toast(((HttpData<?>) result).getMessage());
  76 + }
  77 +
  78 + @Override
  79 + public void onFail(Exception e) {
  80 + toast(e.getMessage());
  81 + }
  82 +
  83 + @Override
  84 + public void onEnd(Call call) {
  85 + hideDialog();
  86 + }
  87 +
  88 + @Override
  89 + public void onDestroy() {
  90 + super.onDestroy();
  91 + EventBusManager.unregister(this);
  92 + }
  93 +}
\ No newline at end of file
... ...