diff --git a/app/src/main/java/fr/free/nrw/commons/LocationPicker/LocationPickerActivity.java b/app/src/main/java/fr/free/nrw/commons/LocationPicker/LocationPickerActivity.java index 2f05705ba..40f360a24 100644 --- a/app/src/main/java/fr/free/nrw/commons/LocationPicker/LocationPickerActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/LocationPicker/LocationPickerActivity.java @@ -367,7 +367,7 @@ public class LocationPickerActivity extends BaseActivity implements */ private void removeLocationFromImage() { if (media != null) { - compositeDisposable.add(coordinateEditHelper.makeCoordinatesEdit(getApplicationContext() + getCompositeDisposable().add(coordinateEditHelper.makeCoordinatesEdit(getApplicationContext() , media, "0.0", "0.0", "0.0f") .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -479,7 +479,7 @@ public class LocationPickerActivity extends BaseActivity implements } try { - compositeDisposable.add( + getCompositeDisposable().add( coordinateEditHelper.makeCoordinatesEdit(getApplicationContext(), media, Latitude, Longitude, Accuracy) .subscribeOn(Schedulers.io()) diff --git a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt index dbab629ff..3912a4d12 100644 --- a/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt +++ b/app/src/main/java/fr/free/nrw/commons/customselector/ui/selector/ImageFragment.kt @@ -1,6 +1,7 @@ package fr.free.nrw.commons.customselector.ui.selector import android.app.Activity +import android.content.Context import android.content.Context.MODE_PRIVATE import android.content.SharedPreferences import android.os.Bundle @@ -346,7 +347,7 @@ class ImageFragment : context .getSharedPreferences( "CustomSelector", - BaseActivity.MODE_PRIVATE, + MODE_PRIVATE, )?.let { prefs -> prefs.edit()?.let { editor -> editor.putLong("ItemId", imageAdapter.getImageIdAt(position))?.apply() diff --git a/app/src/main/java/fr/free/nrw/commons/explore/SearchActivity.java b/app/src/main/java/fr/free/nrw/commons/explore/SearchActivity.java index abb27184f..934bff6ec 100644 --- a/app/src/main/java/fr/free/nrw/commons/explore/SearchActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/explore/SearchActivity.java @@ -104,7 +104,7 @@ public class SearchActivity extends BaseActivity viewPagerAdapter.setTabData(fragmentList, titleList); viewPagerAdapter.notifyDataSetChanged(); - compositeDisposable.add(RxSearchView.queryTextChanges(binding.searchBox) + getCompositeDisposable().add(RxSearchView.queryTextChanges(binding.searchBox) .takeUntil(RxView.detaches(binding.searchBox)) .debounce(500, TimeUnit.MILLISECONDS) .observeOn(AndroidSchedulers.mainThread()) @@ -284,7 +284,7 @@ public class SearchActivity extends BaseActivity @Override protected void onDestroy() { super.onDestroy(); //Dispose the disposables when the activity is destroyed - compositeDisposable.dispose(); + getCompositeDisposable().dispose(); binding = null; } } diff --git a/app/src/main/java/fr/free/nrw/commons/notification/NotificationActivity.java b/app/src/main/java/fr/free/nrw/commons/notification/NotificationActivity.java index 572dd0317..b57df4948 100644 --- a/app/src/main/java/fr/free/nrw/commons/notification/NotificationActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/notification/NotificationActivity.java @@ -133,7 +133,7 @@ public class NotificationActivity extends BaseActivity { } binding.progressBar.setVisibility(View.GONE); }); - compositeDisposable.add(disposable); + getCompositeDisposable().add(disposable); } @@ -178,7 +178,7 @@ public class NotificationActivity extends BaseActivity { Timber.d("Add notifications"); if (mNotificationWorkerFragment == null) { binding.progressBar.setVisibility(View.VISIBLE); - compositeDisposable.add(controller.getNotifications(archived) + getCompositeDisposable().add(controller.getNotifications(archived) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(notificationList -> { diff --git a/app/src/main/java/fr/free/nrw/commons/profile/ProfileActivity.java b/app/src/main/java/fr/free/nrw/commons/profile/ProfileActivity.java index c6d09fdc6..60a0f47a1 100644 --- a/app/src/main/java/fr/free/nrw/commons/profile/ProfileActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/profile/ProfileActivity.java @@ -157,7 +157,7 @@ public class ProfileActivity extends BaseActivity { @Override public void onDestroy() { super.onDestroy(); - compositeDisposable.clear(); + getCompositeDisposable().clear(); } /** diff --git a/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.java b/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.java deleted file mode 100644 index 95ec00dc6..000000000 --- a/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.java +++ /dev/null @@ -1,66 +0,0 @@ -package fr.free.nrw.commons.theme; - -import android.content.res.Configuration; -import android.os.Bundle; -import android.util.DisplayMetrics; -import android.view.WindowManager; -import javax.inject.Inject; -import javax.inject.Named; -import fr.free.nrw.commons.R; -import fr.free.nrw.commons.di.CommonsDaggerAppCompatActivity; -import fr.free.nrw.commons.kvstore.JsonKvStore; -import fr.free.nrw.commons.utils.SystemThemeUtils; -import io.reactivex.disposables.CompositeDisposable; - -public abstract class BaseActivity extends CommonsDaggerAppCompatActivity { - @Inject - @Named("default_preferences") - public JsonKvStore defaultKvStore; - - @Inject - SystemThemeUtils systemThemeUtils; - - protected CompositeDisposable compositeDisposable = new CompositeDisposable(); - protected boolean wasPreviouslyDarkTheme; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - wasPreviouslyDarkTheme = systemThemeUtils.isDeviceInNightMode(); - setTheme(wasPreviouslyDarkTheme ? R.style.DarkAppTheme : R.style.LightAppTheme); - float fontScale = android.provider.Settings.System.getFloat( - getBaseContext().getContentResolver(), - android.provider.Settings.System.FONT_SCALE, - 1f); - adjustFontScale(getResources().getConfiguration(), fontScale); - } - - @Override - protected void onResume() { - // Restart activity if theme is changed - if (wasPreviouslyDarkTheme != systemThemeUtils.isDeviceInNightMode()) { - recreate(); - } - - super.onResume(); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - compositeDisposable.clear(); - } - - /** - * Apply fontScale on device - */ - public void adjustFontScale(Configuration configuration, float scale) { - configuration.fontScale = scale; - final DisplayMetrics metrics = getResources().getDisplayMetrics(); - final WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); - wm.getDefaultDisplay().getMetrics(metrics); - metrics.scaledDensity = configuration.fontScale * metrics.density; - getBaseContext().getResources().updateConfiguration(configuration, metrics); - } - -} diff --git a/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.kt b/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.kt new file mode 100644 index 000000000..d2d936460 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/theme/BaseActivity.kt @@ -0,0 +1,65 @@ +package fr.free.nrw.commons.theme + +import android.content.res.Configuration +import android.os.Bundle +import android.util.DisplayMetrics +import android.view.WindowManager +import javax.inject.Inject +import javax.inject.Named +import fr.free.nrw.commons.R +import fr.free.nrw.commons.di.CommonsDaggerAppCompatActivity +import fr.free.nrw.commons.kvstore.JsonKvStore +import fr.free.nrw.commons.utils.SystemThemeUtils +import io.reactivex.disposables.CompositeDisposable + + +abstract class BaseActivity : CommonsDaggerAppCompatActivity() { + + @Inject + @field:Named("default_preferences") + lateinit var defaultKvStore: JsonKvStore + + @Inject + lateinit var systemThemeUtils: SystemThemeUtils + + protected val compositeDisposable = CompositeDisposable() + protected var wasPreviouslyDarkTheme: Boolean = false + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + wasPreviouslyDarkTheme = systemThemeUtils.isDeviceInNightMode() + setTheme(if (wasPreviouslyDarkTheme) R.style.DarkAppTheme else R.style.LightAppTheme) + + val fontScale = android.provider.Settings.System.getFloat( + baseContext.contentResolver, + android.provider.Settings.System.FONT_SCALE, + 1f + ) + adjustFontScale(resources.configuration, fontScale) + } + + override fun onResume() { + // Restart activity if theme is changed + if (wasPreviouslyDarkTheme != systemThemeUtils.isDeviceInNightMode()) { + recreate() + } + super.onResume() + } + + override fun onDestroy() { + super.onDestroy() + compositeDisposable.clear() + } + + /** + * Apply fontScale on device + */ + fun adjustFontScale(configuration: Configuration, scale: Float) { + configuration.fontScale = scale + val metrics = resources.displayMetrics + val wm = getSystemService(WINDOW_SERVICE) as WindowManager + wm.defaultDisplay.getMetrics(metrics) + metrics.scaledDensity = configuration.fontScale * metrics.density + baseContext.resources.updateConfiguration(configuration, metrics) + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/ui/PasteSensitiveTextInputEditText.java b/app/src/main/java/fr/free/nrw/commons/ui/PasteSensitiveTextInputEditText.java deleted file mode 100644 index 0b82baf64..000000000 --- a/app/src/main/java/fr/free/nrw/commons/ui/PasteSensitiveTextInputEditText.java +++ /dev/null @@ -1,65 +0,0 @@ -package fr.free.nrw.commons.ui; - -import android.content.Context; -import android.content.res.TypedArray; -import android.os.Build.VERSION; -import android.util.AttributeSet; -import com.google.android.material.textfield.TextInputEditText; -import fr.free.nrw.commons.R; - -public class PasteSensitiveTextInputEditText extends TextInputEditText { - - private boolean formattingAllowed = true; - - public PasteSensitiveTextInputEditText(final Context context) { - super(context); - } - - public PasteSensitiveTextInputEditText(final Context context, final AttributeSet attrs) { - super(context, attrs); - formattingAllowed = extractFormattingAttribute(context, attrs); - } - - @Override - public boolean onTextContextMenuItem(int id) { - - // if not paste command, or formatting is allowed, return default - if(id != android.R.id.paste || formattingAllowed){ - return super.onTextContextMenuItem(id); - } - - // if its paste and formatting not allowed - boolean proceeded; - if(VERSION.SDK_INT >= 23) { - proceeded = super.onTextContextMenuItem(android.R.id.pasteAsPlainText); - }else { - proceeded = super.onTextContextMenuItem(id); - if (proceeded && getText() != null) { - // rewrite with plain text so formatting is lost - setText(getText().toString()); - setSelection(getText().length()); - } - } - return proceeded; - } - - private boolean extractFormattingAttribute(Context context, AttributeSet attrs){ - - boolean formatAllowed = true; - - TypedArray a = context.getTheme().obtainStyledAttributes( - attrs, R.styleable.PasteSensitiveTextInputEditText, 0, 0); - - try { - formatAllowed = a.getBoolean( - R.styleable.PasteSensitiveTextInputEditText_allowFormatting, true); - } finally { - a.recycle(); - } - return formatAllowed; - } - - public void setFormattingAllowed(boolean formattingAllowed){ - this.formattingAllowed = formattingAllowed; - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/ui/PasteSensitiveTextInputEditText.kt b/app/src/main/java/fr/free/nrw/commons/ui/PasteSensitiveTextInputEditText.kt new file mode 100644 index 000000000..56f795485 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/ui/PasteSensitiveTextInputEditText.kt @@ -0,0 +1,60 @@ +package fr.free.nrw.commons.ui + +import android.content.Context +import android.content.res.TypedArray +import android.os.Build +import android.os.Build.VERSION +import android.util.AttributeSet +import com.google.android.material.textfield.TextInputEditText +import fr.free.nrw.commons.R + + +class PasteSensitiveTextInputEditText @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null +) : TextInputEditText(context, attrs) { + + private var formattingAllowed: Boolean = true + + init { + if (attrs != null) { + formattingAllowed = extractFormattingAttribute(context, attrs) + } + } + + override fun onTextContextMenuItem(id: Int): Boolean { + // if not paste command, or formatting is allowed, return default + if (id != android.R.id.paste || formattingAllowed) { + return super.onTextContextMenuItem(id) + } + + // if it's paste and formatting not allowed + val proceeded: Boolean = if (VERSION.SDK_INT >= 23) { + super.onTextContextMenuItem(android.R.id.pasteAsPlainText) + } else { + val success = super.onTextContextMenuItem(id) + if (success && text != null) { + // rewrite with plain text so formatting is lost + setText(text.toString()) + setSelection(text?.length ?: 0) + } + success + } + return proceeded + } + + private fun extractFormattingAttribute(context: Context, attrs: AttributeSet): Boolean { + val a = context.theme.obtainStyledAttributes( + attrs, R.styleable.PasteSensitiveTextInputEditText, 0, 0 + ) + return try { + a.getBoolean(R.styleable.PasteSensitiveTextInputEditText_allowFormatting, true) + } finally { + a.recycle() + } + } + + fun setFormattingAllowed(formattingAllowed: Boolean) { + this.formattingAllowed = formattingAllowed + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/ui/widget/HtmlTextView.java b/app/src/main/java/fr/free/nrw/commons/ui/widget/HtmlTextView.java deleted file mode 100644 index 21af5ee78..000000000 --- a/app/src/main/java/fr/free/nrw/commons/ui/widget/HtmlTextView.java +++ /dev/null @@ -1,36 +0,0 @@ -package fr.free.nrw.commons.ui.widget; - -import android.content.Context; -import android.text.method.LinkMovementMethod; -import android.util.AttributeSet; - -import androidx.appcompat.widget.AppCompatTextView; - -import fr.free.nrw.commons.utils.StringUtil; - -/** - * An {@link AppCompatTextView} which formats the text to HTML displayable text and makes any - * links clickable. - */ -public class HtmlTextView extends AppCompatTextView { - - /** - * Constructs a new instance of HtmlTextView - * @param context the context of the view - * @param attrs the set of attributes for the view - */ - public HtmlTextView(Context context, AttributeSet attrs) { - super(context, attrs); - - setMovementMethod(LinkMovementMethod.getInstance()); - setText(StringUtil.fromHtml(getText().toString())); - } - - /** - * Sets the text to be displayed - * @param newText the text to be displayed - */ - public void setHtmlText(String newText) { - setText(StringUtil.fromHtml(newText)); - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/ui/widget/HtmlTextView.kt b/app/src/main/java/fr/free/nrw/commons/ui/widget/HtmlTextView.kt new file mode 100644 index 000000000..48433136f --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/ui/widget/HtmlTextView.kt @@ -0,0 +1,32 @@ +package fr.free.nrw.commons.ui.widget + +import android.content.Context +import android.text.method.LinkMovementMethod +import android.util.AttributeSet + +import androidx.appcompat.widget.AppCompatTextView + +import fr.free.nrw.commons.utils.StringUtil + +/** + * An [AppCompatTextView] which formats the text to HTML displayable text and makes any + * links clickable. + */ +class HtmlTextView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null +) : AppCompatTextView(context, attrs) { + + init { + movementMethod = LinkMovementMethod.getInstance() + text = StringUtil.fromHtml(text.toString()) + } + + /** + * Sets the text to be displayed + * @param newText the text to be displayed + */ + fun setHtmlText(newText: String) { + text = StringUtil.fromHtml(newText) + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/ui/widget/OverlayDialog.java b/app/src/main/java/fr/free/nrw/commons/ui/widget/OverlayDialog.java deleted file mode 100644 index f36219040..000000000 --- a/app/src/main/java/fr/free/nrw/commons/ui/widget/OverlayDialog.java +++ /dev/null @@ -1,70 +0,0 @@ -package fr.free.nrw.commons.ui.widget; - -import android.app.Dialog; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.os.Bundle; -import android.view.Gravity; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; - -import androidx.annotation.NonNull; -import androidx.fragment.app.DialogFragment; - -/** - * a formatted dialog fragment - * This class is used by NearbyInfoDialog - */ -public abstract class OverlayDialog extends DialogFragment { - - /** - * creates a DialogFragment with the correct style and theme - * @param savedInstanceState bundle re-constructed from a previous saved state - */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setStyle(STYLE_NO_FRAME, android.R.style.Theme_Holo_Light); - } - - /** - * When the view is created, sets the dialog layout to full screen - * - * @param view the view being used - * @param savedInstanceState bundle re-constructed from a previous saved state - */ - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - setDialogLayoutToFullScreen(); - super.onViewCreated(view, savedInstanceState); - } - - /** - * sets the dialog layout to fullscreen - */ - private void setDialogLayoutToFullScreen() { - Window window = getDialog().getWindow(); - WindowManager.LayoutParams wlp = window.getAttributes(); - window.requestFeature(Window.FEATURE_NO_TITLE); - wlp.gravity = Gravity.BOTTOM; - wlp.width = WindowManager.LayoutParams.MATCH_PARENT; - wlp.height = WindowManager.LayoutParams.MATCH_PARENT; - window.setAttributes(wlp); - } - - /** - * builds custom dialog container - * - * @param savedInstanceState the previously saved state - * @return the dialog - */ - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - Dialog dialog = super.onCreateDialog(savedInstanceState); - Window window = dialog.getWindow(); - window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); - return dialog; - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/ui/widget/OverlayDialog.kt b/app/src/main/java/fr/free/nrw/commons/ui/widget/OverlayDialog.kt new file mode 100644 index 000000000..5d4bc2b46 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/ui/widget/OverlayDialog.kt @@ -0,0 +1,64 @@ +package fr.free.nrw.commons.ui.widget + +import android.app.Dialog +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.view.Gravity +import android.view.View +import android.view.Window +import android.view.WindowManager + +import androidx.fragment.app.DialogFragment + +/** + * A formatted dialog fragment + * This class is used by NearbyInfoDialog + */ +abstract class OverlayDialog : DialogFragment() { + + /** + * Creates a DialogFragment with the correct style and theme + * @param savedInstanceState bundle re-constructed from a previous saved state + */ + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(STYLE_NO_FRAME, android.R.style.Theme_Holo_Light) + } + + /** + * When the view is created, sets the dialog layout to full screen + * + * @param view the view being used + * @param savedInstanceState bundle re-constructed from a previous saved state + */ + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + setDialogLayoutToFullScreen() + super.onViewCreated(view, savedInstanceState) + } + + /** + * Sets the dialog layout to fullscreen + */ + private fun setDialogLayoutToFullScreen() { + val window = dialog?.window ?: return + val wlp = window.attributes + window.requestFeature(Window.FEATURE_NO_TITLE) + wlp.gravity = Gravity.BOTTOM + wlp.width = WindowManager.LayoutParams.MATCH_PARENT + wlp.height = WindowManager.LayoutParams.MATCH_PARENT + window.attributes = wlp + } + + /** + * Builds custom dialog container + * + * @param savedInstanceState the previously saved state + * @return the dialog + */ + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val dialog = super.onCreateDialog(savedInstanceState) + dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + return dialog + } +}