diff --git a/android/android-base/src/main/java/org/isoron/androidbase/activities/BaseScreen.java b/android/android-base/src/main/java/org/isoron/androidbase/activities/BaseScreen.java deleted file mode 100644 index 331d91742..000000000 --- a/android/android-base/src/main/java/org/isoron/androidbase/activities/BaseScreen.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright (C) 2016 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.androidbase.activities; - -import android.content.*; -import android.graphics.*; -import android.graphics.drawable.*; -import android.net.*; -import android.os.*; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.StringRes; -import androidx.core.content.res.*; -import androidx.appcompat.app.*; -import androidx.appcompat.view.ActionMode; -import androidx.appcompat.widget.Toolbar; -import android.view.*; -import android.widget.*; - -import com.google.android.material.snackbar.Snackbar; - -import org.isoron.androidbase.*; -import org.isoron.androidbase.utils.*; - -import java.io.*; - -import static android.os.Build.VERSION.SDK_INT; -import static android.os.Build.VERSION_CODES.LOLLIPOP; -import static androidx.core.content.FileProvider.getUriForFile; - -/** - * Base class for all screens in the application. - *

- * Screens are responsible for deciding what root views and what menus should be - * attached to the main window. They are also responsible for showing other - * screens and for receiving their results. - */ -public class BaseScreen -{ - protected BaseActivity activity; - - @Nullable - private BaseRootView rootView; - - @Nullable - private BaseSelectionMenu selectionMenu; - - protected Snackbar snackbar; - - public BaseScreen(@NonNull BaseActivity activity) - { - this.activity = activity; - } - - @Deprecated - public static int getDefaultActionBarColor(Context context) - { - if (SDK_INT < LOLLIPOP) - { - return ResourcesCompat.getColor(context.getResources(), - R.color.grey_900, context.getTheme()); - } - else - { - StyledResources res = new StyledResources(context); - return res.getColor(R.attr.colorPrimary); - } - } - - @Deprecated - public static void setupActionBarColor(@NonNull AppCompatActivity activity, - int color) - { - - Toolbar toolbar = (Toolbar) activity.findViewById(R.id.toolbar); - if (toolbar == null) return; - - activity.setSupportActionBar(toolbar); - - ActionBar actionBar = activity.getSupportActionBar(); - if (actionBar == null) return; - - actionBar.setDisplayHomeAsUpEnabled(true); - - ColorDrawable drawable = new ColorDrawable(color); - actionBar.setBackgroundDrawable(drawable); - - if (SDK_INT >= LOLLIPOP) - { - int darkerColor = ColorUtils.mixColors(color, Color.BLACK, 0.75f); - activity.getWindow().setStatusBarColor(darkerColor); - - toolbar.setElevation(InterfaceUtils.dpToPixels(activity, 2)); - - View view = activity.findViewById(R.id.toolbarShadow); - if (view != null) view.setVisibility(View.GONE); - - view = activity.findViewById(R.id.headerShadow); - if (view != null) view.setVisibility(View.GONE); - } - } - - /** - * Notifies the screen that its contents should be updated. - */ - public void invalidate() - { - if (rootView == null) return; - rootView.invalidate(); - } - - public void invalidateToolbar() - { - if (rootView == null) return; - - activity.runOnUiThread(() -> - { - Toolbar toolbar = rootView.getToolbar(); - activity.setSupportActionBar(toolbar); - ActionBar actionBar = activity.getSupportActionBar(); - if (actionBar == null) return; - - actionBar.setDisplayHomeAsUpEnabled(rootView.getDisplayHomeAsUp()); - - int color = rootView.getToolbarColor(); - setActionBarColor(actionBar, color); - setStatusBarColor(color); - }); - } - - /** - * Called when another Activity has finished, and has returned some result. - * - * @param requestCode the request code originally supplied to {@link - * android.app.Activity#startActivityForResult(Intent, - * int, Bundle)}. - * @param resultCode the result code sent by the other activity. - * @param data an Intent containing extra data sent by the other - * activity. - * @see {@link android.app.Activity#onActivityResult(int, int, Intent)} - */ - public void onResult(int requestCode, int resultCode, Intent data) - { - } - - - /** - * Called after activity has been recreated, and the dialogs should be - * reattached to their controllers. - */ - public void reattachDialogs() - { - } - - /** - * Sets the menu to be shown by this screen. - *

- * This menu will be visible if when there is no active selection operation. - * If the provided menu is null, then no menu will be shown. - * - * @param menu the menu to be shown. - */ - public void setMenu(@Nullable BaseMenu menu) - { - activity.setBaseMenu(menu); - } - - /** - * Sets the root view for this screen. - * - * @param rootView the root view for this screen. - */ - public void setRootView(@Nullable BaseRootView rootView) - { - this.rootView = rootView; - activity.setContentView(rootView); - if (rootView == null) return; - rootView.onAttachedToScreen(this); - invalidateToolbar(); - } - - /** - * Sets the menu to be shown when a selection is active on the screen. - * - * @param menu the menu to be shown during a selection - */ - public void setSelectionMenu(@Nullable BaseSelectionMenu menu) - { - this.selectionMenu = menu; - } - - /** - * Shows a message on the screen. - * - * @param stringId the string resource id for this message. - */ - public void showMessage(@StringRes Integer stringId) - { - if (stringId == null || rootView == null) return; - if (snackbar == null) - { - snackbar = Snackbar.make(rootView, stringId, Snackbar.LENGTH_SHORT); - int tvId = R.id.snackbar_text; - TextView tv = (TextView) snackbar.getView().findViewById(tvId); - tv.setTextColor(Color.WHITE); - } - else snackbar.setText(stringId); - snackbar.show(); - } - - public void showSendEmailScreen(@StringRes int toId, - @StringRes int subjectId, - String content) - { - String to = activity.getString(toId); - String subject = activity.getString(subjectId); - - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_SEND); - intent.setType("message/rfc822"); - intent.putExtra(Intent.EXTRA_EMAIL, new String[]{ to }); - intent.putExtra(Intent.EXTRA_SUBJECT, subject); - intent.putExtra(Intent.EXTRA_TEXT, content); - activity.startActivity(intent); - } - - public void showSendFileScreen(@NonNull String archiveFilename) - { - File file = new File(archiveFilename); - Uri fileUri = getUriForFile(activity, "org.isoron.uhabits", file); - - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_SEND); - intent.setType("application/zip"); - intent.putExtra(Intent.EXTRA_STREAM, fileUri); - intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - activity.startActivity(intent); - } - - /** - * Instructs the screen to start a selection. - *

- * If a selection menu was provided, this menu will be shown instead of the - * regular one. - */ - public void startSelection() - { - activity.startSupportActionMode(new ActionModeWrapper()); - } - - private void setActionBarColor(@NonNull ActionBar actionBar, int color) - { - ColorDrawable drawable = new ColorDrawable(color); - actionBar.setBackgroundDrawable(drawable); - } - - private void setStatusBarColor(int baseColor) - { - if (SDK_INT < LOLLIPOP) return; - - int darkerColor = ColorUtils.mixColors(baseColor, Color.BLACK, 0.75f); - activity.getWindow().setStatusBarColor(darkerColor); - } - - private class ActionModeWrapper implements ActionMode.Callback - { - @Override - public boolean onActionItemClicked(@Nullable ActionMode mode, - @Nullable MenuItem item) - { - if (item == null || selectionMenu == null) return false; - return selectionMenu.onItemClicked(item); - } - - @Override - public boolean onCreateActionMode(@Nullable ActionMode mode, - @Nullable Menu menu) - { - if (selectionMenu == null) return false; - if (mode == null || menu == null) return false; - selectionMenu.onCreate(activity.getMenuInflater(), mode, menu); - return true; - } - - @Override - public void onDestroyActionMode(@Nullable ActionMode mode) - { - if (selectionMenu == null) return; - selectionMenu.onFinish(); - } - - @Override - public boolean onPrepareActionMode(@Nullable ActionMode mode, - @Nullable Menu menu) - { - if (selectionMenu == null || menu == null) return false; - return selectionMenu.onPrepare(menu); - } - } -} diff --git a/android/android-base/src/main/java/org/isoron/androidbase/activities/BaseScreen.kt b/android/android-base/src/main/java/org/isoron/androidbase/activities/BaseScreen.kt new file mode 100644 index 000000000..0d327b37e --- /dev/null +++ b/android/android-base/src/main/java/org/isoron/androidbase/activities/BaseScreen.kt @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.androidbase.activities + +import android.content.Context +import android.content.Intent +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Build.VERSION +import android.os.Build.VERSION_CODES +import android.view.Menu +import android.view.MenuItem +import android.view.View +import android.widget.TextView +import androidx.annotation.StringRes +import androidx.appcompat.app.ActionBar +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.view.ActionMode +import androidx.appcompat.widget.Toolbar +import androidx.core.content.FileProvider +import androidx.core.content.res.ResourcesCompat +import com.google.android.material.snackbar.Snackbar +import org.isoron.androidbase.R +import org.isoron.androidbase.utils.ColorUtils.mixColors +import org.isoron.androidbase.utils.InterfaceUtils.dpToPixels +import org.isoron.androidbase.utils.StyledResources +import java.io.File + +/** + * Base class for all screens in the application. + * + * + * Screens are responsible for deciding what root views and what menus should be + * attached to the main window. They are also responsible for showing other + * screens and for receiving their results. + */ +open class BaseScreen(@JvmField protected var activity: BaseActivity) { + private var rootView: BaseRootView? = null + private var selectionMenu: BaseSelectionMenu? = null + protected var snackbar: Snackbar? = null + + /** + * Notifies the screen that its contents should be updated. + */ + fun invalidate() { + if (rootView == null) return + rootView!!.invalidate() + } + + fun invalidateToolbar() { + if (rootView == null) return + activity.runOnUiThread { + val toolbar = rootView!!.getToolbar() + activity.setSupportActionBar(toolbar) + val actionBar = activity.supportActionBar ?: return@runOnUiThread + actionBar.setDisplayHomeAsUpEnabled(rootView!!.displayHomeAsUp) + val color = rootView!!.getToolbarColor() + setActionBarColor(actionBar, color) + setStatusBarColor(color) + } + } + + /** + * Called when another Activity has finished, and has returned some result. + * + * @param requestCode the request code originally supplied to [ ][android.app.Activity.startActivityForResult]. + * @param resultCode the result code sent by the other activity. + * @param data an Intent containing extra data sent by the other + * activity. + * @see {@link android.app.Activity.onActivityResult + */ + open fun onResult(requestCode: Int, resultCode: Int, data: Intent?) {} + + /** + * Called after activity has been recreated, and the dialogs should be + * reattached to their controllers. + */ + open fun reattachDialogs() {} + + /** + * Sets the menu to be shown by this screen. + * + * + * This menu will be visible if when there is no active selection operation. + * If the provided menu is null, then no menu will be shown. + * + * @param menu the menu to be shown. + */ + fun setMenu(menu: BaseMenu?) { + activity.setBaseMenu(menu) + } + + /** + * Sets the root view for this screen. + * + * @param rootView the root view for this screen. + */ + fun setRootView(rootView: BaseRootView?) { + this.rootView = rootView + activity.setContentView(rootView) + if (rootView == null) return + rootView.onAttachedToScreen(this) + invalidateToolbar() + } + + /** + * Sets the menu to be shown when a selection is active on the screen. + * + * @param menu the menu to be shown during a selection + */ + fun setSelectionMenu(menu: BaseSelectionMenu?) { + selectionMenu = menu + } + + /** + * Shows a message on the screen. + * + * @param stringId the string resource id for this message. + */ + fun showMessage(@StringRes stringId: Int?) { + if (stringId == null || rootView == null) return + if (snackbar == null) { + snackbar = Snackbar.make(rootView!!, stringId, Snackbar.LENGTH_SHORT) + val tvId = R.id.snackbar_text + val tv = snackbar!!.view.findViewById(tvId) as TextView + tv.setTextColor(Color.WHITE) + } else snackbar!!.setText(stringId) + snackbar!!.show() + } + + fun showSendEmailScreen(@StringRes toId: Int, + @StringRes subjectId: Int, + content: String?) { + val to = activity.getString(toId) + val subject = activity.getString(subjectId) + val intent = Intent() + intent.action = Intent.ACTION_SEND + intent.type = "message/rfc822" + intent.putExtra(Intent.EXTRA_EMAIL, arrayOf(to)) + intent.putExtra(Intent.EXTRA_SUBJECT, subject) + intent.putExtra(Intent.EXTRA_TEXT, content) + activity.startActivity(intent) + } + + fun showSendFileScreen(archiveFilename: String) { + val file = File(archiveFilename) + val fileUri = FileProvider.getUriForFile(activity, "org.isoron.uhabits", file) + val intent = Intent() + intent.action = Intent.ACTION_SEND + intent.type = "application/zip" + intent.putExtra(Intent.EXTRA_STREAM, fileUri) + intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION + activity.startActivity(intent) + } + + /** + * Instructs the screen to start a selection. + * + * + * If a selection menu was provided, this menu will be shown instead of the + * regular one. + */ + fun startSelection() { + activity.startSupportActionMode(ActionModeWrapper()) + } + + private fun setActionBarColor(actionBar: ActionBar, color: Int) { + val drawable = ColorDrawable(color) + actionBar.setBackgroundDrawable(drawable) + } + + private fun setStatusBarColor(baseColor: Int) { + if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) return + val darkerColor = mixColors(baseColor, Color.BLACK, 0.75f) + activity.window.statusBarColor = darkerColor + } + + private inner class ActionModeWrapper : ActionMode.Callback { + override fun onActionItemClicked(mode: ActionMode?, + item: MenuItem?): Boolean { + return if (item == null || selectionMenu == null) false else selectionMenu!!.onItemClicked(item) + } + + override fun onCreateActionMode(mode: ActionMode?, + menu: Menu?): Boolean { + if (selectionMenu == null) return false + if (mode == null || menu == null) return false + selectionMenu!!.onCreate(activity.menuInflater, mode, menu) + return true + } + + override fun onDestroyActionMode(mode: ActionMode?) { + if (selectionMenu == null) return + selectionMenu!!.onFinish() + } + + override fun onPrepareActionMode(mode: ActionMode?, + menu: Menu?): Boolean { + return if (selectionMenu == null || menu == null) false else selectionMenu!!.onPrepare(menu) + } + } + + companion object { + @JvmStatic + @Deprecated("") + fun getDefaultActionBarColor(context: Context): Int { + return if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) { + ResourcesCompat.getColor(context.resources, + R.color.grey_900, context.theme) + } else { + val res = StyledResources(context) + res.getColor(R.attr.colorPrimary) + } + } + + @JvmStatic + @Deprecated("") + fun setupActionBarColor(activity: AppCompatActivity, + color: Int) { + val toolbar = activity.findViewById(R.id.toolbar) as Toolbar ?: return + activity.setSupportActionBar(toolbar) + val actionBar = activity.supportActionBar ?: return + actionBar.setDisplayHomeAsUpEnabled(true) + val drawable = ColorDrawable(color) + actionBar.setBackgroundDrawable(drawable) + if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { + val darkerColor = mixColors(color, Color.BLACK, 0.75f) + activity.window.statusBarColor = darkerColor + toolbar.elevation = dpToPixels(activity, 2f) + var view = activity.findViewById(R.id.toolbarShadow) + if (view != null) view.visibility = View.GONE + view = activity.findViewById(R.id.headerShadow) + if (view != null) view.visibility = View.GONE + } + } + } + +} \ No newline at end of file