Migrated ui and theme module to Kotlin

This commit is contained in:
Saifuddin 2024-11-20 17:00:41 +05:30
parent 1a36d1ffd2
commit 0bb1df819a
9 changed files with 144 additions and 159 deletions

View file

@ -367,7 +367,7 @@ public class LocationPickerActivity extends BaseActivity implements
*/ */
private void removeLocationFromImage() { private void removeLocationFromImage() {
if (media != null) { if (media != null) {
compositeDisposable.add(coordinateEditHelper.makeCoordinatesEdit(getApplicationContext() getCompositeDisposable().add(coordinateEditHelper.makeCoordinatesEdit(getApplicationContext()
, media, "0.0", "0.0", "0.0f") , media, "0.0", "0.0", "0.0f")
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
@ -479,7 +479,7 @@ public class LocationPickerActivity extends BaseActivity implements
} }
try { try {
compositeDisposable.add( getCompositeDisposable().add(
coordinateEditHelper.makeCoordinatesEdit(getApplicationContext(), media, coordinateEditHelper.makeCoordinatesEdit(getApplicationContext(), media,
Latitude, Longitude, Accuracy) Latitude, Longitude, Accuracy)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())

View file

@ -1,6 +1,7 @@
package fr.free.nrw.commons.customselector.ui.selector package fr.free.nrw.commons.customselector.ui.selector
import android.app.Activity import android.app.Activity
import android.content.Context
import android.content.Context.MODE_PRIVATE import android.content.Context.MODE_PRIVATE
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
@ -346,7 +347,7 @@ class ImageFragment :
context context
.getSharedPreferences( .getSharedPreferences(
"CustomSelector", "CustomSelector",
BaseActivity.MODE_PRIVATE, MODE_PRIVATE,
)?.let { prefs -> )?.let { prefs ->
prefs.edit()?.let { editor -> prefs.edit()?.let { editor ->
editor.putLong("ItemId", imageAdapter.getImageIdAt(position))?.apply() editor.putLong("ItemId", imageAdapter.getImageIdAt(position))?.apply()

View file

@ -104,7 +104,7 @@ public class SearchActivity extends BaseActivity
viewPagerAdapter.setTabData(fragmentList, titleList); viewPagerAdapter.setTabData(fragmentList, titleList);
viewPagerAdapter.notifyDataSetChanged(); viewPagerAdapter.notifyDataSetChanged();
compositeDisposable.add(RxSearchView.queryTextChanges(binding.searchBox) getCompositeDisposable().add(RxSearchView.queryTextChanges(binding.searchBox)
.takeUntil(RxView.detaches(binding.searchBox)) .takeUntil(RxView.detaches(binding.searchBox))
.debounce(500, TimeUnit.MILLISECONDS) .debounce(500, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
@ -284,7 +284,7 @@ public class SearchActivity extends BaseActivity
@Override protected void onDestroy() { @Override protected void onDestroy() {
super.onDestroy(); super.onDestroy();
//Dispose the disposables when the activity is destroyed //Dispose the disposables when the activity is destroyed
compositeDisposable.dispose(); getCompositeDisposable().dispose();
binding = null; binding = null;
} }
} }

View file

@ -133,7 +133,7 @@ public class NotificationActivity extends BaseActivity {
} }
binding.progressBar.setVisibility(View.GONE); binding.progressBar.setVisibility(View.GONE);
}); });
compositeDisposable.add(disposable); getCompositeDisposable().add(disposable);
} }
@ -178,7 +178,7 @@ public class NotificationActivity extends BaseActivity {
Timber.d("Add notifications"); Timber.d("Add notifications");
if (mNotificationWorkerFragment == null) { if (mNotificationWorkerFragment == null) {
binding.progressBar.setVisibility(View.VISIBLE); binding.progressBar.setVisibility(View.VISIBLE);
compositeDisposable.add(controller.getNotifications(archived) getCompositeDisposable().add(controller.getNotifications(archived)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(notificationList -> { .subscribe(notificationList -> {

View file

@ -157,7 +157,7 @@ public class ProfileActivity extends BaseActivity {
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
compositeDisposable.clear(); getCompositeDisposable().clear();
} }
/** /**

View file

@ -1,66 +1,65 @@
package fr.free.nrw.commons.theme; package fr.free.nrw.commons.theme
import android.content.res.Configuration; import android.content.res.Configuration
import android.os.Bundle; import android.os.Bundle
import android.util.DisplayMetrics; import android.util.DisplayMetrics
import android.view.WindowManager; import android.view.WindowManager
import javax.inject.Inject; import javax.inject.Inject
import javax.inject.Named; import javax.inject.Named
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R
import fr.free.nrw.commons.di.CommonsDaggerAppCompatActivity; import fr.free.nrw.commons.di.CommonsDaggerAppCompatActivity
import fr.free.nrw.commons.kvstore.JsonKvStore; import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.utils.SystemThemeUtils; import fr.free.nrw.commons.utils.SystemThemeUtils
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable
public abstract class BaseActivity extends CommonsDaggerAppCompatActivity {
@Inject abstract class BaseActivity : CommonsDaggerAppCompatActivity() {
@Named("default_preferences")
public JsonKvStore defaultKvStore;
@Inject @Inject
SystemThemeUtils systemThemeUtils; @field:Named("default_preferences")
lateinit var defaultKvStore: JsonKvStore
protected CompositeDisposable compositeDisposable = new CompositeDisposable(); @Inject
protected boolean wasPreviouslyDarkTheme; lateinit var systemThemeUtils: SystemThemeUtils
@Override protected val compositeDisposable = CompositeDisposable()
protected void onCreate(Bundle savedInstanceState) { protected var wasPreviouslyDarkTheme: Boolean = false
super.onCreate(savedInstanceState);
wasPreviouslyDarkTheme = systemThemeUtils.isDeviceInNightMode(); override fun onCreate(savedInstanceState: Bundle?) {
setTheme(wasPreviouslyDarkTheme ? R.style.DarkAppTheme : R.style.LightAppTheme); super.onCreate(savedInstanceState)
float fontScale = android.provider.Settings.System.getFloat( wasPreviouslyDarkTheme = systemThemeUtils.isDeviceInNightMode()
getBaseContext().getContentResolver(), 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, android.provider.Settings.System.FONT_SCALE,
1f); 1f
adjustFontScale(getResources().getConfiguration(), fontScale); )
adjustFontScale(resources.configuration, fontScale)
} }
@Override override fun onResume() {
protected void onResume() {
// Restart activity if theme is changed // Restart activity if theme is changed
if (wasPreviouslyDarkTheme != systemThemeUtils.isDeviceInNightMode()) { if (wasPreviouslyDarkTheme != systemThemeUtils.isDeviceInNightMode()) {
recreate(); recreate()
} }
super.onResume()
super.onResume();
} }
@Override override fun onDestroy() {
protected void onDestroy() { super.onDestroy()
super.onDestroy(); compositeDisposable.clear()
compositeDisposable.clear();
} }
/** /**
* Apply fontScale on device * Apply fontScale on device
*/ */
public void adjustFontScale(Configuration configuration, float scale) { fun adjustFontScale(configuration: Configuration, scale: Float) {
configuration.fontScale = scale; configuration.fontScale = scale
final DisplayMetrics metrics = getResources().getDisplayMetrics(); val metrics = resources.displayMetrics
final WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); val wm = getSystemService(WINDOW_SERVICE) as WindowManager
wm.getDefaultDisplay().getMetrics(metrics); wm.defaultDisplay.getMetrics(metrics)
metrics.scaledDensity = configuration.fontScale * metrics.density; metrics.scaledDensity = configuration.fontScale * metrics.density
getBaseContext().getResources().updateConfiguration(configuration, metrics); baseContext.resources.updateConfiguration(configuration, metrics)
} }
} }

View file

@ -1,65 +1,60 @@
package fr.free.nrw.commons.ui; package fr.free.nrw.commons.ui
import android.content.Context; import android.content.Context
import android.content.res.TypedArray; import android.content.res.TypedArray
import android.os.Build.VERSION; import android.os.Build
import android.util.AttributeSet; import android.os.Build.VERSION
import com.google.android.material.textfield.TextInputEditText; import android.util.AttributeSet
import fr.free.nrw.commons.R; import com.google.android.material.textfield.TextInputEditText
import fr.free.nrw.commons.R
public class PasteSensitiveTextInputEditText extends TextInputEditText {
private boolean formattingAllowed = true; class PasteSensitiveTextInputEditText @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : TextInputEditText(context, attrs) {
public PasteSensitiveTextInputEditText(final Context context) { private var formattingAllowed: Boolean = true
super(context);
init {
if (attrs != null) {
formattingAllowed = extractFormattingAttribute(context, attrs)
}
} }
public PasteSensitiveTextInputEditText(final Context context, final AttributeSet attrs) { override fun onTextContextMenuItem(id: Int): Boolean {
super(context, attrs);
formattingAllowed = extractFormattingAttribute(context, attrs);
}
@Override
public boolean onTextContextMenuItem(int id) {
// if not paste command, or formatting is allowed, return default // if not paste command, or formatting is allowed, return default
if(id != android.R.id.paste || formattingAllowed){ if (id != android.R.id.paste || formattingAllowed) {
return super.onTextContextMenuItem(id); return super.onTextContextMenuItem(id)
} }
// if its paste and formatting not allowed // if it's paste and formatting not allowed
boolean proceeded; val proceeded: Boolean = if (VERSION.SDK_INT >= 23) {
if(VERSION.SDK_INT >= 23) { super.onTextContextMenuItem(android.R.id.pasteAsPlainText)
proceeded = super.onTextContextMenuItem(android.R.id.pasteAsPlainText); } else {
}else { val success = super.onTextContextMenuItem(id)
proceeded = super.onTextContextMenuItem(id); if (success && text != null) {
if (proceeded && getText() != null) {
// rewrite with plain text so formatting is lost // rewrite with plain text so formatting is lost
setText(getText().toString()); setText(text.toString())
setSelection(getText().length()); setSelection(text?.length ?: 0)
} }
success
} }
return proceeded; return proceeded
} }
private boolean extractFormattingAttribute(Context context, AttributeSet attrs){ private fun extractFormattingAttribute(context: Context, attrs: AttributeSet): Boolean {
val a = context.theme.obtainStyledAttributes(
boolean formatAllowed = true; attrs, R.styleable.PasteSensitiveTextInputEditText, 0, 0
)
TypedArray a = context.getTheme().obtainStyledAttributes( return try {
attrs, R.styleable.PasteSensitiveTextInputEditText, 0, 0); a.getBoolean(R.styleable.PasteSensitiveTextInputEditText_allowFormatting, true)
try {
formatAllowed = a.getBoolean(
R.styleable.PasteSensitiveTextInputEditText_allowFormatting, true);
} finally { } finally {
a.recycle(); a.recycle()
} }
return formatAllowed;
} }
public void setFormattingAllowed(boolean formattingAllowed){ fun setFormattingAllowed(formattingAllowed: Boolean) {
this.formattingAllowed = formattingAllowed; this.formattingAllowed = formattingAllowed
} }
} }

View file

@ -1,36 +1,32 @@
package fr.free.nrw.commons.ui.widget; package fr.free.nrw.commons.ui.widget
import android.content.Context; import android.content.Context
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod
import android.util.AttributeSet; import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView; import androidx.appcompat.widget.AppCompatTextView
import fr.free.nrw.commons.utils.StringUtil; import fr.free.nrw.commons.utils.StringUtil
/** /**
* An {@link AppCompatTextView} which formats the text to HTML displayable text and makes any * An [AppCompatTextView] which formats the text to HTML displayable text and makes any
* links clickable. * links clickable.
*/ */
public class HtmlTextView extends AppCompatTextView { class HtmlTextView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : AppCompatTextView(context, attrs) {
/** init {
* Constructs a new instance of HtmlTextView movementMethod = LinkMovementMethod.getInstance()
* @param context the context of the view text = StringUtil.fromHtml(text.toString())
* @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 * Sets the text to be displayed
* @param newText the text to be displayed * @param newText the text to be displayed
*/ */
public void setHtmlText(String newText) { fun setHtmlText(newText: String) {
setText(StringUtil.fromHtml(newText)); text = StringUtil.fromHtml(newText)
} }
} }

View file

@ -1,31 +1,29 @@
package fr.free.nrw.commons.ui.widget; package fr.free.nrw.commons.ui.widget
import android.app.Dialog; import android.app.Dialog
import android.graphics.Color; import android.graphics.Color
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable
import android.os.Bundle; import android.os.Bundle
import android.view.Gravity; import android.view.Gravity
import android.view.View; import android.view.View
import android.view.Window; import android.view.Window
import android.view.WindowManager; import android.view.WindowManager
import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment
import androidx.fragment.app.DialogFragment;
/** /**
* a formatted dialog fragment * A formatted dialog fragment
* This class is used by NearbyInfoDialog * This class is used by NearbyInfoDialog
*/ */
public abstract class OverlayDialog extends DialogFragment { abstract class OverlayDialog : DialogFragment() {
/** /**
* creates a DialogFragment with the correct style and theme * Creates a DialogFragment with the correct style and theme
* @param savedInstanceState bundle re-constructed from a previous saved state * @param savedInstanceState bundle re-constructed from a previous saved state
*/ */
@Override override fun onCreate(savedInstanceState: Bundle?) {
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState)
super.onCreate(savedInstanceState); setStyle(STYLE_NO_FRAME, android.R.style.Theme_Holo_Light)
setStyle(STYLE_NO_FRAME, android.R.style.Theme_Holo_Light);
} }
/** /**
@ -34,37 +32,33 @@ public abstract class OverlayDialog extends DialogFragment {
* @param view the view being used * @param view the view being used
* @param savedInstanceState bundle re-constructed from a previous saved state * @param savedInstanceState bundle re-constructed from a previous saved state
*/ */
@Override override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
public void onViewCreated(View view, Bundle savedInstanceState) { setDialogLayoutToFullScreen()
setDialogLayoutToFullScreen(); super.onViewCreated(view, savedInstanceState)
super.onViewCreated(view, savedInstanceState);
} }
/** /**
* sets the dialog layout to fullscreen * Sets the dialog layout to fullscreen
*/ */
private void setDialogLayoutToFullScreen() { private fun setDialogLayoutToFullScreen() {
Window window = getDialog().getWindow(); val window = dialog?.window ?: return
WindowManager.LayoutParams wlp = window.getAttributes(); val wlp = window.attributes
window.requestFeature(Window.FEATURE_NO_TITLE); window.requestFeature(Window.FEATURE_NO_TITLE)
wlp.gravity = Gravity.BOTTOM; wlp.gravity = Gravity.BOTTOM
wlp.width = WindowManager.LayoutParams.MATCH_PARENT; wlp.width = WindowManager.LayoutParams.MATCH_PARENT
wlp.height = WindowManager.LayoutParams.MATCH_PARENT; wlp.height = WindowManager.LayoutParams.MATCH_PARENT
window.setAttributes(wlp); window.attributes = wlp
} }
/** /**
* builds custom dialog container * Builds custom dialog container
* *
* @param savedInstanceState the previously saved state * @param savedInstanceState the previously saved state
* @return the dialog * @return the dialog
*/ */
@NonNull override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
@Override val dialog = super.onCreateDialog(savedInstanceState)
public Dialog onCreateDialog(Bundle savedInstanceState) { dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
Dialog dialog = super.onCreateDialog(savedInstanceState); return dialog
Window window = dialog.getWindow();
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
return dialog;
} }
} }