Commit 8bbe0494 authored by wanglei's avatar wanglei

初始化

parent 77dc57b6
*.iml
.gradle
/local.properties
/.idea
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
/build
\ No newline at end of file
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
id("com.google.gms.google-services")
id("com.google.firebase.crashlytics")
}
android {
namespace = "com.base.pdfreaderallpdfreader"
compileSdk = 34
defaultConfig {
applicationId = "com.base.pdfreaderallpdfreader"
minSdk = 24
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
signingConfigs {
create("release") {
//E6:A2:DD:0A:E6:73:22:32:4E:98:08:78:73:29:01:C4:8D:A0:38:DB:D8:B2:DD:B9:AC:55:69:B2:6B:DF:B0:B4
storeFile = file("../smartcl.jks")
storePassword = "123456"
keyAlias = "key0"
keyPassword = "123456"
}
}
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
// 设置是否要自动上传
// firebaseCrashlytics {
// mappingFileUploadEnabled = true
// }
signingConfig = signingConfigs.getByName("release")
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
buildFeatures {
viewBinding = true
buildConfig = true
}
}
gradle.taskGraph.whenReady {
tasks.forEach { task ->
if (task.name.contains("uploadCrashlyticsMappingFile")) {
task.enabled = false
}
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.lifecycle.livedata.ktx)
implementation(libs.androidx.lifecycle.viewmodel.ktx)
implementation(libs.androidx.navigation.fragment.ktx)
implementation(libs.androidx.navigation.ui.ktx)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
//第三方UI
implementation("io.github.cymchad:BaseRecyclerViewAdapterHelper4:4.1.4")
implementation("com.github.angcyo.DslTablayout:TabLayout:3.5.5")
implementation("com.github.angcyo.DslTablayout:ViewPager2Delegate:3.5.5")
implementation("com.airbnb.android:lottie:6.4.0")
implementation("com.github.pokercc:ExpandableRecyclerView:0.9.3")
//mlkit
implementation("com.google.android.gms:play-services-mlkit-document-scanner:16.0.0-beta1")
//Pdf库
implementation("com.tom-roush:pdfbox-android:2.0.27.0")
// api(project(":pdflibrary"))
//
//Word库
//PPT库
//Excel库
// api(project(":library"))
//广告
implementation("com.google.android.gms:play-services-ads:23.1.0")
implementation("com.google.ads.mediation:applovin:12.4.3.0")
implementation("com.google.ads.mediation:facebook:6.17.0.0")
implementation("com.google.ads.mediation:mintegral:16.7.21.0")
implementation("com.google.ads.mediation:pangle:5.9.0.4.0")
//ump
implementation("com.google.android.ump:user-messaging-platform:3.0.0")
//firebase
implementation(platform("com.google.firebase:firebase-bom:32.3.1"))
implementation("com.google.firebase:firebase-messaging")
implementation("com.google.firebase:firebase-analytics-ktx")
implementation("com.google.firebase:firebase-crashlytics")
// implementation("com.google.firebase:firebase-database-ktx")
// implementation("com.google.firebase:firebase-config-ktx")
//facebook
implementation("com.facebook.android:facebook-android-sdk:[8,9)")
//网络请求和解析
implementation("com.google.code.gson:gson:2.11.0")
// define a BOM and its version
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.12.0"))
// define any required OkHttp artifacts without version
implementation("com.squareup.okhttp3:okhttp")
implementation("com.squareup.okhttp3:logging-interceptor")
//mintegral
implementation("com.reyun.solar.engine.oversea:solar-engine-core:1.2.8.3")
}
\ No newline at end of file
{
"project_info": {
"project_number": "618927174476",
"project_id": "scream-11bf5",
"storage_bucket": "scream-11bf5.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:618927174476:android:08858366fed11d3b2455e9",
"android_client_info": {
"package_name": "com.base.pdfreaderallpdfreader"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyDlEmOxb1M343Tv-FixB0ieQ3NQO0I3ibQ"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}
\ No newline at end of file
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
\ No newline at end of file
package com.base.pdfreaderallpdfreader
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.base.pdfreaderallpdfreader", appContext.packageName)
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<meta-data
android:name="com.google.mlkit.vision.DEPENDENCIES"
android:value="document_ui" />
<application
android:name=".helper.MyApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.PdfReaderAllPdfReader"
tools:targetApi="31">
<activity
android:name=".ui.document.DocumentActivity"
android:exported="false" />
<activity
android:name=".ui.search.SearchActivity"
android:exported="false" />
<activity
android:name=".ui.splash.SplashActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.main.MainActivity"
android:exported="false"
android:theme="@style/Theme.PdfReaderAllPdfReader.NoActionBar" />
<activity
android:name=".ui.language.LanguageActivity"
android:exported="false"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity" />
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-3940256099942544~3347511713" />
</application>
</manifest>
\ No newline at end of file
package com.base.pdfreaderallpdfreader.base
import android.app.Dialog
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.viewbinding.ViewBinding
import com.base.pdfreaderallpdfreader.bean.ConstObject.appLanguageSp
import com.base.pdfreaderallpdfreader.bean.ConstObject.changeLanguageSp
import com.base.pdfreaderallpdfreader.helper.EventHelper
import com.base.pdfreaderallpdfreader.ui.main.MainActivity
import com.base.pdfreaderallpdfreader.utils.ActivityLauncher
import com.base.pdfreaderallpdfreader.utils.ActivityManagerUtils
import com.base.pdfreaderallpdfreader.utils.LanguageUtils.changeAppLanguage
import com.base.pdfreaderallpdfreader.utils.LogEx
abstract class BaseActivity<T : ViewBinding> : AppCompatActivity() {
private val TAG = "BaseActivity"
protected abstract val binding: T
lateinit var launcher: ActivityLauncher
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
launcher = ActivityLauncher(this)
setContentView(binding.root)
EventHelper.event("page_${javaClass.simpleName}")
initView()
initListener()
}
protected abstract fun initView()
protected open fun initListener() {}
fun finishToMain() {
if (this !is MainActivity && !ActivityManagerUtils.getInstance().isActivityInStack(MainActivity::class.java)) {
startActivity(Intent(this, MainActivity::class.java))
}
finish()
}
var dialog: Dialog? = null
override fun onDestroy() {
super.onDestroy()
ActivityManagerUtils.getInstance().removeActivity(this)
if (dialog != null) {
dialog?.dismiss()
dialog = null
}
}
override fun onResume() {
super.onResume()
}
fun updateAppLanguage(
activityLanguage: String,
activityTag: String? = null,
activityChangeCallback: ((language: String) -> Unit)? = null
): Boolean {
LogEx.logDebug(
TAG,
"activityTag=$activityTag " +
"appLanguageSp=$appLanguageSp " +
"changeLanguageSp=$changeLanguageSp " +
"activityLanguage=$activityLanguage"
)
var isRecreate = false
if (appLanguageSp != changeLanguageSp || activityLanguage != changeLanguageSp) {
changeAppLanguage(this, changeLanguageSp)
// Restart the app
appLanguageSp = changeLanguageSp
activityChangeCallback?.invoke(changeLanguageSp)
LogEx.logDebug(TAG, "activityTag=$activityTag recreate")
isRecreate = true
//https://stackoverflow.com/questions/63209993/getting-lifecycle-exception-while-recreating-the-activity
//MIUI recreate
this@BaseActivity.recreate()
}
return isRecreate
}
fun checkNeedRecreate(activityLanguage: String): Boolean {
return appLanguageSp != changeLanguageSp || activityLanguage != changeLanguageSp
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.bean
import com.base.pdfreaderallpdfreader.utils.AppPreferences
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
object ConstObject {
const val MIME_TYPE_IMAGE = "image/*"
const val MIME_TYPE_VIDEO = "video/*"
const val MIME_TYPE_AUDIO = "audio/*"
const val MIME_TYPE_PDF = "application/pdf"
const val MIME_TYPE_DOC = "application/msword"
const val MIME_TYPE_DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
const val MIME_TYPE_XLS = "application/vnd.ms-excel"
const val MIME_TYPE_XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
const val MIME_TYPE_PPT = "application/vnd.ms-powerpoint"
const val MIME_TYPE_PPTX = "application/vnd.openxmlformats-officedocument.presentationml.presentation"
const val MIME_TYPE_APK = "application/vnd.android.package-archive"
const val MIME_TYPE_ZIP = "application/zip"
const val DO_SPLIT_PDF = "do_split_pdf"
const val DO_SAVE_PDF = "do_save_pdf"
const val DO_MERGE_PDF = "do_merge_pdf"
const val DO_LOCK_PDF = "do_lock_pdf"
const val DO_UNLOCK_PDF = "do_unlock_pdf"
const val DOCUMENT_DATA_TYPE = "document"
const val RECENT_DATA_TYPE = "recent"
const val BOOKMARK_DATA_TYPE = "bookmark"
const val UI_MODE_NORMAL = "ui_mode_normal"
const val UI_MODE_SELECT = "ui_mode_select"
const val UI_MODE_SEARCH = "ui_mode_search"
const val UI_SORT_LAST_MODIFIED = "ui_sort_last_modified"
const val UI_SORT_FINAL_MODIFIED = "ui_sort_final_modified"
const val UI_SORT_NAME_A_Z = "ui_sort_name_a_z"
const val UI_SORT_NAME_Z_A = "ui_sort_name_z_a"
const val NOTIFICATION_ACTION_LOG = "notification_action_log"
const val NOTIFICATION_ACTION_DOCUMENT = "notification_action_document"
const val NOTIFICATION_ACTION_BOOKMARK = "notification_action_bookmark"
const val NOTIFICATION_ACTION_NEW_IMAGE_PDF = "notification_action_new_image_pdf"
const val NOTIFICATION_ACTION_READ_PDF = "notification_action_read_pdf"
const val NOTIFICATION_ACTION_READ_DOCUMENTS = "notification_action_read_documents"
const val NOTIFICATION_ACTION_UN_VIEW_FILES = "notification_action_un_view_files"
const val NOTIFICATION_ACTION_IMPORTANT_DOCUMENT = "notification_action_important_document"
const val NOTIFICATION_ACTION_APP_PROCESS = "notification_action_app_process"
const val NOTIFICATION_ACTION_CLEAN_JUNK = "notification_action_clean_junk"
const val NOTIFICATION_ACTION_WEATHER = "notification_action_weather"
const val SHORTCUT_SCAN_PDF = "shortcut_scan_pdf"
const val SHORTCUT_SPLIT_PDF = "shortcut_split_pdf"
const val SHORTCUT_MERGE_PDF = "shortcut_merge_pdf"
const val FUNCTION_SCAM_JUNK = "function_scam_junk"
const val FUNCTION_APP_PROCESS = "function_app_process"
var ifAgreePrivacy = false
get() {
return AppPreferences.getInstance().getBoolean("ifAgreePrivacy", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("ifAgreePrivacy", value, true)
}
var haveSaveDemo = false
get() {
return AppPreferences.getInstance().getBoolean("haveSaveDemo", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("haveSaveDemo", value, true)
}
var haveGuideGesture = false
get() {
return AppPreferences.getInstance().getBoolean("haveGuideGesture", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("haveGuideGesture", value, true)
}
var appLanguageSp = Locale.ENGLISH.language
get() {
return AppPreferences.getInstance().getString("appLanguageSp", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("appLanguageSp", value, true)
}
var changeLanguageSp = appLanguageSp
get() {
return AppPreferences.getInstance().getString("changeLanguageSp", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("changeLanguageSp", value, true)
}
var haveSelectLanguage = false
get() {
return AppPreferences.getInstance().getBoolean("selectFollowLanguage", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("selectFollowLanguage", value, true)
}
var selectFollowLanguage = false
get() {
return AppPreferences.getInstance().getBoolean("selectFollowLanguage", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("selectFollowLanguage", value, true)
}
//是否第一次启动
var isFirstStart = true
get() {
return AppPreferences.getInstance().getBoolean("isFirstStart", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("isFirstStart", value, true)
}
//主页启动次数
var mainStartTimes = 0
get() {
return AppPreferences.getInstance().getInt("mainStartTimes", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("mainStartTimes", value, true)
}
var todayShowNotificationDialog = false
get() {
return AppPreferences.getInstance().getBoolean("todayShowNotificationDialog_${currentDate()}", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("todayShowNotificationDialog_${currentDate()}", value, true)
}
var setDefault = false
get() {
return AppPreferences.getInstance().getBoolean("setDefault", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("setDefault", value, true)
}
private fun currentDate(): String {
val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
val currentDate = Calendar.getInstance().time
return dateFormat.format(currentDate)
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.bean
import android.net.Uri
data class DocumentBean(
var path: String = "",
var uri: Uri = Uri.EMPTY,
var type: String = "",
var isBookmarked: Boolean = false,
) {
var uiType: Int = 0//0首页模式 1合并选择模式 2拆分模式 3解锁加锁模式 4搜索模式
var isSelect: Boolean = false
var state: Int = -1//0正常状态 1 锁定
var password: String = ""
var lastViewTime: Long = 0
var isAd: Boolean = false
companion object {
const val TYPE_PDF = "type_pdf"
const val TYPE_WORD = "type_word"
const val TYPE_EXCEL = "type_excel"
const val TYPE_PPT = "type_ppt"
}
}
package com.base.pdfreaderallpdfreader.bean
data class LanguageBean(
val key: String,
val language: String,
val country: String,
) {
var isSelect: Boolean = false
var isFollowSystem: Boolean = false
companion object {
const val English = "English"
const val 简体中文 = "简体中文"
const val português = "português"
const val Español = "Español "
const val Français = "Français"
const val Deutsch = "Deutsch"
const val ไทย = "ไทย"
const val Bahasa_Indonesia = "Bahasa Indonesia"
const val Melayu = "Melayu"
const val Tiếng_Việt = "Tiếng Việt"
const val 日本語 = "日本語"
const val Italiano = "Italiano"
const val 한국인 = "한국인"
const val Nederlands = "Nederlands"
const val 繁體中文 = "繁體中文"
const val Türk = "Türk"
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.bean
import android.net.Uri
data class MediaBean(
val path: String = "",
val uri: Uri = Uri.EMPTY,
val mimeType: String = ""
)
package com.base.pdfreaderallpdfreader.helper
import android.util.Base64
import java.security.SecureRandom
import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.SecretKeySpec
object AESHelper {
private const val aesKey = "7vwdrlk6bp8rihe4"
private val cipher by lazy {
Cipher.getInstance("AES/GCM/NoPadding")
}
fun encrypt(content: String): String {
try {
val iv = ByteArray(12).apply {
SecureRandom().nextBytes(this)
}
val contentBytes = content.toByteArray(Charsets.UTF_8)
val params = GCMParameterSpec(128, iv)
cipher.init(
Cipher.ENCRYPT_MODE,
secretKey, params
)
val encryptData = cipher.doFinal(contentBytes)
if (encryptData.size != contentBytes.size + 16) {
throw IllegalStateException("Encryption failed")
}
val message = ByteArray(12 + contentBytes.size + 16)
System.arraycopy(iv, 0, message, 0, 12)
System.arraycopy(encryptData, 0, message, 12, encryptData.size)
return String(Base64.encode(message, Base64.NO_WRAP), Charsets.UTF_8)
} catch (_: Exception) {
}
return content
}
@Synchronized
fun decrypt(content: String): String {
try {
val con = content.replace(" ".toRegex(), "+")
val contentByte = Base64.decode(con, Base64.NO_WRAP)
require(contentByte.size >= 12 + 16)
val params = GCMParameterSpec(128, contentByte, 0, 12)
cipher.init(
Cipher.DECRYPT_MODE,
secretKey, params
)
val decryptData = cipher.doFinal(contentByte, 12, contentByte.size - 12)
return String(decryptData, Charsets.UTF_8)
} catch (_: Exception) {
}
return content
}
private val secretKey by lazy {
SecretKeySpec(aesKey.toByteArray(), "AES")
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.helper
import com.base.pdfreaderallpdfreader.ui.splash.SplashActivity
object ConfigHelper {
const val privacyPolicy: String = "https://sites.google.com/view/pdf-reader-scan/pdf-reader"
const val termService: String = "https://sites.google.com/view/term-of-service-s/term-of-service"
// 正式包名
const val packageName = "com.lol.pdfscanner.libstdc.chovey"
// 域名
const val eventUrl = "https://rp.gamexzonerk.xyz"
const val apiUrl = "https://api.gamexzonerk.xyz"
//admob test id
const val openAdmobIdTest = "ca-app-pub-3940256099942544/9257395921"
const val bannerAdmobIdTest = "ca-app-pub-3940256099942544/9214589741"
const val interAdmobIdTest = "ca-app-pub-3940256099942544/1033173712"
const val nativeAdmobIdTest = "ca-app-pub-3940256099942544/2247696110"
// admob广告id
const val interAdmobId = "ca-app-pub-3940256099942544/1033173111"
const val nativeAdmobId = "ca-app-pub-3940256099942544/2247696111"
const val openAdmobId = "/6499/example/app-open"
const val bannerAdmobId = "ca-app-pub-3940256099942544/9214581111"
val noLoadingActivities = listOf(
"full", // 过滤全屏广告
"adActivity",
"AdActivity",
"AppLovinFullscreenActivity",
SplashActivity::class.java.simpleName,
"GmsDocumentScanningDelegateActivity",
// 返回前台时不跳转启动页的 activity
)
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.helper
import android.os.Build
import com.base.pdfreaderallpdfreader.bean.ConstObject.ifAgreePrivacy
import com.base.pdfreaderallpdfreader.helper.ReportUtils.doPost
import com.base.pdfreaderallpdfreader.utils.AppPreferences
import com.base.pdfreaderallpdfreader.utils.LogEx
import org.json.JSONException
import org.json.JSONObject
object EventHelper {
private val TAG = "EventUtils"
fun event(
key: String,
value: String? = null,
ext: JSONObject? = null,
isSingleEvent: Boolean = false
) {
if (!ifAgreePrivacy) {
return
}
if (isSingleEvent) {
val stringSet = AppPreferences.getInstance().getStringSet("singleEvent", setOf())
if (stringSet.contains(key)) {
return
}
}
Thread {
var paramJson: String? = ""
try {
val pkg = ConfigHelper.packageName
val s = JSONObject()
.put("action", key)
.put("value", value)
.put("ext", ext)
val s2 = getBp()
val data = JSONObject()
.put("data", s)
.put("bp", s2)
.toString()
LogEx.logDebug(TAG, "uuid=${AppPreferences.getInstance().getString("uuid", "")}")
LogEx.logDebug(TAG, "gid=${AppPreferences.getInstance().getString("gid", "")}")
paramJson = AESHelper.encrypt(data)
} catch (e: JSONException) {
paramJson = ""
}
LogEx.logDebug(TAG, "url=$url")
doPost(
url,
HashMap(),
paramJson
)
}.start()
}
private val url by lazy {
val pkg = ConfigHelper.packageName
val url = StringBuilder(
"${ConfigHelper.eventUrl}/${
pkg.filter { it.isLowerCase() }.substring(4, 9)
}sp"
)
url.append("?pkg=$pkg")
url.toString()
}
fun getBp(): JSONObject {
val pkg = ConfigHelper.packageName
val s2 = JSONObject()
.put("${pkg}_3", AppPreferences.getInstance().getString("Equipment", ""))
.put("${pkg}_4", AppPreferences.getInstance().getString("Manufacturer", ""))
.put("${pkg}_5", Build.VERSION.SDK_INT)
.put("${pkg}_9", AppPreferences.getInstance().getString("uuid", ""))
.put("${pkg}_10", AppPreferences.getInstance().getString("gid", ""))
.put("${pkg}_13", "android")
.put("${pkg}_15", "google")
// .put("${pkg}_14", BuildConfig.VERSION_CODE)
// .put("${pkg}_8", BuildConfig.VERSION_NAME)
// .put("${pkg}_24", BuildConfig.BUILD_TYPE)
return s2
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.helper
import android.app.Activity
import android.app.Application
import android.content.Intent
import android.os.Bundle
import android.text.TextUtils
import com.base.pdfreaderallpdfreader.ui.splash.SplashActivity
import com.base.pdfreaderallpdfreader.utils.ActivityManagerUtils
import com.base.pdfreaderallpdfreader.utils.AppPreferences
import com.base.pdfreaderallpdfreader.utils.LogEx
import com.facebook.FacebookSdk
import com.tom_roush.pdfbox.android.PDFBoxResourceLoader
import java.util.Locale
import java.util.UUID
class MyApplication : Application() {
private val TAG = "MyApplication"
var uuid = ""
companion object {
lateinit var context: MyApplication
var splashLanguage: String = Locale.getDefault().language
var mainLanguage: String = Locale.getDefault().language
var setLanguage: String = Locale.getDefault().language
var feedbackLanguage: String = Locale.getDefault().language
var pptLanguage: String = Locale.getDefault().language
var pdfLanguage: String = Locale.getDefault().language
var pdfLoadingLanguage: String = Locale.getDefault().language
var pdfMergeLanguage: String = Locale.getDefault().language
var pdfSelectLanguage: String = Locale.getDefault().language
var pdfSplitLanguage: String = Locale.getDefault().language
var wordLanguage: String = Locale.getDefault().language
@JvmField
var PAUSED_VALUE = 0
}
override fun onCreate() {
super.onCreate()
context = this
initUUid()
initApp()
PDFBoxResourceLoader.init(applicationContext)
// initWeather()
}
// private fun initWeather() {
// requestWeatherData()
// }
private fun initUUid() {
uuid = AppPreferences.getInstance().getString("uuid", "")
if (TextUtils.isEmpty(uuid)) {
uuid = UUID.randomUUID().toString() + System.currentTimeMillis()
AppPreferences.getInstance().put("uuid", uuid)
LogEx.logDebug(TAG, "uuid=$uuid")
}
}
fun initApp() {
// SolarEngineManager.getInstance().preInit(context, "81a11caa4076cd7c")
// FacebookSdk.sdkInitialize(applicationContext)
// var topicNumber = System.currentTimeMillis().toFormatMinute()
// LogEx.logDebug(TAG, "topicNumber=$topicNumber")
// if (topic_number.isNotEmpty()) {
// topicNumber = topic_number
// } else {
// topic_number = topicNumber
// }
// val topic = ConfigHelper.packageName + "_push_$topicNumber"
val topic = ConfigHelper.packageName + "_push"
LogEx.logDebug(TAG, "topic=${topic}")
// FCMManager.initFirebase(this)
// FCMManager.subscribeToTopic(topic)
// InstallHelps.init()
initLifeListener()
// ScreenStatusReceiver.setupScreenStatusListener(this)
}
// fun initSolarEngine(gdprDeny: Boolean = false) {
//
// val configBuilder = SolarEngineConfig.Builder()
//
// if (BuildConfig.DEBUG) {
// configBuilder.logEnabled() //开启本地调试日志
// }
// if (gdprDeny) {
// configBuilder.isGDPRArea = true
// configBuilder.adPersonalizationEnabled = true
// configBuilder.adUserDataEnabled = true
// }
// configBuilder.isCoppaEnabled = true
// configBuilder.setKidsAppEnabled(true)
// configBuilder.fbAppID = ""
//
// val config = configBuilder.build()
//
// SolarEngineManager.getInstance().initialize(context, "81a11caa4076cd7c", config,
// OnInitializationCallback { code ->
// if (code == 0) {
// //初始化成功
// config.setOnAttributionListener(object : OnAttributionListener {
// override fun onAttributionSuccess(attribution: JSONObject) {
// //获取归因结果成功时执行的动作
// LogEx.logDebug(TAG, "attribution=$attribution")
// EventHelper.event("install_referrer", attribution.toString())
// }
//
// override fun onAttributionFail(errorCode: Int) {
// //获取归因结果失败时执行的动作
// EventHelper.event("SolarEngineManager onAttributionFail errorCode=$errorCode")
// }
// })
// } else {
// //初始化失败,具体失败原因参考下方code码释义
// EventHelper.event("SolarEngineManager init error code=$code")
// }
// })
// }
private var lastTimePause = 0L
private var lastTimeResume = 0L
private fun isHotLaunch(): Boolean {
if ((lastTimeResume - lastTimePause) > 5000) {
return true
}
return false
}
private fun initLifeListener() {
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
private var count = 0
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
ActivityManagerUtils.getInstance().addActivity(activity)
}
override fun onActivityStarted(activity: Activity) {
count++
lastTimeResume = System.currentTimeMillis()
if (count == 1 && isHotLaunch()) {
val topActivity: Activity? = ActivityManagerUtils.getInstance().topActivity
val flag = if (topActivity == null) {
true
} else {
ConfigHelper.noLoadingActivities.all { !topActivity.localClassName.contains(it, true) }
}
LogEx.logDebug(TAG, "flag=$flag" + " activity:" + activity.localClassName)
if (flag) {
topActivity?.startActivity(
Intent(
topActivity, SplashActivity::class.java
).apply {
putExtra("isHotLaunch", true)
putExtra("type", -1)
})
}
}
lastTimeResume = 0
}
override fun onActivityResumed(activity: Activity) {
// LogEx.logDebug(TAG, "onActivityResumed")
PAUSED_VALUE = 1
}
override fun onActivityPaused(activity: Activity) {
// LogEx.logDebug(TAG, "onActivityPaused")
PAUSED_VALUE = 2
lastTimePause = System.currentTimeMillis()
}
override fun onActivityStopped(activity: Activity) {
count--
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityDestroyed(activity: Activity) {
ActivityManagerUtils.getInstance().removeActivity(activity)
}
})
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.helper;
import android.text.TextUtils;
import com.base.pdfreaderallpdfreader.utils.LogEx;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
public class ReportUtils {
private static String TAG = "ReportUtils";
public static String doPost(String urlPath, Map<String, String> paramsMap, String json) {
try {
HttpURLConnection conn = (HttpURLConnection) new URL(urlPath).openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setConnectTimeout(600000);
if (!TextUtils.isEmpty(json)) {
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Content-Length", Integer.toString(json.getBytes().length));
conn.getOutputStream().write(json.getBytes());
}
StringBuilder result = new StringBuilder();
for (Map.Entry<String, String> entry : paramsMap.entrySet()) {
result.append("&").append(entry.getKey()).append("=").append(entry.getValue());
}
if (result.length() > 0) {
conn.getOutputStream().write(result.substring(1).getBytes());
} else {
// conn.getOutputStream().write(result.substring(0).getBytes());
}
if (conn.getResponseCode() == 200) {
String s = new BufferedReader(new InputStreamReader(conn.getInputStream())).readLine();
if (!TextUtils.isEmpty(s)) {
} else {
s = "";
}
LogEx.INSTANCE.logDebug(TAG, "code=200", false);
return s;
} else {
LogEx.INSTANCE.logDebug(TAG, "code!=200", false);
}
} catch (Exception e) {
e.printStackTrace();
}
return "{ \"success\": false,\n \"errorMsg\": \"后台服务器开小差了!\",\n \"result\":{}}";
}
}
package com.base.pdfreaderallpdfreader.ui.document
import android.graphics.Color
import android.text.Spannable
import android.text.SpannableString
import android.text.style.ForegroundColorSpan
import androidx.activity.addCallback
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import com.angcyo.tablayout.delegate2.ViewPager2Delegate
import com.base.pdfreaderallpdfreader.R
import com.base.pdfreaderallpdfreader.base.BaseActivity
import com.base.pdfreaderallpdfreader.bean.DocumentBean
import com.base.pdfreaderallpdfreader.databinding.ActivityDocumentBinding
import com.base.pdfreaderallpdfreader.utils.BarUtils
class DocumentActivity : BaseActivity<ActivityDocumentBinding>() {
private lateinit var documentViewModel: DocumentViewModel
override val binding: ActivityDocumentBinding by lazy {
ActivityDocumentBinding.inflate(layoutInflater)
}
private val allPage: DocumentFragment by lazy {
DocumentFragment("All")
}
private val pdfPage: DocumentFragment by lazy {
DocumentFragment(DocumentBean.TYPE_PDF)
}
private val wordPage: DocumentFragment by lazy {
DocumentFragment(DocumentBean.TYPE_WORD)
}
private val excelPage: DocumentFragment by lazy {
DocumentFragment(DocumentBean.TYPE_EXCEL)
}
private val pptPage: DocumentFragment by lazy {
DocumentFragment(DocumentBean.TYPE_PPT)
}
private val fragments by lazy {
mutableListOf(allPage, pdfPage, wordPage, excelPage, pptPage)
}
override fun initView() {
BarUtils.setStatusBarLightMode(this, true)
BarUtils.setStatusBarColor(this, Color.WHITE)
binding.root.updatePadding(top = BarUtils.getStatusBarHeight())
documentViewModel = ViewModelProvider(this)[DocumentViewModel::class.java]
val spannableString = SpannableString(this.getString(R.string.pdf_reader))
spannableString.setSpan(ForegroundColorSpan(Color.parseColor("#E20001")), 0, 3, Spannable.SPAN_INCLUSIVE_INCLUSIVE)
binding.tvTittle.text = spannableString
initViewPager2()
initTabLayout()
}
private var pageAdapter: FragmentStateAdapter? = null
private fun initViewPager2() {
pageAdapter = object : FragmentStateAdapter(this) {
override fun getItemCount(): Int {
return fragments.size
}
override fun createFragment(position: Int): Fragment {
return fragments[position]
}
}
binding.viewPager2.run {
isUserInputEnabled = true
//https://www.jianshu.com/p/f69bd30cf5b0
//FragmentStateAdapter 这里必须传人fragment
adapter = pageAdapter
}
binding.viewPager2.registerOnPageChangeCallback(object :
ViewPager2.OnPageChangeCallback() {
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels)
}
override fun onPageSelected(position: Int) {
}
})
}
private fun initTabLayout() {
val allColor = Color.parseColor("#2287FE")
val pdfColor = Color.parseColor("#F40000")
val wordColor = Color.parseColor("#2287FE")
val excelColor = Color.parseColor("#1ABE5D")
val pptColor = Color.parseColor("#FF9E0E")
val deselectColor = Color.parseColor("#8F8F8F")
binding.tabLayoutDocument.apply {
configTabLayoutConfig {
tabDeselectColor = deselectColor
onSelectIndexChange = { fromIndex, selectIndexList, reselect, fromUser ->
val toIndex = selectIndexList.first()
binding.viewPager2.currentItem = toIndex
when (toIndex) {
0 -> {
tabSelectColor = allColor
tabIndicator.indicatorColor = allColor
}
1 -> {
tabSelectColor = pdfColor
tabIndicator.indicatorColor = pdfColor
}
2 -> {
tabSelectColor = wordColor
tabIndicator.indicatorColor = wordColor
}
3 -> {
tabSelectColor = excelColor
tabIndicator.indicatorColor = excelColor
}
4 -> {
tabSelectColor = pptColor
tabIndicator.indicatorColor = pptColor
}
}
dslSelector.updateStyle()
}
}
}
ViewPager2Delegate.install(binding.viewPager2, binding.tabLayoutDocument)
}
override fun initListener() {
super.initListener()
onBackPressedDispatcher.addCallback {
finishToMain()
}
binding.flFanhui.setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.document
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.lifecycleScope
import com.base.pdfreaderallpdfreader.bean.DocumentBean
import com.base.pdfreaderallpdfreader.bean.DocumentBean.Companion.TYPE_EXCEL
import com.base.pdfreaderallpdfreader.bean.DocumentBean.Companion.TYPE_PDF
import com.base.pdfreaderallpdfreader.bean.DocumentBean.Companion.TYPE_PPT
import com.base.pdfreaderallpdfreader.bean.DocumentBean.Companion.TYPE_WORD
import com.base.pdfreaderallpdfreader.databinding.FragmentDocumentBinding
import com.base.pdfreaderallpdfreader.ui.main.DocumentAdapter
import com.base.pdfreaderallpdfreader.ui.main.getAllDocument
import com.base.pdfreaderallpdfreader.ui.main.getExcelDocument
import com.base.pdfreaderallpdfreader.ui.main.getPdfDocument
import com.base.pdfreaderallpdfreader.ui.main.getPptDocument
import com.base.pdfreaderallpdfreader.ui.main.getWordDocument
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class DocumentFragment() : Fragment() {
private var type = TYPE_PDF
private lateinit var binding: FragmentDocumentBinding
private var adapter: DocumentAdapter? = null
constructor(type: String) : this() {
this.type = type
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentDocumentBinding.inflate(layoutInflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
adapter = DocumentAdapter()
binding.rv.adapter = adapter
}
override fun onResume() {
super.onResume()
if (type == TYPE_PDF) {
if (pdfNeedRefresh) {
pdfNeedRefresh = false
initData()
}
} else {
initData()
}
}
private fun initData() {
binding.swipeRefreshLayout.isRefreshing = true
lifecycleScope.launch(Dispatchers.IO) {
val list: List<DocumentBean>
when (type) {
TYPE_PDF -> {
list = getPdfDocument(requireContext())
}
TYPE_WORD -> {
list = getWordDocument(requireContext())
}
TYPE_EXCEL -> {
list = getExcelDocument(requireContext())
}
TYPE_PPT -> {
list = getPptDocument(requireContext())
}
else -> {
list = getAllDocument(requireContext())
}
}
launch(Dispatchers.Main) {
if (list.isEmpty()) {
binding.llEmpty.visibility = View.VISIBLE
adapter?.submitList(listOf())
} else {
binding.llEmpty.visibility = View.GONE
adapter?.submitList(list)
}
binding.swipeRefreshLayout.isRefreshing = false
}
}
}
companion object {
var pdfNeedRefresh: Boolean = true
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.document
import androidx.lifecycle.ViewModel
class DocumentViewModel : ViewModel() {
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.language
import android.graphics.Color
import androidx.activity.addCallback
import androidx.core.view.updatePadding
import com.base.pdfreaderallpdfreader.R
import com.base.pdfreaderallpdfreader.base.BaseActivity
import com.base.pdfreaderallpdfreader.bean.ConstObject
import com.base.pdfreaderallpdfreader.bean.ConstObject.appLanguageSp
import com.base.pdfreaderallpdfreader.bean.ConstObject.changeLanguageSp
import com.base.pdfreaderallpdfreader.bean.ConstObject.haveSelectLanguage
import com.base.pdfreaderallpdfreader.bean.LanguageBean
import com.base.pdfreaderallpdfreader.databinding.ActivityLanguageBinding
import com.base.pdfreaderallpdfreader.utils.BarUtils
import java.util.Locale
class LanguageActivity : BaseActivity<ActivityLanguageBinding>() {
override val binding: ActivityLanguageBinding by lazy {
ActivityLanguageBinding.inflate(layoutInflater)
}
private lateinit var adapter: LanguageAdapter
private var from: String = ""
override fun initView() {
BarUtils.setStatusBarLightMode(this, true)
BarUtils.setStatusBarColor(this, Color.WHITE)
binding.root.updatePadding(top = BarUtils.getStatusBarHeight())
from = intent.extras?.getString("from", "") ?: ""
adapter = LanguageAdapter()
binding.rv.adapter = adapter
// AdmobNativeUtils.showNativeAd(this, binding.flAd)
initData()
}
override fun initListener() {
super.initListener()
onBackPressedDispatcher.addCallback {
if (from == "Set") {
finish()
} else {
// startActivity(Intent(this@LanguageActivity, PermissionActivity::class.java))
finish()
}
}
binding.flFanhui.setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
binding.ivRight.setOnClickListener {
val item = adapter.items.find { it.isSelect }
val selectLanguage = item?.language ?: Locale.ENGLISH.language
if (changeLanguageSp != selectLanguage) {
changeLanguageSp = selectLanguage
}
ConstObject.selectFollowLanguage = item?.isFollowSystem == true
onBackPressedDispatcher.onBackPressed()
}
}
private fun initData() {
val list = listOf(
LanguageBean(
this.getString(R.string.follow_system),
Locale.getDefault().language,
Locale.getDefault().country
).apply { isFollowSystem = true },
LanguageBean(LanguageBean.English, Locale.ENGLISH.language, Locale.ENGLISH.country),
LanguageBean(LanguageBean.简体中文, Locale.SIMPLIFIED_CHINESE.language, Locale.SIMPLIFIED_CHINESE.country),
LanguageBean(LanguageBean.português, Locale("pt", "BR").language, Locale("pt", "BR").country),
LanguageBean(LanguageBean.Español, Locale("es").language, Locale("es").country),
LanguageBean(LanguageBean.Français, Locale.FRENCH.language, Locale.FRENCH.country),
LanguageBean(LanguageBean.Deutsch, Locale.GERMAN.language, Locale.GERMAN.country),
LanguageBean(LanguageBean.ไทย, Locale("th", "TH").language, Locale("th", "TH").country),
LanguageBean(LanguageBean.Bahasa_Indonesia, Locale("in", "ID").language, Locale("in", "ID").country),
LanguageBean(LanguageBean.Melayu, Locale("ms", "MY").language, Locale("ms", "MY").country),
LanguageBean(LanguageBean.Tiếng_Việt, Locale("vi", "VN").language, Locale("vi", "VN").country),
LanguageBean(LanguageBean.日本語, Locale.JAPAN.language, Locale.JAPAN.country),
LanguageBean(LanguageBean.Italiano, Locale.ITALY.language, Locale.ITALY.country),
LanguageBean(LanguageBean.한국인, Locale.KOREAN.language, Locale.KOREAN.country),
LanguageBean(LanguageBean.Nederlands, Locale("nl", "NL").language, Locale("nl", "NL").country),
LanguageBean(LanguageBean.繁體中文, Locale.TRADITIONAL_CHINESE.language, Locale.TRADITIONAL_CHINESE.country),
LanguageBean(LanguageBean.Türk, Locale("tr", "TR").language, Locale("tr", "TR").country),
)
if (ConstObject.selectFollowLanguage || !ConstObject.haveSelectLanguage) {
list.first().isSelect = true
} else {
list.findLast { it.language == appLanguageSp }?.isSelect = true
}
adapter.submitList(list)
haveSelectLanguage = true
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.language
import android.annotation.SuppressLint
import android.content.Context
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.base.pdfreaderallpdfreader.R
import com.base.pdfreaderallpdfreader.bean.LanguageBean
import com.base.pdfreaderallpdfreader.databinding.ItemLanguageSetBinding
import com.base.pdfreaderallpdfreader.utils.XmlEx.inflate
import com.chad.library.adapter4.BaseQuickAdapter
class LanguageAdapter : BaseQuickAdapter<LanguageBean, LanguageAdapter.LanguageViewHolder>() {
inner class LanguageViewHolder(view: View) : ViewHolder(view)
@SuppressLint("NotifyDataSetChanged")
override fun onBindViewHolder(holder: LanguageViewHolder, position: Int, item: LanguageBean?) {
item ?: return
val binding = ItemLanguageSetBinding.bind(holder.itemView)
binding.ivSelector.isSelected = item.isSelect
binding.tvLanguage.text = item.key
binding.root.setOnClickListener {
items.find { it.isSelect }?.isSelect = false
item.isSelect = true
notifyDataSetChanged()
}
}
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): LanguageViewHolder {
return LanguageViewHolder(R.layout.item_language_set.inflate(parent))
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.main
import android.annotation.SuppressLint
import android.content.Context
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.base.pdfreaderallpdfreader.R
import com.base.pdfreaderallpdfreader.bean.DocumentBean
import com.base.pdfreaderallpdfreader.bean.DocumentBean.Companion.TYPE_EXCEL
import com.base.pdfreaderallpdfreader.bean.DocumentBean.Companion.TYPE_PDF
import com.base.pdfreaderallpdfreader.bean.DocumentBean.Companion.TYPE_PPT
import com.base.pdfreaderallpdfreader.bean.DocumentBean.Companion.TYPE_WORD
import com.base.pdfreaderallpdfreader.databinding.ItemDocumentBinding
import com.base.pdfreaderallpdfreader.utils.KotlinExt.toFormatSize
import com.base.pdfreaderallpdfreader.utils.KotlinExt.toFormatTime5
import com.base.pdfreaderallpdfreader.utils.LogEx
import com.base.pdfreaderallpdfreader.utils.XmlEx.inflate
import com.chad.library.adapter4.BaseQuickAdapter
import java.io.File
class DocumentAdapter : BaseQuickAdapter<DocumentBean, DocumentAdapter.DocumentViewHolder>() {
private val TAG = "DocumentAdapter"
inner class DocumentViewHolder(view: View) : ViewHolder(view)
var moreAction: ((item: DocumentBean) -> Unit)? = null
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: DocumentViewHolder, position: Int, item: DocumentBean?) {
item ?: return
val binding = ItemDocumentBinding.bind(holder.itemView)
when (item.type) {
TYPE_PDF -> {
LogEx.logDebug(TAG, "pdf state = ${item.state}")
if (item.state == 0) {
binding.ivIcon.setImageResource(R.mipmap.r_pdf)
} else {
binding.ivIcon.setImageResource(R.mipmap.rv_pdf_lock)
}
}
TYPE_WORD -> {
binding.ivIcon.setImageResource(R.mipmap.rv_word)
}
TYPE_EXCEL -> {
binding.ivIcon.setImageResource(R.mipmap.rv_excel)
}
TYPE_PPT -> {
binding.ivIcon.setImageResource(R.mipmap.r_ppt)
}
}
val file = File(item.path)
binding.tvName.text = file.name
binding.tvInfo.text = file.lastModified().toFormatTime5() + " " + file.length().toFormatSize()
binding.flMore.setOnClickListener {
moreAction?.invoke(item)
}
}
override fun onCreateViewHolder(context: Context, parent: ViewGroup, viewType: Int): DocumentViewHolder {
return DocumentViewHolder(R.layout.item_document.inflate(parent))
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.main
import android.content.Context
import android.media.MediaScannerConnection
import android.net.Uri
import com.base.pdfreaderallpdfreader.bean.ConstObject
import com.base.pdfreaderallpdfreader.bean.ConstObject.MIME_TYPE_DOC
import com.base.pdfreaderallpdfreader.bean.ConstObject.MIME_TYPE_DOCX
import com.base.pdfreaderallpdfreader.bean.ConstObject.MIME_TYPE_PDF
import com.base.pdfreaderallpdfreader.bean.ConstObject.MIME_TYPE_PPT
import com.base.pdfreaderallpdfreader.bean.ConstObject.MIME_TYPE_PPTX
import com.base.pdfreaderallpdfreader.bean.ConstObject.MIME_TYPE_XLS
import com.base.pdfreaderallpdfreader.bean.ConstObject.MIME_TYPE_XLSX
import com.base.pdfreaderallpdfreader.bean.DocumentBean
import com.base.pdfreaderallpdfreader.bean.DocumentBean.Companion.TYPE_EXCEL
import com.base.pdfreaderallpdfreader.bean.DocumentBean.Companion.TYPE_PDF
import com.base.pdfreaderallpdfreader.bean.DocumentBean.Companion.TYPE_PPT
import com.base.pdfreaderallpdfreader.bean.DocumentBean.Companion.TYPE_WORD
import com.base.pdfreaderallpdfreader.bean.MediaBean
import com.base.pdfreaderallpdfreader.utils.AssetUtils.readByteArrayFromAsset
import com.base.pdfreaderallpdfreader.utils.PdfBoxUtils.checkPdfEncryption
import com.base.pdfreaderallpdfreader.utils.getMediaFile
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
fun Context.upDateDemoStore() {
val demoFile = File(filesDir, "demo")
MediaScannerConnection.scanFile(
this, arrayOf(demoFile.absolutePath), null
) { path: String?, uri: Uri? -> }
}
fun Context.saveAssetsFile() {
val demoFile = File(filesDir, "demo")
demoFile.mkdirs()
arrayOf(
"DEMO.pdf",
"DEMO.docx",
"DEMO.xlsx",
"DEMO.pptx"
).forEach {
val file = File(demoFile, it)
if (file.exists() && file.length() != 0L) {
return
}
file.createNewFile()
try {
FileOutputStream(file).use { fos -> fos.write(readByteArrayFromAsset(it)) }
} catch (e: IOException) {
e.printStackTrace()
}
}
}
fun getPdfDemo(context: Context): DocumentBean {
val demoDocumentBean = DocumentBean()
demoDocumentBean.type = TYPE_PDF
val demoFile = File(context.filesDir, "demo")
demoDocumentBean.path = demoFile.listFiles()?.find { it.name.contains(".pdf") }?.absolutePath ?: ""
context.pdfCheck(demoDocumentBean)
return demoDocumentBean
}
fun getWordDemo(context: Context): DocumentBean {
val demoDocumentBean = DocumentBean()
demoDocumentBean.type = TYPE_WORD
val demoFile = File(context.filesDir, "demo")
demoDocumentBean.path = demoFile.listFiles()?.find { it.name.contains(".docx") }?.absolutePath ?: ""
return demoDocumentBean
}
fun getExcelDemo(context: Context): DocumentBean {
val demoDocumentBean = DocumentBean()
demoDocumentBean.type = TYPE_EXCEL
val demoFile = File(context.filesDir, "demo")
demoDocumentBean.path = demoFile.listFiles()?.find { it.name.contains(".xlsx") }?.absolutePath ?: ""
return demoDocumentBean
}
fun getPPtDemo(context: Context): DocumentBean {
val demoDocumentBean = DocumentBean()
demoDocumentBean.type = TYPE_PPT
val demoFile = File(context.filesDir, "demo")
demoDocumentBean.path = demoFile.listFiles()?.find { it.name.contains(".pptx") }?.absolutePath ?: ""
return demoDocumentBean
}
fun getAllDocument(context: Context): MutableList<DocumentBean> {
context.upDateDemoStore()
if (!ConstObject.haveSaveDemo) {
context.saveAssetsFile()
ConstObject.haveSaveDemo = true
}
val selectionArgs = arrayOf(
MIME_TYPE_PDF,
MIME_TYPE_DOC,
MIME_TYPE_DOCX,
MIME_TYPE_XLS,
MIME_TYPE_XLSX,
MIME_TYPE_PPT,
MIME_TYPE_PPTX,
)
val list = context.getMediaFile(selectionArgs = selectionArgs)
val documentList = list.map {
val documentBean = DocumentBean(it.path, uri = it.uri, type = getDocumentType(it))
if (documentBean.type == TYPE_PDF) {
context.pdfCheck(documentBean)
}
documentBean
}
val new = documentList.toMutableList()
val pptDemo = getPPtDemo(context)
if (File(pptDemo.path).exists()) {
new.add(0, pptDemo)
}
val excelDemo = getExcelDemo(context)
if (File(excelDemo.path).exists()) {
new.add(0, excelDemo)
}
val wordDemp = getWordDemo(context)
if (File(wordDemp.path).exists()) {
new.add(0, wordDemp)
}
val pdfDemo = getPdfDemo(context)
if (File(pdfDemo.path).exists()) {
new.add(0, pdfDemo)
}
return new
}
fun getPdfDocument(context: Context): MutableList<DocumentBean> {
if (!ConstObject.haveSaveDemo) {
context.saveAssetsFile()
ConstObject.haveSaveDemo = true
}
val selectionArgs = arrayOf(
MIME_TYPE_PDF
)
val list = context.getMediaFile(selectionArgs = selectionArgs)
val documentList = list.map {
val demoDocumentBean = DocumentBean(it.path, uri = it.uri, type = TYPE_PDF)
context.pdfCheck(demoDocumentBean)
demoDocumentBean
}
val new = documentList.toMutableList()
val pdfDemo = getPdfDemo(context)
if (File(pdfDemo.path).exists()) {
new.add(0, pdfDemo)
}
return new
}
fun getWordDocument(context: Context): MutableList<DocumentBean> {
if (!ConstObject.haveSaveDemo) {
context.saveAssetsFile()
ConstObject.haveSaveDemo = true
}
val selectionArgs = arrayOf(
MIME_TYPE_DOC,
MIME_TYPE_DOCX,
)
val list = context.getMediaFile(selectionArgs = selectionArgs)
val documentList = list.map {
DocumentBean(it.path, uri = it.uri, type = TYPE_WORD)
}
val new = documentList.toMutableList()
val wordDemo = getWordDemo(context)
if (File(wordDemo.path).exists()) {
new.add(0, wordDemo)
}
return new
}
fun getExcelDocument(context: Context): MutableList<DocumentBean> {
if (!ConstObject.haveSaveDemo) {
context.saveAssetsFile()
ConstObject.haveSaveDemo = true
}
val selectionArgs = arrayOf(
MIME_TYPE_XLS,
MIME_TYPE_XLSX,
)
val list = context.getMediaFile(selectionArgs = selectionArgs)
val documentList = list.map {
DocumentBean(it.path, uri = it.uri, type = TYPE_EXCEL)
}
val new = documentList.toMutableList()
val excelDemo = getExcelDemo(context)
if (File(excelDemo.path).exists()) {
new.add(0, excelDemo)
}
return new
}
fun getPptDocument(context: Context): MutableList<DocumentBean> {
if (!ConstObject.haveSaveDemo) {
context.saveAssetsFile()
ConstObject.haveSaveDemo = true
}
val selectionArgs = arrayOf(
MIME_TYPE_PPT,
MIME_TYPE_PPTX,
)
val list = context.getMediaFile(selectionArgs = selectionArgs)
val documentList = list.map {
DocumentBean(it.path, uri = it.uri, type = TYPE_PPT)
}
val new = documentList.toMutableList()
val pptDemo = getPPtDemo(context)
if (File(pptDemo.path).exists()) {
new.add(0, pptDemo)
}
return new
}
fun recentFilter(recentList: List<String>, documentBean: DocumentBean) {
val findLastTime = recentList.filter { it.contains(documentBean.path) }.map {
it.split("_/_")[1].toLong()
}
if (findLastTime.isNotEmpty()) {
val max = findLastTime.max()
documentBean.lastViewTime = max
}
}
fun Context.pdfCheck(pdfDocumentBean: DocumentBean) {
pdfDocumentBean.state = this.checkPdfEncryption(pdfDocumentBean.path)
}
fun getDocumentType(mediaBean: MediaBean): String {
return if (mediaBean.path.endsWith(".pdf")) {
MIME_TYPE_PDF
} else if (mediaBean.path.endsWith(".doc") || mediaBean.path.endsWith(".docx")) {
TYPE_WORD
} else if (mediaBean.path.endsWith(".xls") || mediaBean.path.endsWith(".xlsx")) {
TYPE_EXCEL
} else if (mediaBean.path.endsWith(".ppt") || mediaBean.path.endsWith(".pptx")) {
TYPE_PPT
} else {
TYPE_PPT
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.main
import android.content.Intent
import android.graphics.Color
import android.text.Spannable
import android.text.SpannableString
import android.text.style.ForegroundColorSpan
import androidx.core.view.GravityCompat
import androidx.core.view.updatePadding
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.NavController
import androidx.navigation.findNavController
import com.base.pdfreaderallpdfreader.R
import com.base.pdfreaderallpdfreader.base.BaseActivity
import com.base.pdfreaderallpdfreader.databinding.ActivityMainBinding
import com.base.pdfreaderallpdfreader.ui.language.LanguageActivity
import com.base.pdfreaderallpdfreader.ui.search.SearchActivity
import com.base.pdfreaderallpdfreader.ui.view.MainDialog.showStoragePermission
import com.base.pdfreaderallpdfreader.utils.BarUtils
import com.base.pdfreaderallpdfreader.utils.PermissionUtils.checkStorePermission
class MainActivity : BaseActivity<ActivityMainBinding>() {
override val binding: ActivityMainBinding by lazy {
ActivityMainBinding.inflate(layoutInflater)
}
private lateinit var mainViewModel: MainViewModel
private lateinit var navController: NavController
override fun initView() {
mainViewModel = ViewModelProvider(this)[MainViewModel::class.java]
mainViewModel.initScannerLauncher(this)
mainViewModel.handleActivityGmsScanResult = { imageUri, pdfUri ->
}
BarUtils.setStatusBarLightMode(this, true)
BarUtils.setStatusBarColor(this, Color.WHITE)
binding.root.updatePadding(top = BarUtils.getStatusBarHeight())
navController = findNavController(R.id.nav_host_fragment_content_main)
val spannableString = SpannableString(this.getString(R.string.pdf_reader))
spannableString.setSpan(ForegroundColorSpan(Color.parseColor("#E20001")), 0, 3, Spannable.SPAN_INCLUSIVE_INCLUSIVE)
binding.includeMain.tvTittle.text = spannableString
binding.tvPdfReader.text = spannableString
if (!checkStorePermission()) {
showStoragePermission(launcher)
}
}
override fun initListener() {
super.initListener()
binding.includeMain.ivMenu.setOnClickListener {
binding.drawerLayout.openDrawer(GravityCompat.START)
}
binding.flFanhui.setOnClickListener {
binding.drawerLayout.closeDrawer(GravityCompat.START)
}
binding.includeMain.includeContentMain.llHome.setOnClickListener {
changeHomeUI()
}
binding.includeMain.includeContentMain.llHome.callOnClick()
binding.includeMain.includeContentMain.llRecent.setOnClickListener {
changeRecentUI()
}
binding.includeMain.includeContentMain.llBookmark.setOnClickListener {
changeBookMarkUI()
}
binding.llLanguage.setOnClickListener {
startActivity(Intent(this, LanguageActivity::class.java))
}
binding.includeMain.includeContentMain.ivScan.setOnClickListener {
starAdGmsScan()
}
binding.includeMain.ivSearch.setOnClickListener {
startActivity(Intent(this, SearchActivity::class.java))
}
}
private fun starAdGmsScan() {
// if (AdmobHelper.isShowScanInter() && AdmobHelper.canCommonShowAd()) {
// AdmobInterstitialUtils.showInterstitialAd(activity) {
// if (it) {
// lastScanShowAd = System.currentTimeMillis()
// }
// starGmsScan(activity)
// }
// } else {
mainViewModel.starGmsScan(this)
// }
}
private fun disSelectBottomNav() {
binding.includeMain.includeContentMain.ivHome.isSelected = false
binding.includeMain.includeContentMain.tvHome.isSelected = false
binding.includeMain.includeContentMain.ivRecent.isSelected = false
binding.includeMain.includeContentMain.tvRecent.isSelected = false
binding.includeMain.includeContentMain.ivBookmark.isSelected = false
binding.includeMain.includeContentMain.tvBookmark.isSelected = false
}
private fun changeBookMarkUI() {
disSelectBottomNav()
binding.includeMain.includeContentMain.ivBookmark.isSelected = true
binding.includeMain.includeContentMain.tvBookmark.isSelected = true
navController.popBackStack()
navController.navigate(R.id.nav_bookmarkFragment)
}
private fun changeRecentUI() {
disSelectBottomNav()
binding.includeMain.includeContentMain.ivRecent.isSelected = true
binding.includeMain.includeContentMain.tvRecent.isSelected = true
navController.popBackStack()
navController.navigate(R.id.nav_recentFragment)
}
private fun changeHomeUI() {
disSelectBottomNav()
binding.includeMain.includeContentMain.ivHome.isSelected = true
binding.includeMain.includeContentMain.tvHome.isSelected = true
navController.popBackStack()
navController.navigate(R.id.nav_homeFragment)
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.main
import android.app.Activity
import android.content.IntentSender
import android.net.Uri
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.IntentSenderRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModel
import com.google.mlkit.vision.documentscanner.GmsDocumentScannerOptions
import com.google.mlkit.vision.documentscanner.GmsDocumentScanning
import com.google.mlkit.vision.documentscanner.GmsDocumentScanningResult
class MainViewModel : ViewModel() {
private var scannerLauncher: ActivityResultLauncher<IntentSenderRequest>? = null
var handleActivityGmsScanResult: ((imageUri: Uri?, pdfUri: Uri?) -> Unit)? = null
private var scannerLauncherRegister: Boolean = false
fun initScannerLauncher(appCompatActivity: AppCompatActivity) {
scannerLauncher =
appCompatActivity.registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { activityResult ->
val resultCode = activityResult.resultCode
val result = GmsDocumentScanningResult.fromActivityResultIntent(activityResult.data)
// appCompatActivity.toast("回调1")
if (resultCode == Activity.RESULT_OK && result != null) {
val pages = result.pages
// appCompatActivity.toast("回调2 ${pages?.size}")
var imageUri = Uri.EMPTY
if (!pages.isNullOrEmpty()) {
// appCompatActivity.toast("回调3")
imageUri = pages[0].imageUri
}
val pdfUri = result.pdf?.uri ?: Uri.EMPTY
handleActivityGmsScanResult?.invoke(imageUri, pdfUri)
} else {
handleActivityGmsScanResult?.invoke(null, null)
}
}
scannerLauncherRegister = true
}
fun starGmsScan(activity: Activity) {
runCatching {
if (scannerLauncher == null && !scannerLauncherRegister) return
val options =
GmsDocumentScannerOptions.Builder()
.setScannerMode(GmsDocumentScannerOptions.SCANNER_MODE_BASE)
.setResultFormats(GmsDocumentScannerOptions.RESULT_FORMAT_PDF)
.setGalleryImportAllowed(true)
options.setScannerMode(GmsDocumentScannerOptions.SCANNER_MODE_FULL)
val pageLimit = 1
options.setPageLimit(pageLimit)
GmsDocumentScanning.getClient(options.build())
.getStartScanIntent(activity)
.addOnSuccessListener { intentSender: IntentSender ->
scannerLauncher?.launch(IntentSenderRequest.Builder(intentSender).build())
}
.addOnFailureListener { e: Exception ->
}
}
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.main
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.base.pdfreaderallpdfreader.R
class PermissionFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_permission, container, false)
}
companion object {
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.main.bookmark
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.base.pdfreaderallpdfreader.databinding.FragmentBookmarkBinding
import com.base.pdfreaderallpdfreader.ui.main.DocumentAdapter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class BookmarkFragment : Fragment() {
private var _binding: FragmentBookmarkBinding? = null
// onDestroyView.
private val binding get() = _binding!!
private lateinit var bookmarkViewModel: BookmarkViewModel
private var adapter: DocumentAdapter? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
bookmarkViewModel = ViewModelProvider(this)[BookmarkViewModel::class.java]
_binding = FragmentBookmarkBinding.inflate(inflater, container, false)
val root: View = binding.root
return root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
adapter = DocumentAdapter()
binding.rv.adapter = adapter
}
override fun onResume() {
super.onResume()
initData()
}
private fun initData() {
binding.swipeRefreshLayout.isRefreshing = true
lifecycleScope.launch(Dispatchers.IO) {
val recentList = bookmarkViewModel.getBookmarkDocument(requireContext())
launch(Dispatchers.Main) {
if (recentList.isEmpty()) {
binding.llEmpty.visibility = View.VISIBLE
adapter?.submitList(listOf())
} else {
binding.llEmpty.visibility = View.GONE
adapter?.submitList(recentList)
}
binding.swipeRefreshLayout.isRefreshing = false
}
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.main.bookmark
import android.content.Context
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.base.pdfreaderallpdfreader.bean.DocumentBean
import com.base.pdfreaderallpdfreader.bean.DocumentBean.Companion.TYPE_PDF
import com.base.pdfreaderallpdfreader.ui.main.getAllDocument
import com.base.pdfreaderallpdfreader.ui.main.pdfCheck
import com.base.pdfreaderallpdfreader.utils.SpStringUtils
import com.base.pdfreaderallpdfreader.utils.SpStringUtils.BOOKMARK_KEY
class BookmarkViewModel : ViewModel() {
private val _text = MutableLiveData<String>().apply {
value = "This is gallery Fragment"
}
val text: LiveData<String> = _text
fun getBookmarkDocument(context: Context): List<DocumentBean> {
val all = getAllDocument(context)
val bookmarkList = SpStringUtils.getSpStringList(BOOKMARK_KEY)
all.map {
if (it.type == TYPE_PDF) {
context.pdfCheck(it)
}
it.isBookmarked = bookmarkList.contains(it.path)
}
return all.filter { it.isBookmarked }
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.main.home
import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.text.Spannable
import android.text.SpannableString
import android.text.style.ForegroundColorSpan
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.base.pdfreaderallpdfreader.R
import com.base.pdfreaderallpdfreader.databinding.FragmentHomeBinding
import com.base.pdfreaderallpdfreader.ui.document.DocumentActivity
class HomeFragment : Fragment() {
private var _binding: FragmentHomeBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val homeViewModel =
ViewModelProvider(this).get(HomeViewModel::class.java)
_binding = FragmentHomeBinding.inflate(inflater, container, false)
val root: View = binding.root
return root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.clPdfReader.setOnClickListener {
startActivity(Intent(requireContext(), DocumentActivity::class.java))
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.main.home
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class HomeViewModel : ViewModel() {
private val _text = MutableLiveData<String>().apply {
value = "This is home Fragment"
}
val text: LiveData<String> = _text
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.main.recent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.base.pdfreaderallpdfreader.databinding.FragmentRecentBinding
import com.base.pdfreaderallpdfreader.ui.main.DocumentAdapter
import com.base.pdfreaderallpdfreader.utils.LogEx
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlin.random.Random
class RecentFragment() : Fragment() {
private val TAG = "RecentFragment"
private var _binding: FragmentRecentBinding? = null
private val binding get() = _binding!!
private lateinit var recentViewModel: RecentViewModel
private var adapter: DocumentAdapter? = null
var i = Random(100).nextInt()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
LogEx.logDebug(TAG, "onCreate $i")
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
recentViewModel = ViewModelProvider(this)[RecentViewModel::class.java]
_binding = FragmentRecentBinding.inflate(inflater, container, false)
val root: View = binding.root
return root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
adapter = DocumentAdapter()
binding.rv.adapter = adapter
}
override fun onResume() {
super.onResume()
initData()
}
private fun initData() {
// if (!recentNeedRefresh) return
// recentNeedRefresh = false
binding.swipeRefreshLayout.isRefreshing = true
lifecycleScope.launch(Dispatchers.IO) {
val recentList = recentViewModel.getRecentDocument(requireContext())
launch(Dispatchers.Main) {
if (recentList.isEmpty()) {
binding.llEmpty.visibility = View.VISIBLE
adapter?.submitList(listOf())
} else {
binding.llEmpty.visibility = View.GONE
adapter?.submitList(recentList)
}
binding.swipeRefreshLayout.isRefreshing = false
}
}
}
companion object {
var recentNeedRefresh = true
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
LogEx.logDebug(TAG, "onDestroyView $i")
}
override fun onDestroy() {
super.onDestroy()
LogEx.logDebug(TAG, "onDestroy $i")
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.main.recent
import android.content.Context
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.base.pdfreaderallpdfreader.bean.DocumentBean
import com.base.pdfreaderallpdfreader.bean.DocumentBean.Companion.TYPE_PDF
import com.base.pdfreaderallpdfreader.ui.main.getAllDocument
import com.base.pdfreaderallpdfreader.ui.main.pdfCheck
import com.base.pdfreaderallpdfreader.ui.main.recentFilter
import com.base.pdfreaderallpdfreader.utils.SpStringUtils
import com.base.pdfreaderallpdfreader.utils.SpStringUtils.LAST_VIEW_KEY
class RecentViewModel : ViewModel() {
private val _text = MutableLiveData<String>().apply {
value = "This is home Fragment"
}
val text: LiveData<String> = _text
fun getRecentDocument(context: Context): List<DocumentBean> {
val all = getAllDocument(context)
val recentList = SpStringUtils.getSpStringList(LAST_VIEW_KEY)
all.forEach {
if (it.type == TYPE_PDF) {
context.pdfCheck(it)
}
recentFilter(recentList, it)
}
return all.filter { it.lastViewTime != 0L }.sortedByDescending { it.lastViewTime }
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.search
import android.graphics.Color
import android.view.View
import android.view.inputmethod.EditorInfo
import androidx.activity.addCallback
import androidx.core.view.updatePadding
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.base.pdfreaderallpdfreader.base.BaseActivity
import com.base.pdfreaderallpdfreader.databinding.ActivitySearchBinding
import com.base.pdfreaderallpdfreader.databinding.ItemTabDocumentBinding
import com.base.pdfreaderallpdfreader.ui.main.DocumentAdapter
import com.base.pdfreaderallpdfreader.utils.BarUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class SearchActivity : BaseActivity<ActivitySearchBinding>() {
private lateinit var searchViewModel: SearchViewModel
private var adapter: DocumentAdapter? = null
override val binding: ActivitySearchBinding by lazy {
ActivitySearchBinding.inflate(layoutInflater)
}
override fun initView() {
BarUtils.setStatusBarLightMode(this, true)
BarUtils.setStatusBarColor(this, Color.WHITE)
binding.root.updatePadding(top = BarUtils.getStatusBarHeight())
searchViewModel = ViewModelProvider(this)[SearchViewModel::class.java]
adapter = DocumentAdapter()
binding.rv.adapter = adapter
arrayOf("All", "PDF", "Word", "Excel", "PPT").forEach { tab ->
val tabBinding = ItemTabDocumentBinding.inflate(layoutInflater)
tabBinding.tv.text = tab
binding.tabLayout.addView(tabBinding.root)
}
binding.tabLayout.observeIndexChange { fromIndex, toIndex, reselect, fromUser ->
if (!reselect) {
when (toIndex) {
0 -> searchViewModel.searchMode = SEARCH_MODE_ALL
1 -> searchViewModel.searchMode = SEARCH_MODE_PDF
2 -> searchViewModel.searchMode = SEARCH_MODE_WORD
3 -> searchViewModel.searchMode = SEARCH_MODE_EXCEL
4 -> searchViewModel.searchMode = SEARCH_MODE_PPT
}
searchDocument()
}
}
binding.edit.setOnEditorActionListener { v, actionId, event ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
if (binding.edit.text.isNotEmpty()) {
searchDocument()
}
}
false
}
searchDocument()
}
override fun initListener() {
super.initListener()
onBackPressedDispatcher.addCallback {
finishToMain()
}
binding.flFanhui.setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
}
private fun searchDocument() {
val search = binding.edit.text.toString()
lifecycleScope.launch(Dispatchers.IO) {
val result = searchViewModel.getSearchDocument(this@SearchActivity, search)
launch(Dispatchers.Main) {
if (result.isEmpty()) {
binding.llEmpty.visibility = View.VISIBLE
adapter?.submitList(listOf())
} else {
binding.llEmpty.visibility = View.GONE
adapter?.submitList(result)
}
}
}
}
companion object {
var SEARCH_MODE_ALL = "search_mode_all"
var SEARCH_MODE_PDF = "search_mode_pdf"
var SEARCH_MODE_WORD = "search_mode_word"
var SEARCH_MODE_EXCEL = "search_mode_excel"
var SEARCH_MODE_PPT = "search_mode_ppt"
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.search
import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.base.pdfreaderallpdfreader.bean.DocumentBean
import com.base.pdfreaderallpdfreader.bean.DocumentBean.Companion.TYPE_EXCEL
import com.base.pdfreaderallpdfreader.bean.DocumentBean.Companion.TYPE_PDF
import com.base.pdfreaderallpdfreader.bean.DocumentBean.Companion.TYPE_PPT
import com.base.pdfreaderallpdfreader.bean.DocumentBean.Companion.TYPE_WORD
import com.base.pdfreaderallpdfreader.ui.main.getAllDocument
import com.base.pdfreaderallpdfreader.ui.search.SearchActivity.Companion.SEARCH_MODE_ALL
import com.base.pdfreaderallpdfreader.ui.search.SearchActivity.Companion.SEARCH_MODE_EXCEL
import com.base.pdfreaderallpdfreader.ui.search.SearchActivity.Companion.SEARCH_MODE_PDF
import com.base.pdfreaderallpdfreader.ui.search.SearchActivity.Companion.SEARCH_MODE_PPT
import com.base.pdfreaderallpdfreader.ui.search.SearchActivity.Companion.SEARCH_MODE_WORD
import java.io.File
import java.util.Locale
class SearchViewModel : ViewModel() {
var searchMode = SEARCH_MODE_ALL
fun getSearchDocument(context: Context, search: String): List<DocumentBean> {
val all = getAllDocument(context)
val typeList: List<DocumentBean>
when (searchMode) {
SEARCH_MODE_PDF -> {
typeList = all.filter { it.type == TYPE_PDF }
}
SEARCH_MODE_WORD -> {
typeList = all.filter { it.type == TYPE_WORD }
}
SEARCH_MODE_EXCEL -> {
typeList = all.filter { it.type == TYPE_EXCEL }
}
SEARCH_MODE_PPT -> {
typeList = all.filter { it.type == TYPE_PPT }
}
else -> typeList = all
}
typeList.filter {
File(it.path).name.lowercase(Locale.ENGLISH)
.contains(search.lowercase(Locale.ENGLISH))
}
return typeList
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.splash
import android.annotation.SuppressLint
import android.content.Intent
import com.base.pdfreaderallpdfreader.base.BaseActivity
import com.base.pdfreaderallpdfreader.databinding.ActivitySplashBinding
import com.base.pdfreaderallpdfreader.ui.main.MainActivity
@SuppressLint("CustomSplashScreen")
class SplashActivity : BaseActivity<ActivitySplashBinding>() {
override val binding: ActivitySplashBinding by lazy {
ActivitySplashBinding.inflate(layoutInflater)
}
override fun initView() {
startActivity(Intent(this, MainActivity::class.java))
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.ui.view
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import com.base.pdfreaderallpdfreader.R
import com.base.pdfreaderallpdfreader.databinding.DialogStoragePermissionBinding
import com.base.pdfreaderallpdfreader.utils.ActivityLauncher
import com.base.pdfreaderallpdfreader.utils.PermissionUtils.requestStoragePermission
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
object MainDialog {
fun Context.showStoragePermission(
launcher: ActivityLauncher,
launcherAction: ((flag: Boolean) -> Unit)? = null,
noLauncherAction: (() -> Unit)? = null,
dismissAction: (() -> Unit)? = null,
): BottomSheetDialog {
val dialog = BottomSheetDialog(this, R.style.BottomSheetDialog)
val binding = DialogStoragePermissionBinding.inflate(LayoutInflater.from(this))
dialog.setContentView(binding.root)
dialog.setCanceledOnTouchOutside(true)
dialog.show()
val parentView = binding.root.parent as View
val behavior = BottomSheetBehavior.from(parentView)
//展开
behavior.state = BottomSheetBehavior.STATE_EXPANDED
binding.tvAllow.setOnClickListener {
dialog.dismiss()
requestStoragePermission(launcher) {
launcherAction?.invoke(it)
}
}
dialog.setOnDismissListener {
dismissAction?.invoke()
}
return dialog
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.utils
import android.content.Intent
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultCaller
import androidx.activity.result.contract.ActivityResultContracts
class ActivityLauncher(activityResultCaller: ActivityResultCaller) {
//region 权限
private var permissionCallback: ActivityResultCallback<Map<String, Boolean>>? = null
private val permissionLauncher =
activityResultCaller.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result: Map<String, Boolean> ->
permissionCallback?.onActivityResult(result)
}
fun launch(
permissionArray: Array<String>,
permissionCallback: ActivityResultCallback<Map<String, Boolean>>?
) {
this.permissionCallback = permissionCallback
permissionLauncher.launch(permissionArray)
}
//endregion
//region intent跳转
private var activityResultCallback: ActivityResultCallback<ActivityResult>? = null
private val intentLauncher =
activityResultCaller.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult: ActivityResult ->
activityResultCallback?.onActivityResult(activityResult)
}
/**
* it.resultCode == Activity.RESULT_OK
*/
fun launch(
intent: Intent,
activityResultCallback: ActivityResultCallback<ActivityResult>? = null
) {
this.activityResultCallback = activityResultCallback
intentLauncher.launch(intent)
}
//endregion
//region saf
// private var safResultCallback: ActivityResultCallback<Uri?>? = null
// private val safLauncher =
// activityResultCaller.registerForActivityResult(
// ActivityResultContracts.OpenDocument(),
// ) { uri ->
// safResultCallback?.onActivityResult(uri)
// }
//
// fun launch(array: Array<String>, safResultCallback: ActivityResultCallback<Uri?>?) {
// this.safResultCallback = safResultCallback
// safLauncher.launch(array)
// }
//end region
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.utils;
import android.app.Activity;
import java.util.Stack;
public class ActivityManagerUtils {
private static ActivityManagerUtils instance;
private Stack<Activity> activityStack = new Stack<>();
private ActivityManagerUtils() {
}
public static ActivityManagerUtils getInstance() {
if (instance == null) {
instance = new ActivityManagerUtils();
}
return instance;
}
/**
* 添加Activity到堆栈
*/
public void addActivity(Activity activity) {
activityStack.add(activity);
}
/**
* 移除Activity从堆栈
*/
public void removeActivity(Activity activity) {
activityStack.remove(activity);
}
/**
* 获取当前Activity(堆栈中最后一个压入的)
*/
public Activity getCurrentActivity() {
return activityStack.lastElement();
}
/**
* 结束指定的Activity
*/
public void finishActivity(Activity activity) {
if (activity != null) {
activityStack.remove(activity);
activity.finish();
}
}
/**
* 结束所有Activity
*/
public void finishAllActivity() {
for (Activity activity : activityStack) {
if (activity != null) {
activity.finish();
}
}
activityStack.clear();
}
/**
* 检查Activity是否存在于堆栈中
*/
public boolean isActivityInStack(Class<?> cls) {
boolean isExist = false;
if (cls != null) {
for (Activity activity : activityStack) {
if (cls.equals(activity.getClass())) {
isExist = true;
break;
}
}
}
return isExist;
}
public Activity getTopActivity() {
if (activityStack.empty()) {
return null;
} else {
return activityStack.peek();
}
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.utils;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import com.base.pdfreaderallpdfreader.helper.MyApplication;
import java.util.Set;
/**
* @noinspection ALL, rawtypes, rawtypes
*/
public class AppPreferences {
private static AppPreferences sInstance;
private final SharedPreferences sharedPreferences;
private static final String PREF_FILE_NAME = "app_prefs"; // 偏好文件名
private AppPreferences(Context context) {
sharedPreferences = context.getSharedPreferences(PREF_FILE_NAME, Context.MODE_PRIVATE);
}
public static synchronized AppPreferences getInstance() {
if (sInstance == null) {
sInstance = new AppPreferences(MyApplication.context.getApplicationContext());
}
return sInstance;
}
// 通用 put 方法
public void put(String key, Object value) {
if (value instanceof Integer) {
sharedPreferences.edit().putInt(key, (Integer) value).apply();
} else if (value instanceof Long) {
sharedPreferences.edit().putLong(key, (Long) value).apply();
} else if (value instanceof Float) {
sharedPreferences.edit().putFloat(key, (Float) value).apply();
} else if (value instanceof Boolean) {
sharedPreferences.edit().putBoolean(key, (Boolean) value).apply();
} else if (value instanceof String) {
sharedPreferences.edit().putString(key, (String) value).apply();
} else if (value instanceof Double) {
sharedPreferences.edit().putString(key, (String) value.toString()).apply();
} else if (value instanceof Set) {
sharedPreferences.edit().putStringSet(key, (Set<String>) value).apply();
} else {
throw new IllegalArgumentException("Unsupported type: " + value.getClass());
}
}
@SuppressLint("ApplySharedPref")
public void put(String key, Object value, boolean isCommit) {
SharedPreferences.Editor editor = sharedPreferences.edit();
if (value instanceof Integer) {
editor.putInt(key, (Integer) value);
} else if (value instanceof Long) {
editor.putLong(key, (Long) value);
} else if (value instanceof Float) {
editor.putFloat(key, (Float) value);
} else if (value instanceof Boolean) {
editor.putBoolean(key, (Boolean) value);
} else if (value instanceof String) {
editor.putString(key, (String) value);
} else if (value instanceof Set) {
sharedPreferences.edit().putStringSet(key, (Set<String>) value).apply();
} else {
throw new IllegalArgumentException("Unsupported type: " + value.getClass());
}
// 根据 isCommit 参数的值决定使用 commit() 还是 apply()
if (isCommit) {
editor.commit();
} else {
editor.apply();
}
}
// 存入整数
public void putInt(String key, int value) {
sharedPreferences.edit().putInt(key, value).apply();
}
public void putStringSet(String key, Set value) {
sharedPreferences.edit().putStringSet(key, value).apply();
}
public Set<String> getStringSet(String key, Set<String> defaultValue) {
return sharedPreferences.getStringSet(key, defaultValue);
}
// 获取整数
public int getInt(String key, int defaultValue) {
return sharedPreferences.getInt(key, defaultValue);
}
// 存入长整数
public void putLong(String key, long value) {
sharedPreferences.edit().putLong(key, value).apply();
}
// 获取长整数
public long getLong(String key, long defaultValue) {
return sharedPreferences.getLong(key, defaultValue);
}
// 存入浮点数
public void putFloat(String key, float value) {
sharedPreferences.edit().putFloat(key, value).apply();
}
// 获取浮点数
public float getFloat(String key, float defaultValue) {
return sharedPreferences.getFloat(key, defaultValue);
}
// 存入布尔值
public void putBoolean(String key, boolean value) {
sharedPreferences.edit().putBoolean(key, value).apply();
}
// 获取布尔值
public boolean getBoolean(String key, boolean defaultValue) {
return sharedPreferences.getBoolean(key, defaultValue);
}
// 存入字符串
public void putString(String key, String value) {
sharedPreferences.edit().putString(key, value).apply();
}
// 获取字符串
public String getString(String key, String defaultValue) {
return sharedPreferences.getString(key, defaultValue);
}
// 检查某个键是否存在
public boolean contains(String key) {
return sharedPreferences.contains(key);
}
// 移除某个键
public void remove(String key) {
sharedPreferences.edit().remove(key).apply();
}
// 清除所有数据
public void clear() {
sharedPreferences.edit().clear().apply();
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.utils
import android.content.Context
import android.content.res.AssetManager
import java.io.BufferedReader
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.io.InputStreamReader
object AssetUtils {
fun Context.readByteArrayFromAsset(fileName: String): ByteArray {
val assetManager: AssetManager = this.assets
var ins: InputStream? = null
val byteStream = ByteArrayOutputStream()
try {
ins = assetManager.open(fileName)
var nextValue: Int
while (ins.read().also { nextValue = it } != -1) {
byteStream.write(nextValue)
}
} catch (e: IOException) {
e.printStackTrace()
} finally {
try {
ins?.close()
byteStream.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
return byteStream.toByteArray()
}
fun Context.getDemoPdf(): String {
val demoFile = File(filesDir, "demo")
demoFile.mkdirs()
val file = File(demoFile, "DEMO.pdf")
return file.absolutePath
}
fun Context.getDemoDocx(): String {
val demoFile = File(filesDir, "demo")
demoFile.mkdirs()
val file = File(demoFile, "DEMO.docx")
return file.absolutePath
}
fun Context.getDemoXlsx(): String {
val demoFile = File(filesDir, "demo")
demoFile.mkdirs()
val file = File(demoFile, "DEMO.xlsx")
return file.absolutePath
}
fun Context.getDemoPptx(): String {
val demoFile = File(filesDir, "demo")
demoFile.mkdirs()
val file = File(demoFile, "DEMO.pptx")
return file.absolutePath
}
fun Context.saveAssetsFile() {
val demoFile = File(filesDir, "demo")
demoFile.mkdirs()
arrayOf(
"DEMO.pdf",
"DEMO.docx",
"DEMO.xlsx",
"DEMO.pptx"
).forEach {
val file = File(demoFile, it)
if (file.exists() && file.length() != 0L) {
return
}
file.createNewFile()
try {
FileOutputStream(file).use { fos -> fos.write(readByteArrayFromAsset(it)) }
} catch (e: IOException) {
e.printStackTrace()
}
}
}
fun Context.readJsonFromAsset(fileName: String): String {
var json = ""
try {
val assetManager = this.assets
val inputStream = assetManager.open(fileName)
val reader = BufferedReader(InputStreamReader(inputStream))
var line: String?
val jsonString = StringBuilder()
while (reader.readLine().also { line = it } != null) {
jsonString.append(line)
}
reader.close()
inputStream.close()
json = jsonString.toString()
} catch (e: IOException) {
e.printStackTrace()
}
return json
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.utils
//noinspection SuspiciousImport
import android.app.Activity
import android.content.Context
import android.content.res.Resources
import android.graphics.Color
import android.os.Build
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.view.WindowManager
import androidx.annotation.ColorInt
object BarUtils {
fun setStatusBarLightMode(activity: Activity, isLightMode: Boolean) {
setStatusBarLightMode(activity.window, isLightMode)
}
private fun setStatusBarLightMode(window: Window, isLightMode: Boolean) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val decorView = window.decorView
var vis = decorView.systemUiVisibility
vis = if (isLightMode) {
vis or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
} else {
vis and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
}
decorView.systemUiVisibility = vis
}
}
fun setStatusBarColor(activity: Activity, @ColorInt color: Int): View? {
return setStatusBarColor(activity, color, false)
}
private fun setStatusBarColor(activity: Activity, @ColorInt color: Int, isDecor: Boolean): View? {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return null
transparentStatusBar(activity)
return applyStatusBarColor(activity, color, isDecor)
}
private fun applyStatusBarColor(activity: Activity, color: Int, isDecor: Boolean): View {
return applyStatusBarColor(activity.window, color, isDecor)
}
private fun transparentStatusBar(activity: Activity) {
transparentStatusBar(activity.window)
}
private fun transparentStatusBar(window: Window) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
val option = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
val vis = window.decorView.systemUiVisibility
window.decorView.systemUiVisibility = option or vis
window.statusBarColor = Color.TRANSPARENT
} else {
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
}
}
private fun applyStatusBarColor(window: Window, color: Int, isDecor: Boolean): View {
val parent =
if (isDecor) window.decorView as ViewGroup else (window.findViewById<View>(android.R.id.content) as ViewGroup)!!
var fakeStatusBarView =
parent.findViewWithTag<View>(TAG_STATUS_BAR)
if (fakeStatusBarView != null) {
if (fakeStatusBarView.visibility == View.GONE) {
fakeStatusBarView.visibility = View.VISIBLE
}
fakeStatusBarView.setBackgroundColor(color)
} else {
fakeStatusBarView = createStatusBarView(window.context, color)
parent.addView(fakeStatusBarView)
}
return fakeStatusBarView
}
private fun createStatusBarView(context: Context, color: Int): View {
val statusBarView = View(context)
statusBarView.layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight()
)
statusBarView.setBackgroundColor(color)
statusBarView.tag = TAG_STATUS_BAR
return statusBarView
}
///////////////////////////////////////////////////////////////////////////
// status bar
///////////////////////////////////////////////////////////////////////////
private const val TAG_STATUS_BAR = "TAG_STATUS_BAR"
fun getStatusBarHeight(): Int {
val resources = Resources.getSystem()
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
return resources.getDimensionPixelSize(resourceId)
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.utils
import java.text.SimpleDateFormat
import java.util.Locale
object KotlinExt {
fun Number.toFormatSize(count: Int = 1): String {
var suffix = "B"
var fSize = this.toDouble()
if (fSize > 1024) {
suffix = "KB"
fSize /= 1024.0
}
if (fSize > 1024) {
suffix = "MB"
fSize /= 1024.0
}
if (fSize > 1024) {
suffix = "GB"
fSize /= 1024.0
}
return String.format("%.${count}f %s", fSize, suffix)
}
fun Long.toFormatTime(): String {
return SimpleDateFormat("MMM dd,yyyy", Locale.ENGLISH).format(this)
}
fun Long.toFormatTime2(): String {
return SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(this)
}
fun Long.toFormatTime3(): String {
return SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH).format(this)
}
fun Long.toFormatTime4(): String {
return SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).format(this)
}
fun Long.toFormatTime5(): String {
return SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH).format(this)
}
fun Long.toFormatMinute(): String {
return SimpleDateFormat("mm", Locale.ENGLISH).format(this)
}
fun Array<String>.array2String(): String {
val stringBuilder = StringBuilder()
forEach {
stringBuilder.append(it)
}
return stringBuilder.toString()
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.utils
import android.content.Context
import android.os.LocaleList
import java.util.Locale
object LanguageUtils {
fun getSystemLanguage(): String {
return Locale.getDefault().language
}
val supportLanguage = listOf(
Locale.ENGLISH.language,
Locale.PRC.language,
Locale("pt", "BR").language,
Locale("es").language,
Locale.FRENCH.language,
Locale("de").language,
Locale("th", "TH").language,
Locale("in", "ID").language,
Locale("ms", "MY").language,
Locale("vi", "VN").language,
Locale("ja", "JP").language,
Locale("it", "IT").language,
Locale("ko", "KR").language,
Locale("nl", "NL").language,
Locale("zh", "TW").language,
Locale("tr", "TR").language
)
fun getSystemLanguageDefault(): String {
var systemLanguage = getSystemLanguage()
if (!supportLanguage.contains(systemLanguage)) {
systemLanguage = Locale.ENGLISH.language
}
return systemLanguage
}
fun isSupportSystemLanguage(): Boolean {
return supportLanguage.contains(getSystemLanguage())
}
fun changeAppLanguage(context: Context,language:String) {
val config = context.resources.configuration
val locale = Locale(language)
//Android 7.0以上的方法
config.setLocale(locale)
config.setLocales(LocaleList(locale))
context.createConfigurationContext(config)
context.resources.updateConfiguration(config, context.resources.displayMetrics)
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.utils
import android.util.Log
object LogEx {
val isOpen = true
val filterTAG = arrayOf(
"",
"MediaStoreUtils",
"DocumentFragment",
"EventUtils",
"ReportUtils",
// "NewComUtils",
)
fun logDebug(tag: String, content: String, isMust: Boolean = false) {
if (isMust) {
Log.e(tag, content)
} else {
if (!isOpen) return
if (filterTAG.contains(tag)) return
// if (BuildConfig.DEBUG) {
Log.e(tag, content)
// }
}
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.utils
import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.net.Uri
import com.base.pdfreaderallpdfreader.utils.UriUtils.readFileToByteArray
import com.tom_roush.pdfbox.pdmodel.PDDocument
import com.tom_roush.pdfbox.pdmodel.PDPage
import com.tom_roush.pdfbox.pdmodel.PDPageContentStream
import com.tom_roush.pdfbox.pdmodel.common.PDRectangle
import com.tom_roush.pdfbox.pdmodel.encryption.AccessPermission
import com.tom_roush.pdfbox.pdmodel.encryption.StandardProtectionPolicy
import com.tom_roush.pdfbox.pdmodel.graphics.image.PDImageXObject
import com.tom_roush.pdfbox.rendering.ImageType
import com.tom_roush.pdfbox.rendering.PDFRenderer
import com.tom_roush.pdfbox.rendering.RenderDestination
import java.io.File
import java.io.IOException
object PdfBoxUtils {
private val TAG = "PdfUtils"
fun Context.getNumberOfPages(filePath: String, password: String? = null, uri: String? = null): Int {
val document =
loadPDDocument(path = filePath, password, uri)
return document.numberOfPages
}
fun Context.getPdfDrawablePage(
context: Context,
filePath: String,
password: String? = null,
uri: String? = null,
pageIndex: Int,
scale: Float = 1f,
): Drawable {
val document = loadPDDocument(filePath, password, uri)
val renderer = PDFRenderer(document)
val bitmap: Bitmap = renderer.renderImage(pageIndex, scale, ImageType.RGB, RenderDestination.EXPORT)
val drawable = BitmapDrawable(context.resources, bitmap)
return drawable
}
fun Context.checkPdfEncryption(filePath: String = "", uri: String? = null): Int {
var state = 0
var pdfDocument: PDDocument? = null
try {
pdfDocument = loadPDDocument(filePath, null, uri)
pdfDocument.use { document ->
if (document.isEncrypted) {
println("The PDF is encrypted.")
val ap = document.getCurrentAccessPermission()
if (ap.canExtractContent()) {
println("You are allowed to extract content.")
} else {
state = 1
println("You are not allowed to extract content.")
}
if (ap.canPrint()) {
println("You are allowed to print the document.")
} else {
println("You are not allowed to print the document.")
state = 1
}
} else {
println("The PDF is not encrypted.")
state = 0
}
}
} catch (e: IOException) {
e.printStackTrace()
state = 1
} finally {
pdfDocument?.close()
}
return state
}
fun setPassword(
sourceFilePath: String,
userPassword: String,
ownerPassword: String
): Boolean {
try {
PDDocument.load(File(sourceFilePath)).use { document ->
val ap = AccessPermission()
ap.setCanPrint(false)
ap.setCanModify(false)
ap.setCanExtractContent(false)
ap.setCanExtractForAccessibility(false)
ap.setCanFillInForm(false)
val spp = StandardProtectionPolicy(userPassword, ownerPassword, ap)
document.protect(spp)
document.save(File(sourceFilePath))
LogEx.logDebug(TAG, "setPassword finish")
}
} catch (e: Exception) {
LogEx.logDebug(TAG, "setPassword Exception ${e.printStackTrace()}")
e.printStackTrace()
return false
}
return true
}
fun clearPassword(filePath: String, password: String) {
try {
PDDocument.load(File(filePath), password).use { document ->
if (document.isEncrypted) {
val ap: AccessPermission = document.getCurrentAccessPermission()
if (ap.isOwnerPermission) {
// 创建一个新的保护策略,不设置密码
val spp = StandardProtectionPolicy(
"", "",
AccessPermission.getOwnerAccessPermission()
)
document.protect(spp)
}
}
// 保存PDF文件到新的位置,没有密码保护
document.save(File(filePath))
}
} catch (e: IOException) {
e.printStackTrace()
}
}
fun Context.checkPwd(
filePath: String,
password: String,
uri: String? = null
): Boolean {
try {
val pdfDocument = loadPDDocument(filePath, password, uri)
// 尝试使用提供的密码加载PDF文件
pdfDocument.use { document ->
// 如果没有抛出异常,说明密码正确
return true
}
} catch (e: Exception) {
// 加载文件时,如果密码保护策略异常,密码可能错误
println("Incorrect password or restricted permissions.")
} catch (e: IOException) {
// 其他I/O异常处理
println("An I/O error occurred: " + e.message)
}
return false
}
private fun Context.loadPDDocument(path: String, password: String?, uri: String? = null): PDDocument {
return if (uri == null) {
if (password == null) {
PDDocument.load(File(path))
} else {
PDDocument.load(File(path), password)
}
} else {
if (password == null) {
PDDocument.load(readFileToByteArray(this, Uri.parse(uri)) ?: byteArrayOf())
} else {
PDDocument.load(readFileToByteArray(this, Uri.parse(uri)) ?: byteArrayOf(), password)
}
}
}
fun saveNewPdf(imagePath: String, savePath: String) {
try {
PDDocument().use { document ->
// 添加一个页面
val page = PDPage(PDRectangle.A4)
document.addPage(page)
// 加载图片
val image = PDImageXObject.createFromFile(imagePath, document)
// 计算图片在页面中的位置和尺寸
val x = (PDRectangle.A4.width - image.width) / 2
val y = (PDRectangle.A4.height - image.height) / 2
PDPageContentStream(document, page).use { contentStream ->
contentStream.drawImage(
image,
x,
y,
image.width.toFloat(),
image.height.toFloat()
)
}
// 保存PDF文档
document.save(savePath)
}
} catch (e: IOException) {
e.printStackTrace()
}
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.utils
import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.Settings
import androidx.core.app.ActivityCompat
object PermissionUtils {
fun Context.checkStorePermission(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
Environment.isExternalStorageManager()
} else {
val readPermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
val writePermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
return readPermission == PackageManager.PERMISSION_GRANTED && writePermission == PackageManager.PERMISSION_GRANTED;
}
}
fun Context.checkNotificationPermission(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED
} else {
return true
}
}
fun Context.requestStoragePermission(
launcher: ActivityLauncher,
jumpAction: (() -> Unit)? = null,
result: (flag: Boolean) -> Unit
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val intent =
Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
intent.addCategory("android.intent.category.DEFAULT")
intent.data = Uri.parse("package:${packageName}")
jumpAction?.invoke()
launcher.launch(intent) {
result.invoke(checkStorePermission())
}
} else {
launcher.launch(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { map ->
result(map.values.all { it })
}
}
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.utils
object SpStringUtils {
private val TAG = "SpStringUtils"
const val BOOKMARK_KEY = "bookmark_key"
//key=last_view_key value=/data/user/0/com.ttesst.gododo.redause/files/demo/DEMO.pdf_/_1728703007625
const val LAST_VIEW_KEY = "last_view_key"
fun getSpStringList(key: String): List<String> {
val sp = AppPreferences.getInstance().getString(key, "")
return if (sp.equals("")) {
listOf()
} else {
sp.split("|||")
}
}
fun addSpString(key: String, value: String) {
LogEx.logDebug(TAG, "key=$key value=$value")
val list = getSpStringList(key).toMutableList()
list.add(value)
val string = list.joinToString(separator = "|||")
AppPreferences.getInstance().put(key, string)
}
fun deleteSpString(key: String, value: String) {
val list = getSpStringList(key).toMutableList()
list.remove(value)
val string = list.joinToString(separator = "|||")
AppPreferences.getInstance().put(key, string)
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.utils
import android.content.Context
import android.net.Uri
import com.tom_roush.pdfbox.io.IOUtils
import java.io.InputStream
object UriUtils {
fun readFileToByteArray(context: Context, uri: Uri): ByteArray? {
var inputStream: InputStream? = null
return try {
inputStream = context.contentResolver.openInputStream(uri)
// 读取文件内容到字节数组
IOUtils.toByteArray(inputStream)
} catch (e: java.lang.Exception) {
e.printStackTrace()
null
} finally {
if (inputStream != null) {
try {
inputStream.close()
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
}
}
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.utils
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
object XmlEx {
fun Int.inflate(parent: ViewGroup, attachToRoot: Boolean = false): View {
return LayoutInflater.from(parent.context).inflate(this, parent, attachToRoot)
}
fun Int.inflate(context: Context, attachToRoot: Boolean = false): View {
return LayoutInflater.from(context).inflate(this, null, attachToRoot)
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.widget
import android.app.Service
import android.content.Context
import android.util.AttributeSet
import android.util.DisplayMetrics
import android.view.WindowManager
import androidx.drawerlayout.widget.DrawerLayout
import com.google.android.material.navigation.NavigationView
class FullScreenNavigationView : NavigationView {
constructor(context: Context) : super(context) {
initView(context)
}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
initView(context)
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
initView(context)
}
private fun initView(context: Context) {
val vto = this.viewTreeObserver
vto.addOnGlobalLayoutListener { setFullScreenWidth(context) }
}
fun setFullScreenWidth(context: Context) {
val displayMetrics = DisplayMetrics()
val windowManager = context.getSystemService(Service.WINDOW_SERVICE) as WindowManager
windowManager.getDefaultDisplay().getMetrics(displayMetrics)
val screenWidth = displayMetrics.widthPixels
val params = this.layoutParams as DrawerLayout.LayoutParams
params.width = screenWidth
this.layoutParams = params
}
}
\ No newline at end of file
package com.base.pdfreaderallpdfreader.widget
import android.content.Context
import android.graphics.Canvas
import android.util.AttributeSet
import com.airbnb.lottie.LottieAnimationView
class XmlLottieAnimationView : LottieAnimationView {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
override fun draw(canvas: Canvas) {
try {
super.draw(canvas)
} catch (e: Exception) {
}
}
override fun playAnimation() {
super.playAnimation()
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#58585A" android:state_selected="false" />
<item android:color="#4385F5" android:state_selected="true" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="22dp" />
<solid android:color="#6EAAFF" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#EAFFF3" />
<corners android:radius="15dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#EDF3FF" />
<corners android:radius="15dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#EFEFEF" />
<corners android:radius="15dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#F6F6F6" />
<corners android:radius="15dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFF1EC" />
<corners android:radius="15dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white" />
<corners
android:topLeftRadius="15dp"
android:topRightRadius="15dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/pdf_unchecked" android:state_selected="false" />
<item android:drawable="@mipmap/pdf_selected" android:state_selected="true" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/pdf_tab_select" android:state_selected="true" />
<item android:drawable="@mipmap/pdf_tab_unselect" android:state_selected="false" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0" />
<path
android:fillColor="#FF000000"
android:pathData="M9,2L7.17,4H4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2H9zm3,15c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z" />
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M22,16V4c0,-1.1 -0.9,-2 -2,-2H8c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2zm-11,-4l2.03,2.71L16,11l4,5H8l3,-4zM2,6v14c0,1.1 0.9,2 2,2h14v-2H4V6H2z" />
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M4,6H2v14c0,1.1 0.9,2 2,2h14v-2H4V6zm16,-4H8c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2zm-8,12.5v-9l6,4.5 -6,4.5z" />
</vector>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="2dp" />
<solid android:color="@color/white" />
<!-- <gradient-->
<!-- android:endColor="#FAF8D1"-->
<!-- android:startColor="#FAD4E7"-->
<!-- android:type="linear" />-->
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#20000000">
</ripple>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/h_tab_bookmark_n" android:state_selected="false" />
<item android:drawable="@mipmap/h_tab_bookmark_s" android:state_selected="true" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/h_tab_home_n" android:state_selected="false" />
<item android:drawable="@mipmap/h_tab_home_s" android:state_selected="true" />
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/h_tab_recent_n" android:state_selected="false" />
<item android:drawable="@mipmap/h_tab_recent_s" android:state_selected="true" />
</selector>
\ No newline at end of file
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="135"
android:centerColor="#009688"
android:endColor="#00695C"
android:startColor="#4DB6AC"
android:type="linear" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".ui.document.DocumentActivity">
<FrameLayout
android:id="@+id/fl_fanhui"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10sp"
android:layout_marginTop="24dp"
android:padding="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/pdf_arrow"
tools:ignore="ContentDescription" />
</FrameLayout>
<TextView
android:id="@+id/tv_tittle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:textColor="@color/black"
android:textSize="23sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@id/fl_fanhui"
app:layout_constraintStart_toEndOf="@id/fl_fanhui"
app:layout_constraintTop_toTopOf="@id/fl_fanhui"
tools:text="PDF Reader" />
<ImageView
android:id="@+id/iv_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="18dp"
android:src="@mipmap/h_sousuo"
app:layout_constraintBottom_toBottomOf="@id/fl_fanhui"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/fl_fanhui"
tools:ignore="ContentDescription" />
<FrameLayout
android:id="@+id/fl_tab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:background="@color/white"
app:layout_constraintTop_toBottomOf="@id/fl_fanhui">
<com.angcyo.tablayout.DslTabLayout
android:id="@+id/tabLayout_document"
android:layout_width="match_parent"
android:layout_height="50dp"
app:tab_badge_gravity="center"
app:tab_badge_offset_x="20dp"
app:tab_draw_indicator="true"
app:tab_enable_text_color="true"
app:tab_indicator_anim="true"
app:tab_indicator_drawable="@drawable/indicator_bottom_line"
app:tab_indicator_height="3dp"
app:tab_indicator_width="30dp"
app:tab_item_is_equ_width="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ripple_select"
android:clipChildren="false"
android:clipToPadding="false"
android:gravity="center"
android:text="All"
android:textSize="16sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ripple_select"
android:clipChildren="false"
android:clipToPadding="false"
android:gravity="center"
android:text="PDF"
android:textSize="16sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/ripple_select"
android:clipChildren="false"
android:clipToPadding="false"
android:gravity="center"
android:paddingVertical="5dp"
android:text="Word"
android:textSize="16sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ripple_select"
android:clipChildren="false"
android:clipToPadding="false"
android:gravity="center"
android:text="Excel"
android:textSize="16sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ripple_select"
android:clipChildren="false"
android:clipToPadding="false"
android:gravity="center"
android:text="PPT"
android:textSize="16sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
</com.angcyo.tablayout.DslTabLayout>
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/fl_tab">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager2"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.language.LanguageActivity">
<FrameLayout
android:id="@+id/fl_fanhui"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10sp"
android:layout_marginTop="24dp"
android:padding="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/pdf_arrow" />
</FrameLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="@string/select_language"
android:textColor="@color/black"
android:textSize="23sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@id/fl_fanhui"
app:layout_constraintStart_toEndOf="@id/fl_fanhui"
app:layout_constraintTop_toTopOf="@id/fl_fanhui" />
<ImageView
android:id="@+id/iv_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="20dp"
android:src="@mipmap/pdf_icon_right"
app:layout_constraintBottom_toBottomOf="@id/fl_fanhui"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/fl_fanhui" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintTop_toBottomOf="@id/fl_fanhui"
tools:listitem="@layout/item_language_set" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".ui.search.SearchActivity">
<FrameLayout
android:id="@+id/fl_fanhui"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginTop="24dp"
android:padding="15dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@mipmap/pdf_arrow"
tools:ignore="ContentDescription" />
</FrameLayout>
<EditText
android:id="@+id/edit"
android:layout_width="0dp"
android:layout_height="45dp"
android:layout_marginStart="5dp"
android:layout_marginEnd="15dp"
android:background="@drawable/bg_efefef_15"
android:hint="@string/search_documents"
android:imeOptions="actionDone"
android:paddingStart="27dp"
android:singleLine="true"
android:textSize="15sp"
app:layout_constraintBottom_toBottomOf="@id/fl_fanhui"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/fl_fanhui"
app:layout_constraintTop_toTopOf="@id/fl_fanhui"
tools:ignore="Autofill,RtlSymmetry,TextFields,TouchTargetSizeCheck" />
<com.angcyo.tablayout.DslTabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="18dp"
app:layout_constraintTop_toBottomOf="@id/fl_fanhui"
app:tab_deselect_color="#8F8F8F"
app:tab_divider_solid_color="@android:color/transparent"
app:tab_divider_width="30dp"
app:tab_draw_divider="true"
app:tab_enable_ico_color="false"
app:tab_indicator_style="STYLE_NONE"
app:tab_item_default_height="30dp"
app:tab_select_color="@color/white" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginVertical="18dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/tabLayout"
tools:listitem="@layout/item_document" />
<LinearLayout
android:id="@+id/ll_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tabLayout"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:src="@mipmap/r_pdf_no"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="8dp"
android:text="@string/no_recent"
android:textColor="#2A2A2A"
android:textSize="15sp"
android:textStyle="bold" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".ui.splash.SplashActivity">
<ImageView
android:id="@+id/iv_logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="220dp"
android:src="@mipmap/logox"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/tv_spanner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/iv_logo"
tools:ignore="HardcodedText"
tools:text="AII PDF Reader" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="@string/one_application_for_all_documents"
android:textColor="#8A8A8A"
android:textSize="12sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_spanner" />
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_ffffff_tlr15"
android:orientation="vertical">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"
android:src="@mipmap/pdf_permissions"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="24dp"
android:text="@string/permission_required"
android:textColor="#333333"
android:textSize="17sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginHorizontal="40dp"
android:layout_marginTop="16dp"
android:gravity="center"
android:textColor="#666666"
android:textSize="15sp"
tools:ignore="HardcodedText"
tools:text="To read and edit documents on your device, please allow PDF Reader to access all your files" />
<TextView
android:id="@+id/tv_allow"
android:layout_width="338dp"
android:layout_height="48dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:layout_marginBottom="34dp"
android:background="@drawable/bg_6eaaff_22"
android:gravity="center"
android:text="@string/allow"
android:textColor="@color/white"
android:textSize="18sp"
tools:ignore="HardcodedText" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.main.recent.RecentFragment">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_document" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<LinearLayout
android:id="@+id/ll_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical"
android:visibility="gone"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:src="@mipmap/r_pdf_no"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="8dp"
android:text="@string/no_recent"
android:textColor="#2A2A2A"
android:textSize="15sp"
android:textStyle="bold" />
</LinearLayout>
</FrameLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.document.DocumentFragment">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginVertical="16dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_document" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<LinearLayout
android:id="@+id/ll_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical"
android:visibility="gone"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:src="@mipmap/r_pdf_no"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="8dp"
android:text="@string/no_document"
android:textColor="#2A2A2A"
android:textSize="15sp"
android:textStyle="bold" />
</LinearLayout>
</FrameLayout>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment