diff --git a/app/build.gradle b/app/build.gradle index a87138e691..96386dc2ff 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -153,6 +153,8 @@ dependencies { // Image library compile 'com.github.bumptech.glide:glide:3.7.0' compile 'com.github.bumptech.glide:okhttp3-integration:1.4.0@aar' + // Transformations + compile 'jp.wasabeef:glide-transformations:2.0.1' // Logging compile 'com.jakewharton.timber:timber:4.3.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d91c3b2d6d..91d0788e72 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -8,6 +8,7 @@ + + android:parentActivityName=".ui.main.MainActivity" + android:exported="true"> () { const val FROM_CATALOGUE_EXTRA = "from_catalogue" const val MANGA_EXTRA = "manga" + const val FROM_LAUNCHER_EXTRA = "from_launcher" const val INFO_FRAGMENT = 0 const val CHAPTERS_FRAGMENT = 1 const val MYANIMELIST_FRAGMENT = 2 @@ -47,6 +48,11 @@ class MangaActivity : BaseRxActivity() { super.onCreate(savedState) setContentView(R.layout.activity_manga) + val fromLauncher = intent.getBooleanExtra(FROM_LAUNCHER_EXTRA, false) + + //Remove any current manga if we are launching from launcher + if(fromLauncher) SharedData.remove(MangaEvent::class.java) + presenter.setMangaEvent(SharedData.getOrPut(MangaEvent::class.java) { val id = intent.getLongExtra(MANGA_EXTRA, 0) MangaEvent(presenter.db.getManga(id).executeAsBlocking()!!) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.kt index 6ab67a9233..6279466ce1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.kt @@ -1,21 +1,44 @@ package eu.kanade.tachiyomi.ui.manga.info +import android.app.Activity import android.content.Intent +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.drawable.BitmapDrawable import android.net.Uri import android.os.Bundle import android.support.customtabs.CustomTabsIntent +import android.support.design.widget.Snackbar +import android.util.SparseArray import android.view.* +import com.afollestad.materialdialogs.MaterialDialog +import com.bumptech.glide.BitmapRequestBuilder +import com.bumptech.glide.BitmapTypeRequest import com.bumptech.glide.Glide import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.load.resource.bitmap.CenterCrop import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.source.Source import eu.kanade.tachiyomi.data.source.online.OnlineSource import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment +import eu.kanade.tachiyomi.ui.library.LibraryFragment +import eu.kanade.tachiyomi.ui.manga.MangaActivity import eu.kanade.tachiyomi.util.getResourceColor import eu.kanade.tachiyomi.util.toast +import jp.wasabeef.glide.transformations.CropCircleTransformation +import jp.wasabeef.glide.transformations.CropSquareTransformation +import jp.wasabeef.glide.transformations.MaskTransformation +import jp.wasabeef.glide.transformations.RoundedCornersTransformation import kotlinx.android.synthetic.main.fragment_manga_info.* +import kotlinx.android.synthetic.main.item_download.* import nucleus.factory.RequiresPresenter +import rx.Observable +import rx.android.schedulers.AndroidSchedulers +import rx.schedulers.Schedulers +import timber.log.Timber +import java.io.IOException +import kotlin.concurrent.thread /** * Fragment that shows manga information. @@ -34,6 +57,7 @@ class MangaInfoFragment : BaseRxFragment() { fun newInstance(): MangaInfoFragment { return MangaInfoFragment() } + } override fun onCreate(savedState: Bundle?) { @@ -61,6 +85,7 @@ class MangaInfoFragment : BaseRxFragment() { when (item.itemId) { R.id.action_open_in_browser -> openInBrowser() R.id.action_share -> shareManga() + R.id.action_add_to_home_screen -> addToHomeScreen() else -> return super.onOptionsItemSelected(item) } return true @@ -178,6 +203,80 @@ class MangaInfoFragment : BaseRxFragment() { } } + /** + * Add the manga to the home screen + */ + fun addToHomeScreen() { + val shortcutIntent = activity.intent + shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + .putExtra(MangaActivity.FROM_LAUNCHER_EXTRA, true) + + val addIntent = Intent() + addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent) + .action = "com.android.launcher.action.INSTALL_SHORTCUT" + + //Set shortcut title + MaterialDialog.Builder(activity) + .title(R.string.shortcut_title) + .input("", presenter.manga.title, { md, text -> + //Set shortcut title + addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, text.toString()) + + reshapeIconBitmap(addIntent, + Glide.with(context).load(presenter.manga).asBitmap()) + }) + .negativeText(android.R.string.cancel) + .onNegative { materialDialog, dialogAction -> materialDialog.cancel() } + .show() + } + + fun reshapeIconBitmap(addIntent: Intent, request: BitmapTypeRequest) { + val modes = intArrayOf(R.string.circular_icon, + R.string.rounded_icon, + R.string.square_icon, + R.string.star_icon) + + fun BitmapRequestBuilder.toIcon(): Bitmap { + return this.into(96, 96).get() + } + + MaterialDialog.Builder(activity) + .title(R.string.icon_shape) + .negativeText(android.R.string.cancel) + .items(modes.map { getString(it) }) + .itemsCallback { dialog, view, i, charSequence -> + Observable.fromCallable { + // i = 0: Circular icon + // i = 1: Rounded icon + // i = 2: Square icon + // i = 3: Star icon (because boredom) + when (i) { + 0 -> request.transform(CropCircleTransformation(context)).toIcon() + 1 -> request.transform(RoundedCornersTransformation(context, 5, 0)).toIcon() + 2 -> request.transform(CropSquareTransformation(context)).toIcon() + 3 -> request.transform(CenterCrop(context), MaskTransformation(context, R.drawable.mask_star)).toIcon() + else -> null + } + }.subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ if (it != null) createShortcut(addIntent, it) }, + { context.toast(R.string.icon_creation_fail) }) + }.show() + } + + fun createShortcut(addIntent: Intent, icon: Bitmap) { + //Send shortcut intent + addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, icon) + context.sendBroadcast(addIntent) + //Go to launcher to show this shiny new shortcut! + val startMain = Intent(Intent.ACTION_MAIN) + startMain.addCategory(Intent.CATEGORY_HOME) + .flags = Intent.FLAG_ACTIVITY_NEW_TASK + activity.runOnUiThread { + startActivity(startMain) + } + } + /** * Update FAB with correct drawable. * diff --git a/app/src/main/res/drawable/ic_home_white_24dp.xml b/app/src/main/res/drawable/ic_home_white_24dp.xml new file mode 100644 index 0000000000..fafc05e0c9 --- /dev/null +++ b/app/src/main/res/drawable/ic_home_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/mask_star.png b/app/src/main/res/drawable/mask_star.png new file mode 100644 index 0000000000..5d3c119538 Binary files /dev/null and b/app/src/main/res/drawable/mask_star.png differ diff --git a/app/src/main/res/menu/manga_info.xml b/app/src/main/res/menu/manga_info.xml index e9aa77c9f9..76f105d1da 100644 --- a/app/src/main/res/menu/manga_info.xml +++ b/app/src/main/res/menu/manga_info.xml @@ -12,4 +12,8 @@ android:title="@string/action_open_in_browser" app:showAsAction="never"/> + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d77e2da59a..cb2d60fef6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -51,6 +51,7 @@ Remove Resume Open in browser + Add to home screen Change display mode Set filter Cancel @@ -225,6 +226,16 @@ Genres Share… Check out %1$s! at %2$s + Manga added to home screen + Icon type + Tachiyomi icon + Circular icon + Rounded icon + Square icon + Star icon + Shortcut title + Icon shape + Failed to create shortcut! Chapters @@ -305,6 +316,7 @@ Select cover image Select backup file + Select shortcut icon New update available!