/* * Copyright 2015 Priyesh Patel * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.chromium.fontinstaller.ui.install; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.TabLayout; import android.support.v4.app.ActivityCompat; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.content.ContextCompat; import android.support.v4.view.ViewPager; import android.util.SparseArray; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; import android.widget.TextView; import com.chromium.fontinstaller.BuildConfig; import com.chromium.fontinstaller.Injector; import com.chromium.fontinstaller.R; import com.chromium.fontinstaller.core.BackupManager; import com.chromium.fontinstaller.core.FontDownloader; import com.chromium.fontinstaller.core.FontInstaller; import com.chromium.fontinstaller.core.FontsterPreferences; import com.chromium.fontinstaller.core.exceptions.ShellCommandException; import com.chromium.fontinstaller.models.FontPackage; import com.chromium.fontinstaller.models.Style; import com.chromium.fontinstaller.ui.common.BaseActivity; import com.chromium.fontinstaller.ui.main.MainActivity; import com.chromium.fontinstaller.util.RebootDialog; import com.crashlytics.android.Crashlytics; import com.google.android.gms.ads.AdView; import javax.inject.Inject; import butterknife.Bind; import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers; import timber.log.Timber; import static com.chromium.fontinstaller.core.FontsterPreferences.Key; import static com.chromium.fontinstaller.util.ViewUtils.animGrowFromCenter; import static com.chromium.fontinstaller.util.ViewUtils.animShrinkToCenter; import static com.chromium.fontinstaller.util.ViewUtils.animSlideInBottom; import static com.chromium.fontinstaller.util.ViewUtils.animSlideUp; import static com.chromium.fontinstaller.util.ViewUtils.reveal; import static com.chromium.fontinstaller.util.ViewUtils.snackbar; public final class FontActivity extends BaseActivity implements TabLayout.OnTabSelectedListener { @Bind(R.id.font_name) TextView mFontTitle; @Bind(R.id.install_fab) FloatingActionButton mInstallButton; @Bind(R.id.download_progress) ProgressBar mDownloadProgress; @Bind(R.id.preview_pager) ViewPager mPreviewPager; @Bind(R.id.sliding_tabs) TabLayout mTabLayout; @Bind(R.id.error_container) ViewGroup mErrorContainer; @Bind(R.id.ad_view) AdView mAdView; @Inject BackupManager mBackupManager; @Inject FontsterPreferences mPreferences; private int mCurrentPage = 0; private FontPackage mFontPackage; private FontDownloader mFontDownloader; private PreviewFragment[] mPreviewPages = new PreviewFragment[3]; private boolean mFragmentsInitialized = false; private ProgressDialog mProgressDialog; static final SparseArray<Style> PREVIEW_STYLES = new SparseArray<Style>() {{ put(0, Style.REGULAR); put(1, Style.BOLD); put(2, Style.ITALIC); }}; public static final String FONT_NAME_KEY = "font_name"; public static Intent getLaunchIntent(final Context context, final String fontName) { final Intent intent = new Intent(context, FontActivity.class); intent.putExtra(FontActivity.FONT_NAME_KEY, fontName); return intent; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Injector.get().inject(this); setContentView(R.layout.activity_font); disableToolbarElevation(); showToolbarBackButton(); setToolbarTitle(""); final String fontName = getIntent().getStringExtra(FONT_NAME_KEY); sendToCrashlytics("Viewing " + fontName); mFontPackage = new FontPackage(fontName); mFontDownloader = new FontDownloader(mFontPackage); downloadPreviewStyles(); mFontTitle.setText(fontName); if (!BuildConfig.DEBUG) initializeAd(mAdView); } private void initializeFragments() { for (int i = 0; i < mPreviewPages.length; i++) { mPreviewPages[i] = PreviewFragment.newInstance(mFontPackage, PREVIEW_STYLES.get(i)); } mFragmentsInitialized = true; } private void downloadPreviewStyles() { if (isVisible(mErrorContainer)) hide(mErrorContainer); show(mDownloadProgress); mFontDownloader.downloadFontStyles(Style.REGULAR, Style.BOLD, Style.ITALIC) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( font -> Timber.i("downloadPreviewStyles: onNext: " + font.getName()), this::handleFailedDownload, this::setupViewPager); } private void handleFailedDownload(Throwable error) { Crashlytics.logException(error); Timber.e("Download failed: " + error.getMessage()); animSlideUp(mDownloadProgress, this); delay(() -> { hideGone(mDownloadProgress); animSlideInBottom(mErrorContainer, this); show(mErrorContainer); }, 400); } private void handleFailedInstall(Throwable error) { Crashlytics.logException(error); Timber.e("Install failed: " + error.getMessage()); delay(() -> { snackbar(R.string.font_activity_install_failed, findViewById(R.id.bottom_bar)); mProgressDialog.dismiss(); animGrowFromCenter(mInstallButton, this); show(mInstallButton); }, 500); } private void setupViewPager() { initializeFragments(); PreviewPagerAdapter pagerAdapter = new PreviewPagerAdapter(getSupportFragmentManager()); mPreviewPager.setOffscreenPageLimit(2); mPreviewPager.setAdapter(pagerAdapter); mTabLayout.setOnTabSelectedListener(this); mTabLayout.setupWithViewPager(mPreviewPager); mTabLayout.setSelectedTabIndicatorColor(ActivityCompat.getColor(this, android.R.color.white)); animateViewsIn(); } private void animateViewsIn() { animShrinkToCenter(mDownloadProgress, this); delay(() -> { hideGone(mDownloadProgress); animSlideInBottom(mTabLayout, this); show(mTabLayout); reveal(this, mPreviewPager, mInstallButton, R.color.primary_accent); delay(() -> { animGrowFromCenter(mInstallButton, this); show(mInstallButton); }, 300); }, 400); } private void startInstall() { sendToCrashlytics("Starting installation of " + mFontPackage.getName()); mProgressDialog = ProgressDialog.show(this, null, getString(R.string.font_activity_install_progress), true, false); mFontDownloader.downloadAllFonts() .last() .flatMap(o -> FontInstaller.install(mFontPackage, this)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( commandOutput -> { Timber.i("startInstall: onNext: " + commandOutput); sendToCrashlytics("Install of " + mFontPackage.getName() + " succeeded"); onInstallComplete(); }, error -> { Timber.e("startInstall: onError: " + error); sendToCrashlytics("Install of " + mFontPackage.getName() + " failed"); if (error instanceof FontDownloader.DownloadException) handleFailedDownload(error.getCause()); else if (error instanceof FontInstaller.InstallException || error instanceof ShellCommandException) handleFailedInstall(error); }); } private Style getCurrentPageStyle() { return PREVIEW_STYLES.get(mCurrentPage); } private void confirmInstall() { new AlertDialog.Builder(this) .setMessage(R.string.font_activity_confirm_install) .setNegativeButton(R.string.no, (dialog, id) -> dialog.dismiss()) .setPositiveButton(R.string.yes, (dialog, id) -> startInstall()) .create().show(); } private void promptBackup() { new PromptBackupDialog(this, backup -> { if (backup) startActivity(MainActivity.getLaunchIntent(MainActivity.BACKUP_RESTORE, this)); else confirmInstall(); }).show(); } public void onInstallFabClicked(View view) { if (mPreferences.getBoolean(Key.DISABLE_PROMPT_TO_BACKUP) || mBackupManager.backupExists()) { confirmInstall(); } else { promptBackup(); } } public void onRetryButtonClicked(View view) { downloadPreviewStyles(); } private void onInstallComplete() { mProgressDialog.dismiss(); delay(() -> { mInstallButton.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_done_white)); animGrowFromCenter(mInstallButton, this); show(mInstallButton); delay(() -> { if (!this.isFinishing()) new RebootDialog(this).show(); }, 200); }, 400); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_font, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.toggle_case: toggleCase(); return true; case R.id.try_font: showTryFontDialog(); return true; } return super.onOptionsItemSelected(item); } private void showTryFontDialog() { if (mFragmentsInitialized) { new TryFontDialog(mFontPackage, getCurrentPageStyle(), this::tryFontCallback, this).show(); } } private void tryFontCallback(String input) { if (input.isEmpty()) return; for (PreviewFragment fragment : mPreviewPages) { fragment.setPreviewText(input); } } private void toggleCase() { if (mFragmentsInitialized) { for (PreviewFragment fragment : mPreviewPages) { fragment.toggleCase(); } } } @Override public void onTabSelected(TabLayout.Tab tab) { mCurrentPage = tab.getPosition(); } @Override public void onTabUnselected(TabLayout.Tab tab) { } @Override public void onTabReselected(TabLayout.Tab tab) { } private final class PreviewPagerAdapter extends FragmentPagerAdapter { private final String[] tabTitles = { getString(R.string.font_activity_tab_regular), getString(R.string.font_activity_tab_bold), getString(R.string.font_activity_tab_italic) }; public PreviewPagerAdapter(FragmentManager fragmentManager) { super(fragmentManager); } @Override public Object instantiateItem(ViewGroup container, int position) { PreviewFragment fragment = (PreviewFragment) super.instantiateItem(container, position); mPreviewPages[position] = fragment; return fragment; } @Override public Fragment getItem(int position) { return mPreviewPages[position]; } @Override public CharSequence getPageTitle(int position) { return tabTitles[position]; } @Override public int getCount() { return mPreviewPages.length; } } }