diff --git a/.idea/vcs.xml b/.idea/vcs.xml index c78d9f02..94a25f7f 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,6 +2,5 @@ - \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 66bcddaa..396af997 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,10 +7,10 @@ android { compileSdkVersion 28 defaultConfig { applicationId "xyz.quaver.pupil" - minSdkVersion 15 + minSdkVersion 16 targetSdkVersion 28 - versionCode 2 - versionName "1.1" + versionCode 3 + versionName "1.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { @@ -19,9 +19,14 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } + kotlinOptions { + freeCompilerArgs += '-Xuse-experimental=kotlin.Experimental' + } } dependencies { + def markwonVersion = "3.0.1" + implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1' @@ -34,6 +39,7 @@ dependencies { implementation 'com.github.arimorty:floatingsearchview:2.1.1' implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation "ru.noties.markwon:core:${markwonVersion}" testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.0' androidTestImplementation 'androidx.test:runner:1.1.1' diff --git a/app/src/androidTest/java/xyz/quaver/pupil/ExampleInstrumentedTest.kt b/app/src/androidTest/java/xyz/quaver/pupil/ExampleInstrumentedTest.kt index 73714252..5a6f14f7 100644 --- a/app/src/androidTest/java/xyz/quaver/pupil/ExampleInstrumentedTest.kt +++ b/app/src/androidTest/java/xyz/quaver/pupil/ExampleInstrumentedTest.kt @@ -11,7 +11,9 @@ import kotlinx.coroutines.runBlocking import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith +import xyz.quaver.hiyobi.getReader import java.io.File +import java.util.* /** * Instrumented test, which will execute on an Android device. @@ -38,16 +40,7 @@ class ExampleInstrumentedTest { } @Test - @ExperimentalUnsignedTypes fun test_doSearch() { - Log.d("TEST", "Starting...") - runBlocking { - CoroutineScope(Dispatchers.Main).launch { - Log.d("TEST", "This is started! wow") - }.join() - } - - Log.d("TEST", "Finished! ...Really?") } } diff --git a/app/src/main/java/xyz/quaver/pupil/GalleryActivity.kt b/app/src/main/java/xyz/quaver/pupil/GalleryActivity.kt index 3a87a040..24fe0795 100644 --- a/app/src/main/java/xyz/quaver/pupil/GalleryActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/GalleryActivity.kt @@ -1,9 +1,11 @@ package xyz.quaver.pupil import android.os.Bundle +import android.util.Log import android.view.View import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity +import androidx.preference.PreferenceManager import kotlinx.android.synthetic.main.activity_gallery.* import kotlinx.coroutines.* import xyz.quaver.hitomi.Reader @@ -32,9 +34,20 @@ class GalleryActivity : AppCompatActivity() { setContentView(R.layout.activity_gallery) + supportActionBar?.title = intent.getStringExtra("GALLERY_TITLE") + galleryID = intent.getIntExtra("GALLERY_ID", 0) CoroutineScope(Dispatchers.Unconfined).launch { reader = async(Dispatchers.IO) { + val preference = PreferenceManager.getDefaultSharedPreferences(this@GalleryActivity) + if (preference.getBoolean("use_hiyobi", false)) { + try { + xyz.quaver.hiyobi.getReader(galleryID) + Log.d("Pupil", "Using Hiyobi.me") + } catch (e: Exception) { + getReader(galleryID) + } + } getReader(galleryID) } } @@ -43,6 +56,18 @@ class GalleryActivity : AppCompatActivity() { loadImages() } + override fun onResume() { + val preferences = android.preference.PreferenceManager.getDefaultSharedPreferences(this) + + if (preferences.getBoolean("security_mode", false)) + window.setFlags( + WindowManager.LayoutParams.FLAG_SECURE, + WindowManager.LayoutParams.FLAG_SECURE) + else + window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) + super.onResume() + } + override fun onDestroy() { super.onDestroy() loadJob?.cancel() @@ -78,17 +103,15 @@ class GalleryActivity : AppCompatActivity() { val reader = reader.await() launch(Dispatchers.Main) { - supportActionBar?.title = reader.title - with(gallery_progressbar) { - max = reader.images.size + max = reader.size progress = 0 visibility = View.VISIBLE } } - reader.images.chunked(8).forEach { chunked -> + reader.chunked(8).forEach { chunked -> chunked.map { async(Dispatchers.IO) { val url = if (it.second?.haswebp == 1) webpUrlFromUrl(it.first) else it.first diff --git a/app/src/main/java/xyz/quaver/pupil/MainActivity.kt b/app/src/main/java/xyz/quaver/pupil/MainActivity.kt index dd4422e6..65ea4cec 100644 --- a/app/src/main/java/xyz/quaver/pupil/MainActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/MainActivity.kt @@ -10,6 +10,7 @@ import android.content.pm.PackageManager import android.graphics.Bitmap import android.graphics.BitmapFactory import android.net.Uri +import android.os.Build import android.os.Bundle import android.os.Environment import android.preference.PreferenceManager @@ -18,12 +19,15 @@ import android.text.style.AlignmentSpan import android.util.Log import android.view.View import android.view.WindowManager +import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat +import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat import androidx.core.content.FileProvider import androidx.core.content.res.ResourcesCompat +import androidx.core.view.GravityCompat import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.arlib.floatingsearchview.FloatingSearchView @@ -31,36 +35,43 @@ import com.arlib.floatingsearchview.suggestions.model.SearchSuggestion import com.arlib.floatingsearchview.util.view.SearchInputView import com.google.android.material.appbar.AppBarLayout import kotlinx.android.synthetic.main.activity_main.* +import kotlinx.android.synthetic.main.activity_main_content.* import kotlinx.coroutines.* +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.content +import ru.noties.markwon.Markwon import xyz.quaver.hitomi.* import xyz.quaver.pupil.adapters.GalleryBlockAdapter import xyz.quaver.pupil.types.TagSuggestion +import xyz.quaver.pupil.util.Histories import xyz.quaver.pupil.util.SetLineOverlap import xyz.quaver.pupil.util.checkUpdate import xyz.quaver.pupil.util.getApkUrl import java.io.File +import java.lang.StringBuilder +import java.util.* import javax.net.ssl.HttpsURLConnection +import kotlin.collections.ArrayList class MainActivity : AppCompatActivity() { - private val PERMISSION_REQUEST_CODE = 4585 + private val permissionRequestCode = 4585 private val galleries = ArrayList>() - private var isLoading = false private var query = "" - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) + private var galleryIDs: Deferred>? = null + private var loadingJob: Job? = null - window.setFlags( - WindowManager.LayoutParams.FLAG_SECURE, - WindowManager.LayoutParams.FLAG_SECURE) + override fun onCreate(savedInstanceState: Bundle?) { + Histories.default = Histories(File(cacheDir, "histories.json")) + super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) checkPermission() - update() + checkUpdate() main_appbar_layout.addOnOffsetChangedListener( AppBarLayout.OnOffsetChangedListener { _, p1 -> @@ -73,16 +84,60 @@ class MainActivity : AppCompatActivity() { setProgressViewOffset(false, 0, resources.getDimensionPixelSize(R.dimen.progress_view_offset)) setOnRefreshListener { - runBlocking { - cleanJob?.join() + CoroutineScope(Dispatchers.Main).launch { + cancelFetch() + clearGalleries() + fetchGalleries(query) + loadBlocks() } - fetchGalleries(query, true) } } + main_nav_view.setNavigationItemSelectedListener { + CoroutineScope(Dispatchers.Main).launch { + main_drawer_layout.closeDrawers() + + cancelFetch() + clearGalleries() + when(it.itemId) { + R.id.main_drawer_home -> { + query = query.replace("HISTORY", "") + fetchGalleries(query) + } + R.id.main_drawer_history -> { + query += "HISTORY" + fetchGalleries(query) + } + } + loadBlocks() + } + + true + } + setupRecyclerView() setupSearchBar() fetchGalleries(query) + loadBlocks() + } + + override fun onBackPressed() { + if (main_drawer_layout.isDrawerOpen(GravityCompat.START)) + main_drawer_layout.closeDrawer(GravityCompat.START) + else + super.onBackPressed() + } + + override fun onResume() { + val preferences = PreferenceManager.getDefaultSharedPreferences(this) + + if (preferences.getBoolean("security_mode", false)) + window.setFlags( + WindowManager.LayoutParams.FLAG_SECURE, + WindowManager.LayoutParams.FLAG_SECURE) + else + window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) + super.onResume() } private fun checkPermission() { @@ -98,11 +153,54 @@ class MainActivity : AppCompatActivity() { setPositiveButton(android.R.string.ok) { _, _ -> } }.show() else - ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE) + ActivityCompat.requestPermissions(this, permissions, permissionRequestCode) } } - private fun update() { + private fun checkUpdate() { + + fun extractReleaseNote(update: JsonObject, locale: String) : String { + val markdown = update["body"]!!.content + + val target = when(locale) { + "ko" -> "한국어" + "ja" -> "日本語" + else -> "English" + } + + val releaseNote = Regex("^# Release Note.+$") + val language = Regex("^## $target$") + val end = Regex("^#.+$") + + var releaseNoteFlag = false + var languageFlag = false + + val result = StringBuilder() + + for(line in markdown.split('\n')) { + if (releaseNote.matches(line)) { + releaseNoteFlag = true + continue + } + + if (releaseNoteFlag) { + if (language.matches(line)) { + languageFlag = true + continue + } + } + + if (languageFlag) { + if (end.matches(line)) + break + + result.append(line+"\n") + } + } + + return getString(R.string.update_release_note, update["tag_name"]?.content, result.toString()) + } + if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) return @@ -114,8 +212,13 @@ class MainActivity : AppCompatActivity() { val dialog = AlertDialog.Builder(this@MainActivity).apply { setTitle(R.string.update_title) - setMessage(getString(R.string.update_message, update["tag_name"], BuildConfig.VERSION_NAME)) + val msg = extractReleaseNote(update, Locale.getDefault().language) + setMessage(Markwon.create(context).toMarkdown(msg)) setPositiveButton(android.R.string.yes) { _, _ -> + Toast.makeText( + context, getString(R.string.update_download_started), Toast.LENGTH_SHORT + ).show() + val dest = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName) val desturi = FileProvider.getUriForFile( @@ -131,6 +234,7 @@ class MainActivity : AppCompatActivity() { setDescription(getString(R.string.update_notification_description)) setTitle(getString(R.string.app_name)) setDestinationUri(Uri.fromFile(dest)) + setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE) } val manager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager @@ -161,12 +265,15 @@ class MainActivity : AppCompatActivity() { private fun setupRecyclerView() { with(main_recyclerview) { adapter = GalleryBlockAdapter(galleries).apply { - setClickListener { + setClickListener { galleryID, title -> val intent = Intent(this@MainActivity, GalleryActivity::class.java) - intent.putExtra("GALLERY_ID", it) + intent.putExtra("GALLERY_ID", galleryID) + intent.putExtra("GALLERY_TITLE", title) //TODO: Maybe sprinke some transitions will be nice :D startActivity(intent) + + Histories.default.add(galleryID) } } addOnScrollListener( @@ -176,9 +283,9 @@ class MainActivity : AppCompatActivity() { val layoutManager = recyclerView.layoutManager as LinearLayoutManager - if (!isLoading) + if (loadingJob?.isActive != true) if (layoutManager.findLastCompletelyVisibleItemPosition() == galleries.size) - fetchGalleries(query) + loadBlocks() } } ) @@ -295,101 +402,107 @@ class MainActivity : AppCompatActivity() { if (query != this@MainActivity.query) { this@MainActivity.query = query - fetchGalleries(query, true) + cancelFetch() + clearGalleries() + fetchGalleries(query) } } }) + + attachNavigationDrawerToMenuButton(main_drawer_layout) } } - private val cache = ArrayList() - private var currentFetchingJob: Job? = null - private var cleanJob: Job? = null - private fun cancelFetch() { - isLoading = false - runBlocking { - cleanJob?.join() - currentFetchingJob?.cancelAndJoin() + galleryIDs?.cancelAndJoin() + loadingJob?.cancelAndJoin() } } - private fun fetchGalleries(query: String, clear: Boolean = false) { + private fun clearGalleries() { + galleries.clear() + + main_recyclerview.adapter?.notifyDataSetChanged() + + main_noresult.visibility = View.INVISIBLE + main_progressbar.show() + main_swipe_layout.isRefreshing = false + } + + private fun fetchGalleries(query: String, from: Int = 0) { val preference = PreferenceManager.getDefaultSharedPreferences(this) val perPage = preference.getString("per_page", "25")?.toInt() ?: 25 val defaultQuery = preference.getString("default_query", "")!! - if (clear) { - cancelFetch() - cleanJob = CoroutineScope(Dispatchers.Main).launch { - cache.clear() - galleries.clear() + galleryIDs = null - main_recyclerview.adapter?.notifyDataSetChanged() - - main_noresult.visibility = View.INVISIBLE - main_progressbar.show() - main_swipe_layout.isRefreshing = false - } - } - - if (isLoading) + if (galleryIDs?.isActive == true) return - isLoading = true + galleryIDs = CoroutineScope(Dispatchers.IO).async { + when { + query.contains("HISTORY") -> + Histories.default.toList() + query.isEmpty() and defaultQuery.isEmpty() -> + fetchNozomi(start = from, count = perPage) + else -> + doSearch("$defaultQuery $query") + } + } + } - currentFetchingJob = CoroutineScope(Dispatchers.IO).launch { - try { - val galleryIDs: List + private fun loadBlocks() { + val preference = PreferenceManager.getDefaultSharedPreferences(this) + val perPage = preference.getString("per_page", "25")?.toInt() ?: 25 + val defaultQuery = preference.getString("default_query", "")!! - cleanJob?.join() + loadingJob = CoroutineScope(Dispatchers.IO).launch { + val galleryIDs = galleryIDs?.await() - if (query.isEmpty() && defaultQuery.isEmpty()) - galleryIDs = fetchNozomi(start = galleries.size, count = perPage) - else { - if (cache.isEmpty()) - cache.addAll(doSearch("$defaultQuery $query")) - - galleryIDs = cache.slice(galleries.size until Math.min(galleries.size + perPage, cache.size)) - - with(main_recyclerview.adapter as GalleryBlockAdapter) { - noMore = galleries.size + perPage >= cache.size - } + if (galleryIDs.isNullOrEmpty()) { //No result + withContext(Dispatchers.Main) { + main_noresult.visibility = View.VISIBLE + main_progressbar.hide() } - if (query.isNotEmpty() and defaultQuery.isNotEmpty() and cache.isNullOrEmpty()) { + return@launch + } + + if (query.isEmpty() and defaultQuery.isEmpty()) + fetchGalleries("", galleries.size+perPage) + else + with(main_recyclerview.adapter as GalleryBlockAdapter) { + noMore = galleries.size + perPage >= galleryIDs.size + } + + when { + query.isEmpty() and defaultQuery.isEmpty() -> + galleryIDs + else -> + galleryIDs.slice(galleries.size until Math.min(galleries.size+perPage, galleryIDs.size)) + }.chunked(4).forEach { chunked -> + chunked.map { + async { + val galleryBlock = getGalleryBlock(it) + val thumbnail: Bitmap + + with(galleryBlock.thumbnails[0].openConnection() as HttpsURLConnection) { + thumbnail = BitmapFactory.decodeStream(inputStream) + } + + Pair(galleryBlock, thumbnail) + } + }.forEach { + val galleryBlock = it.await() + withContext(Dispatchers.Main) { - main_noresult.visibility = View.VISIBLE main_progressbar.hide() + + galleries.add(galleryBlock) + main_recyclerview.adapter?.notifyItemInserted(galleries.size - 1) } } - - galleryIDs.chunked(4).forEach { chunked -> - chunked.map { - async { - val galleryBlock = getGalleryBlock(it) - val thumbnail: Bitmap - - with(galleryBlock.thumbnails[0].openConnection() as HttpsURLConnection) { - thumbnail = BitmapFactory.decodeStream(inputStream) - } - - Pair(galleryBlock, thumbnail) - } - }.forEach { - val galleryBlock = it.await() - - withContext(Dispatchers.Main) { - main_progressbar.hide() - - galleries.add(galleryBlock) - main_recyclerview.adapter?.notifyItemInserted(galleries.size - 1) - } - } - } - } finally { - isLoading = false } } } diff --git a/app/src/main/java/xyz/quaver/pupil/SettingsActivity.kt b/app/src/main/java/xyz/quaver/pupil/SettingsActivity.kt index 40624e27..d5c301ce 100644 --- a/app/src/main/java/xyz/quaver/pupil/SettingsActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/SettingsActivity.kt @@ -1,12 +1,15 @@ package xyz.quaver.pupil import android.os.Bundle +import android.preference.PreferenceManager import android.view.MenuItem import android.view.WindowManager import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat +import xyz.quaver.pupil.util.Histories +import java.io.File class SettingsActivity : AppCompatActivity() { @@ -25,6 +28,18 @@ class SettingsActivity : AppCompatActivity() { supportActionBar?.setDisplayHomeAsUpEnabled(true) } + override fun onResume() { + val preferences = PreferenceManager.getDefaultSharedPreferences(this) + + if (preferences.getBoolean("security_mode", false)) + window.setFlags( + WindowManager.LayoutParams.FLAG_SECURE, + WindowManager.LayoutParams.FLAG_SECURE) + else + window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) + super.onResume() + } + class SettingsFragment : PreferenceFragmentCompat() { private val suffix = listOf( @@ -35,8 +50,8 @@ class SettingsActivity : AppCompatActivity() { "TB" //really? ) - private fun getCacheSize() : String { - var size = context!!.cacheDir.walk().map { it.length() }.sum() + private fun getCacheSize(dir: File) : String { + var size = dir.walk().map { it.length() }.sum() var suffixIndex = 0 while (size >= 1024) { @@ -50,22 +65,43 @@ class SettingsActivity : AppCompatActivity() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.root_preferences, rootKey) - with(findPreference("delete_cache")) { + with(findPreference("delete_image_cache")) { this ?: return@with - summary = getCacheSize() + val dir = File(context.cacheDir, "imageCache") + + summary = getCacheSize(dir) setOnPreferenceClickListener { AlertDialog.Builder(context).apply { setTitle(R.string.warning) setMessage(R.string.settings_clear_cache_alert_message) setPositiveButton(android.R.string.yes) { _, _ -> - with(context.cacheDir) { - if (exists()) - deleteRecursively() - } + if (dir.exists()) + dir.deleteRecursively() - summary = getCacheSize() + summary = getCacheSize(dir) + } + setNegativeButton(android.R.string.no) { _, _ -> } + }.show() + + true + } + } + with(findPreference("clear_history")) { + this ?: return@with + + val histories = Histories.default + + summary = getString(R.string.settings_clear_history_summary, histories.size) + + setOnPreferenceClickListener { + AlertDialog.Builder(context).apply { + setTitle(R.string.warning) + setMessage(R.string.settings_clear_history_alert_message) + setPositiveButton(android.R.string.yes) { _, _ -> + histories.clear() + summary = getString(R.string.settings_clear_history_summary, histories.size) } setNegativeButton(android.R.string.no) { _, _ -> } }.show() diff --git a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt index b94db781..71851505 100644 --- a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt +++ b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt @@ -33,8 +33,8 @@ class GalleryBlockAdapter(private val galleries: List Unit)? = null - fun setClickListener(callback: ((Int) -> Unit)?) { + private var callback: ((Int, String) -> Unit)? = null + fun setClickListener(callback: ((Int, String) -> Unit)?) { this.callback = callback } @@ -74,7 +74,7 @@ class GalleryBlockAdapter(private val galleries: List() { + + init { + if (!file.exists()) + file.parentFile.mkdirs() + + try { + load() + } catch (e: Exception) { + save() + } + } + + companion object { + lateinit var default: Histories + + fun load(file: File) : Histories { + return Histories(file).load() + } + } + + @UseExperimental(ImplicitReflectionSerializer::class) + fun load() : Histories { + return apply { + super.clear() + addAll( + Json(JsonConfiguration.Stable).parseList( + file.bufferedReader().use { it.readText() } + ) + ) + } + } + + @UseExperimental(ImplicitReflectionSerializer::class) + fun save() { + file.writeText(Json(JsonConfiguration.Stable).stringify(this)) + } + + override fun add(element: Int): Boolean { + load() + + if (contains(element)) + super.remove(element) + + super.add(0, element) + + save() + + return true + } + + override fun remove(element: Int): Boolean { + load() + val retval = super.remove(element) + save() + + return retval + } + + override fun clear() { + super.clear() + save() + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-anydpi/ic_history.xml b/app/src/main/res/drawable-anydpi/ic_history.xml new file mode 100644 index 00000000..e5e6c6c8 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_history.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable-anydpi/ic_home.xml b/app/src/main/res/drawable-anydpi/ic_home.xml new file mode 100644 index 00000000..08ebbdf2 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_home.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable-hdpi/ic_history.png b/app/src/main/res/drawable-hdpi/ic_history.png new file mode 100644 index 00000000..8610919f Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_history.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_home.png b/app/src/main/res/drawable-hdpi/ic_home.png new file mode 100644 index 00000000..caccfac0 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_home.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_history.png b/app/src/main/res/drawable-mdpi/ic_history.png new file mode 100644 index 00000000..e64059c8 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_history.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_home.png b/app/src/main/res/drawable-mdpi/ic_home.png new file mode 100644 index 00000000..1eccf9f3 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_home.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_history.png b/app/src/main/res/drawable-xhdpi/ic_history.png new file mode 100644 index 00000000..4a9622d2 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_history.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_home.png b/app/src/main/res/drawable-xhdpi/ic_home.png new file mode 100644 index 00000000..cea7b6c5 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_home.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_history.png b/app/src/main/res/drawable-xxhdpi/ic_history.png new file mode 100644 index 00000000..c22644eb Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_history.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_home.png b/app/src/main/res/drawable-xxhdpi/ic_home.png new file mode 100644 index 00000000..a576a1a4 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_home.png differ diff --git a/app/src/main/res/drawable/side_nav_bar.png b/app/src/main/res/drawable/side_nav_bar.png new file mode 100644 index 00000000..a399a2d5 Binary files /dev/null and b/app/src/main/res/drawable/side_nav_bar.png differ diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 77677f3d..3d702355 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,83 +1,25 @@ - + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/main_drawer_layout" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fitsSystemWindows="true" + tools:openDrawer="start"> - + android:layout_height="match_parent"/> - - - - - - - - - - - - - - - - - - - + android:layout_gravity="start" + android:fitsSystemWindows="true" + app:headerLayout="@layout/nav_header_main" + app:menu="@menu/activity_main_drawer"/> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main_content.xml b/app/src/main/res/layout/activity_main_content.xml new file mode 100644 index 00000000..f0d84786 --- /dev/null +++ b/app/src/main/res/layout/activity_main_content.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/nav_header_main.xml b/app/src/main/res/layout/nav_header_main.xml new file mode 100644 index 00000000..d801cf79 --- /dev/null +++ b/app/src/main/res/layout/nav_header_main.xml @@ -0,0 +1,12 @@ + + \ No newline at end of file diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml new file mode 100644 index 00000000..1877c34f --- /dev/null +++ b/app/src/main/res/menu/activity_main_drawer.xml @@ -0,0 +1,15 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 2d50f270..b102b437 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -1,6 +1,5 @@ - Pupil 言語: %1$s シリーズ: %1$s タイプ: %1$s @@ -8,7 +7,7 @@ 検索 ギャラリー検索 キャッシュ - キャッシュクリア + イメージキャッシュクリア キャッシュをクリアするとイメージのロード速度に影響を与えます。実行しますか? キャッシュサイズ: %1$d%2$s デフォルト検索キーワード @@ -16,8 +15,19 @@ 一回にロードするギャラリー数 検索設定 設定 - 新バージョン%1$sをリリースしました\n(現バージョン: %2$s)\nアップデートしますか? アップデートダウンロード中 新しいアップデートがあります 注意 + その他 + ロード速度を向上させるためhiyobi.meからイメージロード + hiyobi.meからロード + 履歴の削除 + 履歴を削除しますか? + 履歴数: %1$d + 履歴 + トップ + ダウンロード中 + # リリースノート(v%1$s)\n%2$s + セキュリティーモード + アプリ履歴でアプリの画面を表示しない \ No newline at end of file diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index c443a4b4..95f970f6 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -1,23 +1,33 @@ - Pupil 언어: %1$s 시리즈: %1$s 종류: %1$s 권한을 거부하면 일부 기능이 작동하지 않을 수 있습니다 갤러리 검색 기본 검색어 - 캐시 정리하기 + 이미지 캐시 정리하기 캐시를 정리하면 이미지 로딩속도가 느려질 수 있습니다. 계속하시겠습니까? 현재 캐시 사용량: %1$d%2$s 한 번에 로드할 갤러리 수 검색 설정 설정 - 버전 %1$s이 출시되었습니다.\n(현재 %2$s)\n업데이트 하시겠습니까? apk 다운로드중… 업데이트가 있습니다! 경고 결과 없음 검색 캐시 + 기타 + 속도 향상을 위해 가능하면 hiyobi.me에서 이미지 로드 + hiyobi.me 사용 + 히스토리 삭제 + 히스토리를 삭제하시겠습니까? + 히스토리 %1$d개 저장됨 + 히스토리 + + 다운로드 중 + # 릴리즈 노트(v%1$s)\n%2$s + 최근 앱 목록 창에서 앱 화면을 보이지 않게 합니다 + 보안 모드 활성화 \ No newline at end of file diff --git a/app/src/main/res/values-v23/styles.xml b/app/src/main/res/values-v23/styles.xml index 9c3f02d2..0cce6118 100644 --- a/app/src/main/res/values-v23/styles.xml +++ b/app/src/main/res/values-v23/styles.xml @@ -1,7 +1,6 @@