mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-22 06:37:30 +00:00
Handle invalid custom date time format. Fixes austinhuang0131/barinsta#1499
This commit is contained in:
parent
82d7555eee
commit
383485abec
@ -16,18 +16,20 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.DialogFragment;
|
import androidx.fragment.app.DialogFragment;
|
||||||
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
import awais.instagrabber.R;
|
||||||
import awais.instagrabber.databinding.DialogTimeSettingsBinding;
|
import awais.instagrabber.databinding.DialogTimeSettingsBinding;
|
||||||
|
import awais.instagrabber.utils.DateUtils;
|
||||||
import awais.instagrabber.utils.LocaleUtils;
|
import awais.instagrabber.utils.LocaleUtils;
|
||||||
import awais.instagrabber.utils.TextUtils;
|
import awais.instagrabber.utils.TextUtils;
|
||||||
|
|
||||||
public final class TimeSettingsDialog extends DialogFragment implements AdapterView.OnItemSelectedListener, CompoundButton.OnCheckedChangeListener,
|
public final class TimeSettingsDialog extends DialogFragment implements AdapterView.OnItemSelectedListener, CompoundButton.OnCheckedChangeListener,
|
||||||
View.OnClickListener, TextWatcher {
|
View.OnClickListener, TextWatcher {
|
||||||
private DialogTimeSettingsBinding timeSettingsBinding;
|
private DialogTimeSettingsBinding binding;
|
||||||
private final LocalDateTime magicDate;
|
private final LocalDateTime magicDate;
|
||||||
private DateTimeFormatter currentFormat;
|
private DateTimeFormatter currentFormat;
|
||||||
private String selectedFormat;
|
private String selectedFormat;
|
||||||
@ -55,57 +57,67 @@ public final class TimeSettingsDialog extends DialogFragment implements AdapterV
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) {
|
public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) {
|
||||||
timeSettingsBinding = DialogTimeSettingsBinding.inflate(inflater, container, false);
|
binding = DialogTimeSettingsBinding.inflate(inflater, container, false);
|
||||||
|
|
||||||
timeSettingsBinding.cbCustomFormat.setOnCheckedChangeListener(this);
|
binding.cbCustomFormat.setOnCheckedChangeListener(this);
|
||||||
timeSettingsBinding.cbCustomFormat.setChecked(customDateTimeFormatEnabled);
|
binding.cbCustomFormat.setChecked(customDateTimeFormatEnabled);
|
||||||
timeSettingsBinding.cbSwapTimeDate.setChecked(swapDateTimeEnabled);
|
binding.cbSwapTimeDate.setChecked(swapDateTimeEnabled);
|
||||||
timeSettingsBinding.etCustomFormat.setText(customDateTimeFormat);
|
binding.customFormatEditText.setText(customDateTimeFormat);
|
||||||
|
|
||||||
final String[] dateTimeFormat = dateTimeSelection.split(";"); // output = time;separator;date
|
final String[] dateTimeFormat = dateTimeSelection.split(";"); // output = time;separator;date
|
||||||
timeSettingsBinding.spTimeFormat.setSelection(Integer.parseInt(dateTimeFormat[0]));
|
binding.spTimeFormat.setSelection(Integer.parseInt(dateTimeFormat[0]));
|
||||||
timeSettingsBinding.spSeparator.setSelection(Integer.parseInt(dateTimeFormat[1]));
|
binding.spSeparator.setSelection(Integer.parseInt(dateTimeFormat[1]));
|
||||||
timeSettingsBinding.spDateFormat.setSelection(Integer.parseInt(dateTimeFormat[2]));
|
binding.spDateFormat.setSelection(Integer.parseInt(dateTimeFormat[2]));
|
||||||
|
|
||||||
timeSettingsBinding.cbSwapTimeDate.setOnCheckedChangeListener(this);
|
binding.cbSwapTimeDate.setOnCheckedChangeListener(this);
|
||||||
|
|
||||||
refreshTimeFormat();
|
refreshTimeFormat();
|
||||||
|
|
||||||
timeSettingsBinding.spTimeFormat.setOnItemSelectedListener(this);
|
binding.spTimeFormat.setOnItemSelectedListener(this);
|
||||||
timeSettingsBinding.spDateFormat.setOnItemSelectedListener(this);
|
binding.spDateFormat.setOnItemSelectedListener(this);
|
||||||
timeSettingsBinding.spSeparator.setOnItemSelectedListener(this);
|
binding.spSeparator.setOnItemSelectedListener(this);
|
||||||
|
|
||||||
timeSettingsBinding.etCustomFormat.addTextChangedListener(this);
|
binding.customFormatEditText.addTextChangedListener(this);
|
||||||
timeSettingsBinding.btnConfirm.setOnClickListener(this);
|
binding.btnConfirm.setOnClickListener(this);
|
||||||
timeSettingsBinding.btnInfo.setOnClickListener(this);
|
binding.customFormatField.setEndIconOnClickListener(this);
|
||||||
|
|
||||||
return timeSettingsBinding.getRoot();
|
return binding.getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshTimeFormat() {
|
private void refreshTimeFormat() {
|
||||||
if (timeSettingsBinding.cbCustomFormat.isChecked())
|
final boolean isCustom = binding.cbCustomFormat.isChecked();
|
||||||
selectedFormat = timeSettingsBinding.etCustomFormat.getText().toString();
|
if (isCustom) {
|
||||||
else {
|
final Editable text = binding.customFormatEditText.getText();
|
||||||
final String sepStr = String.valueOf(timeSettingsBinding.spSeparator.getSelectedItem());
|
if (text != null) {
|
||||||
final String timeStr = String.valueOf(timeSettingsBinding.spTimeFormat.getSelectedItem());
|
selectedFormat = text.toString();
|
||||||
final String dateStr = String.valueOf(timeSettingsBinding.spDateFormat.getSelectedItem());
|
}
|
||||||
|
} else {
|
||||||
|
final String sepStr = String.valueOf(binding.spSeparator.getSelectedItem());
|
||||||
|
final String timeStr = String.valueOf(binding.spTimeFormat.getSelectedItem());
|
||||||
|
final String dateStr = String.valueOf(binding.spDateFormat.getSelectedItem());
|
||||||
|
|
||||||
final boolean isSwapTime = timeSettingsBinding.cbSwapTimeDate.isChecked();
|
final boolean isSwapTime = binding.cbSwapTimeDate.isChecked();
|
||||||
final boolean isBlankSeparator = timeSettingsBinding.spSeparator.getSelectedItemPosition() <= 0;
|
final boolean isBlankSeparator = binding.spSeparator.getSelectedItemPosition() <= 0;
|
||||||
|
|
||||||
selectedFormat = (isSwapTime ? dateStr : timeStr)
|
selectedFormat = (isSwapTime ? dateStr : timeStr)
|
||||||
+ (isBlankSeparator ? " " : " '" + sepStr + "' ")
|
+ (isBlankSeparator ? " " : " '" + sepStr + "' ")
|
||||||
+ (isSwapTime ? timeStr : dateStr);
|
+ (isSwapTime ? timeStr : dateStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
timeSettingsBinding.btnConfirm.setEnabled(true);
|
binding.btnConfirm.setEnabled(true);
|
||||||
try {
|
try {
|
||||||
currentFormat = DateTimeFormatter.ofPattern(selectedFormat, LocaleUtils.getCurrentLocale());
|
currentFormat = DateTimeFormatter.ofPattern(selectedFormat, LocaleUtils.getCurrentLocale());
|
||||||
timeSettingsBinding.timePreview.setText(magicDate.format(currentFormat));
|
if (isCustom) {
|
||||||
|
final boolean valid = !TextUtils.isEmpty(selectedFormat) && DateUtils.checkFormatterValid(currentFormat);
|
||||||
|
binding.customFormatField.setError(valid ? null :getString(R.string.invalid_format));
|
||||||
|
if (!valid) {
|
||||||
|
binding.btnConfirm.setEnabled(false);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
}
|
||||||
timeSettingsBinding.btnConfirm.setEnabled(false);
|
binding.timePreview.setText(magicDate.format(currentFormat));
|
||||||
timeSettingsBinding.timePreview.setText(null);
|
} catch (Exception e) {
|
||||||
|
binding.btnConfirm.setEnabled(false);
|
||||||
|
binding.timePreview.setText(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,16 +128,14 @@ public final class TimeSettingsDialog extends DialogFragment implements AdapterV
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
|
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
|
||||||
if (buttonView == timeSettingsBinding.cbCustomFormat) {
|
if (buttonView == binding.cbCustomFormat) {
|
||||||
final View parent = (View) timeSettingsBinding.etCustomFormat.getParent();
|
binding.customFormatField.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
||||||
parent.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
binding.customFormatField.setEnabled(isChecked);
|
||||||
timeSettingsBinding.etCustomFormat.setEnabled(isChecked);
|
|
||||||
timeSettingsBinding.btnInfo.setEnabled(isChecked);
|
|
||||||
|
|
||||||
timeSettingsBinding.spTimeFormat.setEnabled(!isChecked);
|
binding.spTimeFormat.setEnabled(!isChecked);
|
||||||
timeSettingsBinding.spDateFormat.setEnabled(!isChecked);
|
binding.spDateFormat.setEnabled(!isChecked);
|
||||||
timeSettingsBinding.spSeparator.setEnabled(!isChecked);
|
binding.spSeparator.setEnabled(!isChecked);
|
||||||
timeSettingsBinding.cbSwapTimeDate.setEnabled(!isChecked);
|
binding.cbSwapTimeDate.setEnabled(!isChecked);
|
||||||
}
|
}
|
||||||
refreshTimeFormat();
|
refreshTimeFormat();
|
||||||
}
|
}
|
||||||
@ -137,20 +147,21 @@ public final class TimeSettingsDialog extends DialogFragment implements AdapterV
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(final View v) {
|
public void onClick(final View v) {
|
||||||
if (v == timeSettingsBinding.btnConfirm) {
|
if (v == binding.btnConfirm) {
|
||||||
if (onConfirmListener != null) {
|
if (onConfirmListener != null) {
|
||||||
onConfirmListener.onConfirm(
|
onConfirmListener.onConfirm(
|
||||||
timeSettingsBinding.cbCustomFormat.isChecked(),
|
binding.cbCustomFormat.isChecked(),
|
||||||
timeSettingsBinding.spTimeFormat.getSelectedItemPosition(),
|
binding.spTimeFormat.getSelectedItemPosition(),
|
||||||
timeSettingsBinding.spSeparator.getSelectedItemPosition(),
|
binding.spSeparator.getSelectedItemPosition(),
|
||||||
timeSettingsBinding.spDateFormat.getSelectedItemPosition(),
|
binding.spDateFormat.getSelectedItemPosition(),
|
||||||
selectedFormat,
|
selectedFormat,
|
||||||
timeSettingsBinding.cbSwapTimeDate.isChecked());
|
binding.cbSwapTimeDate.isChecked());
|
||||||
}
|
}
|
||||||
dismiss();
|
dismiss();
|
||||||
} else if (v == timeSettingsBinding.btnInfo) {
|
} else if (v == binding.customFormatField.findViewById(R.id.text_input_end_icon)) {
|
||||||
timeSettingsBinding.customPanel.setVisibility(timeSettingsBinding.customPanel
|
binding.customPanel.setVisibility(
|
||||||
.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE);
|
binding.customPanel.getVisibility() == View.VISIBLE ? View.GONE : View.VISIBLE
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,4 +90,5 @@ object Constants {
|
|||||||
const val DM_THREAD_ACTION_EXTRA_THREAD_TITLE = "thread_title"
|
const val DM_THREAD_ACTION_EXTRA_THREAD_TITLE = "thread_title"
|
||||||
const val X_IG_APP_ID = "936619743392459"
|
const val X_IG_APP_ID = "936619743392459"
|
||||||
const val EXTRA_INITIAL_URI = "initial_uri"
|
const val EXTRA_INITIAL_URI = "initial_uri"
|
||||||
|
const val defaultDateTimeFormat = "hh:mm:ss a 'on' dd-MM-yyyy"
|
||||||
}
|
}
|
@ -1,6 +1,9 @@
|
|||||||
package awais.instagrabber.utils
|
package awais.instagrabber.utils
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import awais.instagrabber.utils.extensions.TAG
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
object DateUtils {
|
object DateUtils {
|
||||||
@ -14,4 +17,13 @@ object DateUtils {
|
|||||||
fun isBeforeOrEqual(localDateTime: LocalDateTime, comparedTo: LocalDateTime): Boolean {
|
fun isBeforeOrEqual(localDateTime: LocalDateTime, comparedTo: LocalDateTime): Boolean {
|
||||||
return localDateTime.isBefore(comparedTo) || localDateTime.isEqual(comparedTo)
|
return localDateTime.isBefore(comparedTo) || localDateTime.isEqual(comparedTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun checkFormatterValid(datetimeParser: DateTimeFormatter): Boolean = try {
|
||||||
|
LocalDateTime.now().format(datetimeParser)
|
||||||
|
true
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "checkFormatterValid: ", e)
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
@ -37,7 +37,9 @@ class SettingsHelper(context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getStringDefault(@StringSettings key: String): String {
|
private fun getStringDefault(@StringSettings key: String): String {
|
||||||
if (PreferenceKeys.DATE_TIME_FORMAT == key) return "hh:mm:ss a 'on' dd-MM-yyyy"
|
if (PreferenceKeys.DATE_TIME_FORMAT == key) {
|
||||||
|
return Constants.defaultDateTimeFormat
|
||||||
|
}
|
||||||
return if (PreferenceKeys.DATE_TIME_SELECTION == key) "0;3;0" else ""
|
return if (PreferenceKeys.DATE_TIME_SELECTION == key) "0;3;0" else ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,11 +11,11 @@ import java.util.*
|
|||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
object TextUtils {
|
object TextUtils {
|
||||||
lateinit var datetimeParser: DateTimeFormatter
|
var dateTimeFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern(Constants.defaultDateTimeFormat)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun isEmpty(charSequence: CharSequence?): Boolean {
|
fun isEmpty(charSequence: CharSequence?): Boolean {
|
||||||
if (charSequence == null || charSequence.length < 1) return true
|
if (charSequence.isNullOrBlank()) return true
|
||||||
if (charSequence is String) {
|
if (charSequence is String) {
|
||||||
var str = charSequence
|
var str = charSequence
|
||||||
if ("" == str || "null" == str || str.isEmpty()) return true
|
if ("" == str || "null" == str || str.isEmpty()) return true
|
||||||
@ -78,7 +78,8 @@ object TextUtils {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun setFormatter(datetimeParser: DateTimeFormatter) {
|
fun setFormatter(datetimeParser: DateTimeFormatter) {
|
||||||
this.datetimeParser = datetimeParser
|
if (!DateUtils.checkFormatterValid(datetimeParser)) return
|
||||||
|
this.dateTimeFormatter = datetimeParser
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@ -86,11 +87,11 @@ object TextUtils {
|
|||||||
return LocalDateTime.ofInstant(
|
return LocalDateTime.ofInstant(
|
||||||
Instant.ofEpochSecond(epochSecond),
|
Instant.ofEpochSecond(epochSecond),
|
||||||
ZoneId.systemDefault()
|
ZoneId.systemDefault()
|
||||||
).format(datetimeParser)
|
).format(dateTimeFormatter)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun nowToString(): String {
|
fun nowToString(): String {
|
||||||
return LocalDateTime.now().format(datetimeParser)
|
return LocalDateTime.now().format(dateTimeFormatter)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -33,27 +33,29 @@
|
|||||||
android:gravity="center" />
|
android:gravity="center" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/custom_format_field"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:visibility="gone"
|
||||||
android:visibility="gone">
|
app:counterEnabled="false"
|
||||||
|
app:counterMaxLength="50"
|
||||||
|
app:endIconDrawable="@drawable/ic_outline_info_24"
|
||||||
|
app:endIconMode="custom"
|
||||||
|
app:hintEnabled="false"
|
||||||
|
tools:visibility="visible">
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/etCustomFormat"
|
android:id="@+id/custom_format_edit_text"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:autofillHints="no"
|
||||||
android:enabled="false" />
|
android:inputType="text"
|
||||||
|
android:maxLength="50"
|
||||||
|
android:padding="16dp"
|
||||||
|
tools:text="test" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
android:id="@+id/btnInfo"
|
|
||||||
style="@style/Widget.AppCompat.Button.ButtonBar.AlertDialog"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="start"
|
|
||||||
app:srcCompat="@drawable/ic_outline_info_24" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/customPanel"
|
android:id="@+id/customPanel"
|
||||||
|
@ -516,4 +516,5 @@
|
|||||||
<string name="share_link">Share link…</string>
|
<string name="share_link">Share link…</string>
|
||||||
<string name="slide_to_cancel">Slide to Cancel</string>
|
<string name="slide_to_cancel">Slide to Cancel</string>
|
||||||
<string name="disable_screen_transitions">Disable screen transitions</string>
|
<string name="disable_screen_transitions">Disable screen transitions</string>
|
||||||
|
<string name="invalid_format">Invalid format</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user