Skip to content

Commit 21a69d6

Browse files
committed
External storage update
1 parent 6461b5a commit 21a69d6

File tree

19 files changed

+101
-43
lines changed

19 files changed

+101
-43
lines changed

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Top-level build file where you can add configuration options common to all sub-projects/modules.
22

33
buildscript {
4-
ext.objectboxVersion = '2.6.0'
4+
ext.objectboxVersion = '2.7.1'
55
ext.booster_version = '2.1.0'
66
ext.isProprietary = getGradle().getStartParameter().getTaskRequests().toString().contains("Proprietary")
77
repositories {
@@ -10,7 +10,7 @@ buildscript {
1010

1111
}
1212
dependencies {
13-
classpath 'com.android.tools.build:gradle:4.0.1'
13+
classpath 'com.android.tools.build:gradle:4.0.2'
1414
if (isProprietary) {
1515
classpath 'com.google.gms:google-services:4.3.3'
1616
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.1.1'

xkcd/build.gradle

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -180,15 +180,15 @@ dependencies {
180180
debugImplementation "io.objectbox:objectbox-android-objectbrowser:$objectboxVersion"
181181
releaseImplementation "io.objectbox:objectbox-android:$objectboxVersion"
182182

183-
implementation 'androidx.core:core-ktx:1.3.1'
183+
implementation 'androidx.core:core-ktx:1.3.2'
184184
implementation 'androidx.appcompat:appcompat:1.2.0'
185185
implementation 'androidx.preference:preference:1.1.1'
186186
implementation 'androidx.media:media:1.2.0'
187187
implementation 'androidx.exifinterface:exifinterface:1.3.0'
188-
implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha05'
189-
implementation 'com.google.android.material:material:1.3.0-alpha02'
188+
implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha06'
189+
implementation 'com.google.android.material:material:1.3.0-alpha03'
190190
implementation 'androidx.percentlayout:percentlayout:1.0.0'
191-
implementation 'org.jsoup:jsoup:1.12.1'
191+
implementation 'org.jsoup:jsoup:1.13.1'
192192
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
193193
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'
194194

@@ -229,9 +229,9 @@ dependencies {
229229

230230
implementation "androidx.work:work-runtime-ktx:2.4.0"
231231
implementation "androidx.work:work-rxjava2:2.4.0"
232-
proprietaryImplementation 'com.google.firebase:firebase-analytics:17.5.0'
233-
proprietaryImplementation 'com.google.firebase:firebase-messaging:20.2.4'
234-
proprietaryImplementation 'com.google.firebase:firebase-crashlytics:17.2.1'
232+
proprietaryImplementation 'com.google.firebase:firebase-analytics:17.6.0'
233+
proprietaryImplementation 'com.google.firebase:firebase-messaging:20.3.0'
234+
proprietaryImplementation 'com.google.firebase:firebase-crashlytics:17.2.2'
235235

236236
// implementation 'androidx.slice:slice-core:1.0.0'
237237
// implementation 'androidx.slice:slice-builders:1.0.0'

xkcd/src/main/java/xyz/jienan/xkcd/Const.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ public class Const {
2727
public static final String PREF_DARK_THEME = "pref_dark";
2828
public static final String PREF_XKCD_STORAGE = "pref_xkcd_storage";
2929
public static final String PREF_XKCD_STORAGE_INTERNAL = "pref_xkcd_storage_internal";
30-
public static final String PREF_XKCD_STORAGE_EXTERNAL = "pref_xkcd_storage_external";
3130

3231

3332
public static final String FIRE_LARGE_IMAGE = "large_image";

xkcd/src/main/java/xyz/jienan/xkcd/XkcdApplication.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ class XkcdApplication : Application() {
9898
val notificationWorkRequest = PeriodicWorkRequestBuilder<NotificationWorker>(PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
9999
TimeUnit.MILLISECONDS)
100100
.addTag("Update")
101+
.setInitialDelay(20L, TimeUnit.SECONDS)
101102
.setConstraints(Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())
102103
.build()
103104
WorkManager.getInstance(this)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package xyz.jienan.xkcd.base.glide
2+
3+
import android.content.Context
4+
import android.os.Build
5+
import android.os.Environment
6+
import androidx.annotation.RequiresApi
7+
import com.bumptech.glide.load.engine.cache.DiskLruCacheFactory
8+
import com.bumptech.glide.load.engine.cache.DiskLruCacheFactory.CacheDirectoryGetter
9+
import timber.log.Timber
10+
import java.io.File
11+
12+
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
13+
class ExternalSDCacheDiskCacheFactory @JvmOverloads constructor(context: Context, diskCacheName: String? = DEFAULT_DISK_CACHE_DIR, diskCacheSize: Int = DEFAULT_DISK_CACHE_SIZE) :
14+
DiskLruCacheFactory(CacheDirectoryGetter {
15+
16+
val file = try {
17+
context.externalCacheDirs.firstOrNull {
18+
try {
19+
!Environment.isExternalStorageEmulated(it) && Environment.isExternalStorageRemovable(it)
20+
} catch (e: Exception) {
21+
Timber.w(e, "Failed to check external storage")
22+
false
23+
}
24+
}
25+
} catch (e: Exception) {
26+
Timber.w(e, "Failed to check external storage")
27+
null
28+
}
29+
30+
val cacheDirectory = file ?: context.cacheDir ?: null
31+
32+
if (diskCacheName != null) {
33+
Timber.d("Use cache directory $cacheDirectory")
34+
File(cacheDirectory, diskCacheName)
35+
}
36+
cacheDirectory
37+
}, diskCacheSize) {
38+
constructor(context: Context, diskCacheSize: Int) : this(context, DEFAULT_DISK_CACHE_DIR, diskCacheSize)
39+
}

xkcd/src/main/java/xyz/jienan/xkcd/base/glide/OkHttpProgressGlideModule.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
package xyz.jienan.xkcd.base.glide;
22

33
import android.content.Context;
4+
import android.os.Build;
45
import android.os.Handler;
56
import android.os.Looper;
67

78
import com.bumptech.glide.Glide;
89
import com.bumptech.glide.GlideBuilder;
910
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader;
10-
import com.bumptech.glide.load.engine.cache.ExternalCacheDiskCacheFactory;
1111
import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory;
1212
import com.bumptech.glide.load.model.GlideUrl;
1313
import com.bumptech.glide.module.GlideModule;
@@ -52,9 +52,9 @@ public static void expect(String url, UIProgressListener listener) {
5252

5353
@Override
5454
public void applyOptions(Context context, GlideBuilder builder) {
55-
if (SharedPrefManager.INSTANCE.getExternalCache() && externalMemoryAvailable(context)) {
55+
if (SharedPrefManager.INSTANCE.getExternalCache() && externalMemoryAvailable(context) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
5656
Timber.i("Use external cache %s", context.getExternalCacheDir());
57-
builder.setDiskCache(new ExternalCacheDiskCacheFactory(context, 600 * 1024 * 1024));
57+
builder.setDiskCache(new ExternalSDCacheDiskCacheFactory(context, 600 * 1024 * 1024));
5858
} else {
5959
Timber.i("Use internal cache");
6060
SharedPrefManager.INSTANCE.disableExternalCache();

xkcd/src/main/java/xyz/jienan/xkcd/home/MainActivity.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
197197
}
198198

199199
private fun getDailyQuote() {
200-
QuoteModel.getQuoteOfTheDay(SharedPrefManager.previousQuote)
200+
QuoteModel.getQuoteOfTheDay(SharedPrefManager.previousQuote, resources)
201201
.observeOn(AndroidSchedulers.mainThread())
202202
.doOnNext { SharedPrefManager.saveNewQuote(it) }
203203
.subscribe({ quote ->
Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,44 @@
11
package xyz.jienan.xkcd.model
22

3+
import android.content.res.Resources
4+
import androidx.annotation.RawRes
5+
import com.google.gson.Gson
6+
import com.google.gson.reflect.TypeToken
37
import io.reactivex.Observable
48
import io.reactivex.schedulers.Schedulers
59
import xyz.jienan.xkcd.BuildConfig
10+
import xyz.jienan.xkcd.R
611
import xyz.jienan.xkcd.base.network.NetworkService
712
import java.util.*
813

914
object QuoteModel {
1015

1116
private val INTERVAL = (if (BuildConfig.DEBUG) 10000 else 1000 * 60 * 60 * 24).toLong()
1217

13-
fun getQuoteOfTheDay(previousQuote: Quote): Observable<Quote> =
18+
fun getQuoteOfTheDay(previousQuote: Quote, resources: Resources): Observable<Quote> =
1419
Observable.just(previousQuote)
1520
.flatMap {
1621
if (System.currentTimeMillis() - it.timestamp < INTERVAL) {
1722
Observable.just(it)
1823
} else {
19-
queryNewQuote(it)
24+
queryNewQuote(it, resources)
2025
}
2126
}
2227

23-
private fun queryNewQuote(quote: Quote) =
28+
private fun queryNewQuote(quote: Quote, resources: Resources) =
2429
NetworkService.quoteAPI.quotes
2530
.subscribeOn(Schedulers.io())
31+
.onErrorReturnItem(resources.readRawJson(R.raw.quotes))
2632
.map { quotes ->
2733
quotes.remove(quote)
2834
quotes
2935
}
3036
.map { quotes -> quotes[Random().nextInt(quotes.size)] }
3137
.doOnNext { result -> result.timestamp = System.currentTimeMillis() }
3238
}
39+
40+
private inline fun <reified T> Resources.readRawJson(@RawRes rawResId: Int): T {
41+
openRawResource(rawResId).bufferedReader().use {
42+
return Gson().fromJson<T>(it, object: TypeToken<T>() {}.type)
43+
}
44+
}

xkcd/src/main/java/xyz/jienan/xkcd/model/util/XkcdSideloadUtils.kt

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@ import xyz.jienan.xkcd.base.network.NetworkService
1212
import xyz.jienan.xkcd.model.ExtraComics
1313
import xyz.jienan.xkcd.model.ExtraModel
1414
import xyz.jienan.xkcd.model.XkcdPic
15-
import java.io.BufferedReader
1615
import java.io.IOException
17-
import java.io.InputStreamReader
18-
import java.io.StringWriter
1916

2017
/**
2118
* Created by Jienan on 2018/3/2.
@@ -99,16 +96,6 @@ object XkcdSideloadUtils {
9996

10097
@Throws(IOException::class)
10198
private fun Context.loadFromRaw(@RawRes raw: Int): String {
102-
val writer = StringWriter()
103-
val buffer = CharArray(1024)
104-
resources.openRawResource(raw).use {
105-
val reader = BufferedReader(InputStreamReader(it, "UTF-8"))
106-
var n = reader.read(buffer)
107-
while (n != -1) {
108-
writer.write(buffer, 0, n)
109-
n = reader.read(buffer)
110-
}
111-
}
112-
return writer.toString()
99+
return resources.openRawResource(raw).bufferedReader().use { it.readText() }
113100
}
114101
}

xkcd/src/main/java/xyz/jienan/xkcd/settings/SettingsFragment.kt

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ import android.content.res.Configuration
66
import android.os.Build
77
import android.os.Bundle
88
import android.os.Environment
9-
import androidx.annotation.RequiresApi
9+
import android.widget.Toast
1010
import androidx.appcompat.app.AppCompatDelegate
11-
import androidx.core.content.ContextCompat
1211
import androidx.preference.*
1312
import androidx.work.*
1413
import timber.log.Timber
@@ -18,6 +17,7 @@ import xyz.jienan.xkcd.model.WhatIfModel
1817
import xyz.jienan.xkcd.model.XkcdModel
1918
import xyz.jienan.xkcd.model.work.XkcdDownloadWorker
2019
import xyz.jienan.xkcd.model.work.XkcdFastLoadWorker
20+
import xyz.jienan.xkcd.ui.ToastUtils
2121

2222
/**
2323
* Created by Jienan on 2018/3/9.
@@ -31,6 +31,8 @@ class SettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChan
3131

3232
private val zoomPref by lazy { findPreference<ListPreference>(PREF_ZOOM) }
3333

34+
private val storagePref by lazy { findPreference<ListPreference>(PREF_XKCD_STORAGE) }
35+
3436
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
3537
setPreferencesFromResource(R.xml.prefs, rootKey)
3638

@@ -41,6 +43,8 @@ class SettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChan
4143
arrowPref?.onPreferenceChangeListener = this
4244
zoomPref?.onPreferenceChangeListener = this
4345
darkPref?.onPreferenceChangeListener = this
46+
storagePref?.onPreferenceChangeListener = this
47+
4448

4549
if (XkcdModel.localizedUrl.isBlank()) {
4650
findPreference<PreferenceCategory>("pref_key_xkcd")?.removePreference(findPreference(PREF_XKCD_TRANSLATION))
@@ -80,6 +84,10 @@ class SettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChan
8084
AppCompatDelegate.setDefaultNightMode(newValue.toString().toInt())
8185
}
8286
}
87+
PREF_XKCD_STORAGE -> {
88+
ToastUtils.showToast(requireContext(), getString(R.string.pref_xkcd_storage_toast), duration = Toast.LENGTH_LONG)
89+
return true
90+
}
8391
}
8492
return false
8593
}
@@ -124,7 +132,14 @@ class SettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChan
124132
fun Context.externalMemoryAvailable(): Boolean {
125133
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && getExternalFilesDir(null) != null) {
126134
try {
127-
!Environment.isExternalStorageEmulated(getExternalFilesDir(null)!!) && Environment.isExternalStorageRemovable(getExternalFilesDir(null)!!)
135+
getExternalFilesDirs(null).any {
136+
try {
137+
!Environment.isExternalStorageEmulated(it) && Environment.isExternalStorageRemovable(it)
138+
} catch (e: Exception) {
139+
Timber.w(e, "Failed to check external storage")
140+
false
141+
}
142+
}
128143
} catch (e: Exception) {
129144
Timber.w(e, "Failed to check external storage")
130145
false

0 commit comments

Comments
 (0)