package com.lazaronixon.rnturbolinks.activities; import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; import androidx.annotation.Nullable; import androidx.appcompat.widget.Toolbar; import com.facebook.common.executors.UiThreadImmediateExecutorService; import com.facebook.common.references.CloseableReference; import com.facebook.datasource.DataSource; import com.facebook.drawee.backends.pipeline.Fresco; import com.facebook.imagepipeline.core.ImagePipeline; import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber; import com.facebook.imagepipeline.image.CloseableImage; import com.facebook.imagepipeline.request.ImageRequest; import com.facebook.imagepipeline.request.ImageRequestBuilder; import com.facebook.react.ReactActivity; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.WritableMap; import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter; import com.facebook.react.views.imagehelper.ImageSource; import com.lazaronixon.rnturbolinks.R; import com.lazaronixon.rnturbolinks.util.NavBarStyle; import com.lazaronixon.rnturbolinks.util.TurbolinksAction; import com.lazaronixon.rnturbolinks.util.TurbolinksRoute; import com.lazaronixon.rnturbolinks.util.TurbolinksToolbar; import java.util.ArrayList; import static android.view.MenuItem.SHOW_AS_ACTION_ALWAYS; import static android.view.MenuItem.SHOW_AS_ACTION_NEVER; import static com.lazaronixon.rnturbolinks.RNTurbolinksModule.INTENT_INITIAL; import static com.lazaronixon.rnturbolinks.RNTurbolinksModule.INTENT_ROUTE; public abstract class ApplicationActivity extends ReactActivity { protected static final String TURBOLINKS_ACTION_PRESS = "turbolinksActionPress"; private static final String TURBOLINKS_TITLE_PRESS = "turbolinksTitlePress"; protected TurbolinksToolbar toolBar; protected TurbolinksRoute route; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); route = getIntent().getParcelableExtra(INTENT_ROUTE); } @Override protected void onRestart() { super.onRestart(); setNavBarStyle(NavBarStyle.getDefault()); } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { return super.onKeyUp(keyCode == KeyEvent.KEYCODE_VOLUME_UP ? KeyEvent.KEYCODE_MENU : keyCode, event); } @Override public boolean onPrepareOptionsMenu(Menu menu) { menu.clear(); if (route.getActions() != null) { for (int i = 0; i < route.getActions().size(); i++) { TurbolinksAction action = new TurbolinksAction(route.getActions().get(i)); MenuItem menuItem = menu.add(Menu.NONE, action.getId(), i, action.getTitle()); menuItem.setShowAsAction(action.getButton() ? SHOW_AS_ACTION_ALWAYS : SHOW_AS_ACTION_NEVER); if (action.getIcon() != null) setMenuItemIcon(action.getIcon(), menuItem); } } return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { onBackPressed(); return false; } else { handleActionPress(item.getItemId()); return true; } } @Override public void onBackPressed() { if (isInitial() || (isModal() && !isDismissable())) { moveTaskToBack(true); } else { super.onBackPressed(); } } public void renderTitle(String title, String subtitle) { getSupportActionBar().setTitle(title); getSupportActionBar().setSubtitle(subtitle); } public void setNavBarStyle(NavBarStyle style) { if (style.getBarTintColor() != null) toolBar.setBackgroundColor(style.getBarTintColor()); if (style.getTitleTextColor() != null) toolBar.setTitleTextColor(style.getTitleTextColor()); if (style.getSubtitleTextColor() != null) toolBar.setSubtitleTextColor(style.getSubtitleTextColor()); if (style.getMenuIcon() != null) setToolbarOverFlowIcon(style.getMenuIcon(), toolBar); } public void setActions(ArrayList<Bundle> actions) { route.setActions(actions); } public abstract void renderComponent(TurbolinksRoute route); public abstract void reloadVisitable(); public abstract void reloadSession(); public abstract void injectJavaScript(String script); protected abstract void handleActionPress(int itemId); protected RCTDeviceEventEmitter getEventEmitter() { return getReactInstanceManager().getCurrentReactContext().getJSModule(RCTDeviceEventEmitter.class); } protected void setupToolBar() { toolBar = findViewById(R.id.toolbar); toolBar.setTitle(""); toolBar.setVisibleDropDown(route.getVisibleDropDown()); setSupportActionBar(toolBar); setHiddenNavBar(); setDisplayHomeAsUpEnabled(!isInitial()); setNavBarStyle(NavBarStyle.getDefault()); } protected void handleTitlePress(final String component, final String url, final String path) { toolBar.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { WritableMap params = Arguments.createMap(); params.putString("component", component); params.putString("url", url); params.putString("path", path); ApplicationActivity.this.getEventEmitter().emit(TURBOLINKS_TITLE_PRESS, params); } }); } protected boolean isInitial() { return getIntent().getBooleanExtra(INTENT_INITIAL, true); } private void setDisplayHomeAsUpEnabled(boolean displayHomeAsUpEnabled) { getSupportActionBar().setDisplayHomeAsUpEnabled(displayHomeAsUpEnabled); } private void setHiddenNavBar() { if (route.getHidesNavBar() || route.getModal()) getSupportActionBar().hide(); } private boolean isModal() { return route.getModal(); } private boolean isDismissable() { return route.getDismissable(); } private void setToolbarOverFlowIcon(Bundle icon, final Toolbar toolBar) { bitmapFor(icon, getApplicationContext(), new BaseBitmapDataSubscriber() { @Override public void onNewResultImpl(@Nullable Bitmap bitmap) { toolBar.setOverflowIcon(new BitmapDrawable(getApplicationContext().getResources(), bitmap)); } @Override public void onFailureImpl(DataSource dataSource) { Log.e(ApplicationActivity.class.getName(), "Invalid bitmap: ", dataSource.getFailureCause()); } }); } private void setMenuItemIcon(Bundle icon, final MenuItem menuItem) { bitmapFor(icon, getApplicationContext(), new BaseBitmapDataSubscriber() { @Override public void onNewResultImpl(@Nullable Bitmap bitmap) { menuItem.setIcon(new BitmapDrawable(getApplicationContext().getResources(), bitmap)); } @Override public void onFailureImpl(DataSource dataSource) { Log.e(ApplicationActivity.class.getName(), "Invalid bitmap: ", dataSource.getFailureCause()); } }); } private void bitmapFor(Bundle image, Context context, BaseBitmapDataSubscriber baseBitmapDataSubscriber) { ImageSource source = new ImageSource(context, image.getString("uri")); ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(source.getUri()).build(); ImagePipeline imagePipeline = Fresco.getImagePipeline(); DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, context); dataSource.subscribe(baseBitmapDataSubscriber, UiThreadImmediateExecutorService.getInstance()); } }