mirror of https://github.com/ThmmyNoLife/mTHMMY
				
				
			
				 22 changed files with 631 additions and 80 deletions
			
			
		| @ -0,0 +1,64 @@ | |||||
|  | package gr.thmmy.mthmmy.utils; | ||||
|  | 
 | ||||
|  | import static android.text.format.DateUtils.DAY_IN_MILLIS; | ||||
|  | import static android.text.format.DateUtils.HOUR_IN_MILLIS; | ||||
|  | import static android.text.format.DateUtils.MINUTE_IN_MILLIS; | ||||
|  | import static android.text.format.DateUtils.SECOND_IN_MILLIS; | ||||
|  | import static android.text.format.DateUtils.YEAR_IN_MILLIS; | ||||
|  | 
 | ||||
|  | public class DateTimeUtils { | ||||
|  |     //TODO: move this function to ThmmyDateTimeParser class once KitKat support is dropped
 | ||||
|  |     public static String convertDateTime(String dateTime, boolean removeSeconds){ | ||||
|  |         //Convert e.g. Today at 12:16:48 -> 12:16:48, but October 03, 2019, 16:40:18 remains as is
 | ||||
|  |         if (!dateTime.contains(",")) | ||||
|  |             dateTime = dateTime.replaceAll(".+? ([0-9])", "$1"); | ||||
|  | 
 | ||||
|  |         //Remove seconds
 | ||||
|  |         if(removeSeconds) | ||||
|  |             dateTime = dateTime.replaceAll("(.+?)(:[0-5][0-9])($|\\s)", "$1$3"); | ||||
|  | 
 | ||||
|  |         return dateTime; | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     private static final long MONTH_IN_MILLIS = DAY_IN_MILLIS*30; | ||||
|  |     private static final long DECADE_IN_MILLIS = YEAR_IN_MILLIS*10; | ||||
|  | 
 | ||||
|  |     static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution) { | ||||
|  |         boolean past = (now >= time); | ||||
|  |         long duration = Math.abs(now - time); | ||||
|  |         String format; | ||||
|  |         long count; | ||||
|  |         if (duration < MINUTE_IN_MILLIS && minResolution < MINUTE_IN_MILLIS) { | ||||
|  |             count = duration / SECOND_IN_MILLIS; | ||||
|  |             format = "%d sec"; | ||||
|  |         } else if (duration < HOUR_IN_MILLIS && minResolution < HOUR_IN_MILLIS) { | ||||
|  |             count = duration / MINUTE_IN_MILLIS; | ||||
|  |             format = "%d min"; | ||||
|  |         } else if (duration < DAY_IN_MILLIS && minResolution < DAY_IN_MILLIS) { | ||||
|  |             count = duration / HOUR_IN_MILLIS; | ||||
|  |             format = "%d hour"; | ||||
|  |             if(count>1) | ||||
|  |                 format = format + 's'; | ||||
|  |         } else if (duration < MONTH_IN_MILLIS && minResolution < MONTH_IN_MILLIS) { | ||||
|  |             count = duration / DAY_IN_MILLIS; | ||||
|  |             format = "%d day"; | ||||
|  |             if(count>1) | ||||
|  |                 format = format + 's'; | ||||
|  |         } else if (duration < YEAR_IN_MILLIS && minResolution < YEAR_IN_MILLIS) { | ||||
|  |             count = duration / MONTH_IN_MILLIS; | ||||
|  |             format = "%d month"; | ||||
|  |             if(count>1) | ||||
|  |                 format = format + 's'; | ||||
|  |         } else if (duration < DECADE_IN_MILLIS && minResolution < DECADE_IN_MILLIS) { | ||||
|  |             count = duration / YEAR_IN_MILLIS; | ||||
|  |             format = "%d year"; | ||||
|  |             if(count>1) | ||||
|  |                 format = format + 's'; | ||||
|  |         } | ||||
|  |         else | ||||
|  |             return past ? "a long time ago": "in the distant future"; | ||||
|  | 
 | ||||
|  |         format = past ? format : "in " + format; | ||||
|  |         return String.format(format, (int) count); | ||||
|  |     } | ||||
|  | } | ||||
| @ -0,0 +1,249 @@ | |||||
|  | package gr.thmmy.mthmmy.utils; | ||||
|  | 
 | ||||
|  | import android.annotation.SuppressLint; | ||||
|  | import android.content.Context; | ||||
|  | import android.content.res.TypedArray; | ||||
|  | import android.os.Handler; | ||||
|  | import android.os.Parcel; | ||||
|  | import android.os.Parcelable; | ||||
|  | import android.text.format.DateUtils; | ||||
|  | import android.util.AttributeSet; | ||||
|  | import android.view.View; | ||||
|  | import android.widget.TextView; | ||||
|  | 
 | ||||
|  | import java.lang.ref.WeakReference; | ||||
|  | 
 | ||||
|  | import gr.thmmy.mthmmy.R; | ||||
|  | 
 | ||||
|  | import static gr.thmmy.mthmmy.utils.DateTimeUtils.getRelativeTimeSpanString; | ||||
|  | 
 | ||||
|  | /** | ||||
|  |  * A modified version of https://github.com/curioustechizen/android-ago
 | ||||
|  |  */ | ||||
|  | @SuppressLint("AppCompatCustomView") | ||||
|  | public class RelativeTimeTextView extends TextView { | ||||
|  | 
 | ||||
|  |     private static final long INITIAL_UPDATE_INTERVAL = DateUtils.MINUTE_IN_MILLIS; | ||||
|  | 
 | ||||
|  |     private long mReferenceTime; | ||||
|  |     private Handler mHandler = new Handler(); | ||||
|  |     private UpdateTimeRunnable mUpdateTimeTask; | ||||
|  |     private boolean isUpdateTaskRunning = false; | ||||
|  | 
 | ||||
|  |     public RelativeTimeTextView(Context context, AttributeSet attrs) { | ||||
|  |         super(context, attrs); | ||||
|  |         init(context, attrs); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     public RelativeTimeTextView(Context context, AttributeSet attrs, int defStyle) { | ||||
|  |         super(context, attrs, defStyle); | ||||
|  |         init(context, attrs); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     private void init(Context context, AttributeSet attrs) { | ||||
|  |         TypedArray a = context.getTheme().obtainStyledAttributes(attrs, | ||||
|  |                 R.styleable.RelativeTimeTextView, 0, 0); | ||||
|  |         String referenceTimeText; | ||||
|  |         try { | ||||
|  |             referenceTimeText = a.getString(R.styleable.RelativeTimeTextView_reference_time); | ||||
|  |         } finally { | ||||
|  |             a.recycle(); | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         try { | ||||
|  |             mReferenceTime = Long.valueOf(referenceTimeText); | ||||
|  |         } catch (NumberFormatException nfe) { | ||||
|  |             /* | ||||
|  |              * TODO: Better exception handling | ||||
|  |              */ | ||||
|  |             mReferenceTime = -1L; | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         setReferenceTime(mReferenceTime); | ||||
|  | 
 | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     /** | ||||
|  |      * Sets the reference time for this view. At any moment, the view will render a relative time period relative to the time set here. | ||||
|  |      * <p/> | ||||
|  |      * This value can also be set with the XML attribute {@code reference_time} | ||||
|  |      * @param referenceTime The timestamp (in milliseconds since epoch) that will be the reference point for this view. | ||||
|  |      */ | ||||
|  |     public void setReferenceTime(long referenceTime) { | ||||
|  |         this.mReferenceTime = referenceTime; | ||||
|  | 
 | ||||
|  |         /* | ||||
|  |          * Note that this method could be called when a row in a ListView is recycled. | ||||
|  |          * Hence, we need to first stop any currently running schedules (for example from the recycled view. | ||||
|  |          */ | ||||
|  |         stopTaskForPeriodicallyUpdatingRelativeTime(); | ||||
|  | 
 | ||||
|  |         /* | ||||
|  |          * Instantiate a new runnable with the new reference time | ||||
|  |          */ | ||||
|  |         initUpdateTimeTask(); | ||||
|  | 
 | ||||
|  |         /* | ||||
|  |          * Start a new schedule. | ||||
|  |          */ | ||||
|  |         startTaskForPeriodicallyUpdatingRelativeTime(); | ||||
|  | 
 | ||||
|  |         /* | ||||
|  |          * Finally, update the text display. | ||||
|  |          */ | ||||
|  |         updateTextDisplay(); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     private void updateTextDisplay() { | ||||
|  |         /* | ||||
|  |          * TODO: Validation, Better handling of negative cases | ||||
|  |          */ | ||||
|  |         if (this.mReferenceTime == -1L) | ||||
|  |             return; | ||||
|  |         setText(getRelativeTimeDisplayString(mReferenceTime, System.currentTimeMillis())); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     /** | ||||
|  |      * Get the text to display for relative time. | ||||
|  |      * <br/> | ||||
|  |      * @param referenceTime The reference time passed in through {@link #setReferenceTime(long)} or through {@code reference_time} attribute | ||||
|  |      * @param now The current time | ||||
|  |      * @return The display text for the relative time | ||||
|  |      */ | ||||
|  |     protected CharSequence getRelativeTimeDisplayString(long referenceTime, long now) { | ||||
|  |         long difference = now - referenceTime; | ||||
|  |         return (difference >= 0 &&  difference<=DateUtils.MINUTE_IN_MILLIS) ? | ||||
|  |                 "just now" : | ||||
|  |                 getRelativeTimeSpanString( | ||||
|  |                         mReferenceTime, | ||||
|  |                         now, | ||||
|  |                         DateUtils.MINUTE_IN_MILLIS); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     @Override | ||||
|  |     protected void onAttachedToWindow() { | ||||
|  |         super.onAttachedToWindow(); | ||||
|  |         startTaskForPeriodicallyUpdatingRelativeTime(); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     @Override | ||||
|  |     protected void onDetachedFromWindow() { | ||||
|  |         super.onDetachedFromWindow(); | ||||
|  |         stopTaskForPeriodicallyUpdatingRelativeTime(); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     @Override | ||||
|  |     protected void onVisibilityChanged(View changedView, int visibility) { | ||||
|  |         super.onVisibilityChanged(changedView, visibility); | ||||
|  |         if (visibility == GONE || visibility == INVISIBLE) { | ||||
|  |             stopTaskForPeriodicallyUpdatingRelativeTime(); | ||||
|  |         } else { | ||||
|  |             startTaskForPeriodicallyUpdatingRelativeTime(); | ||||
|  |         } | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     private void startTaskForPeriodicallyUpdatingRelativeTime() { | ||||
|  |         if(mUpdateTimeTask.isDetached()) initUpdateTimeTask(); | ||||
|  |         mHandler.post(mUpdateTimeTask); | ||||
|  |         isUpdateTaskRunning = true; | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     private void initUpdateTimeTask() { | ||||
|  |         mUpdateTimeTask = new UpdateTimeRunnable(this, mReferenceTime); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     private void stopTaskForPeriodicallyUpdatingRelativeTime() { | ||||
|  |         if(isUpdateTaskRunning) { | ||||
|  |             mUpdateTimeTask.detach(); | ||||
|  |             mHandler.removeCallbacks(mUpdateTimeTask); | ||||
|  |             isUpdateTaskRunning = false; | ||||
|  |         } | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     @Override | ||||
|  |     public Parcelable onSaveInstanceState() { | ||||
|  |         Parcelable superState = super.onSaveInstanceState(); | ||||
|  |         SavedState ss = new SavedState(superState); | ||||
|  |         ss.referenceTime = mReferenceTime; | ||||
|  |         return ss; | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     @Override | ||||
|  |     public void onRestoreInstanceState(Parcelable state) { | ||||
|  |         if (!(state instanceof SavedState)) { | ||||
|  |             super.onRestoreInstanceState(state); | ||||
|  |             return; | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         SavedState ss = (SavedState)state; | ||||
|  |         mReferenceTime = ss.referenceTime; | ||||
|  |         super.onRestoreInstanceState(ss.getSuperState()); | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     public static class SavedState extends BaseSavedState { | ||||
|  | 
 | ||||
|  |         private long referenceTime; | ||||
|  | 
 | ||||
|  |         public SavedState(Parcelable superState) { | ||||
|  |             super(superState); | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         @Override | ||||
|  |         public void writeToParcel(Parcel dest, int flags) { | ||||
|  |             super.writeToParcel(dest, flags); | ||||
|  |             dest.writeLong(referenceTime); | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() { | ||||
|  |             public SavedState createFromParcel(Parcel in) { | ||||
|  |                 return new SavedState(in); | ||||
|  |             } | ||||
|  | 
 | ||||
|  |             public SavedState[] newArray(int size) { | ||||
|  |                 return new SavedState[size]; | ||||
|  |             } | ||||
|  |         }; | ||||
|  | 
 | ||||
|  |         private SavedState(Parcel in) { | ||||
|  |             super(in); | ||||
|  |             referenceTime = in.readLong(); | ||||
|  |         } | ||||
|  |     } | ||||
|  | 
 | ||||
|  |     private static class UpdateTimeRunnable implements Runnable { | ||||
|  | 
 | ||||
|  |         private long mRefTime; | ||||
|  |         private final WeakReference<RelativeTimeTextView> weakRefRttv; | ||||
|  | 
 | ||||
|  |         UpdateTimeRunnable(RelativeTimeTextView rttv, long refTime) { | ||||
|  |             this.mRefTime = refTime; | ||||
|  |             weakRefRttv = new WeakReference<>(rttv); | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         boolean isDetached() { | ||||
|  |             return weakRefRttv.get() == null; | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         void detach() { | ||||
|  |             weakRefRttv.clear(); | ||||
|  |         } | ||||
|  | 
 | ||||
|  |         @Override | ||||
|  |         public void run() { | ||||
|  |             RelativeTimeTextView rttv = weakRefRttv.get(); | ||||
|  |             if (rttv == null) return; | ||||
|  |             long difference = Math.abs(System.currentTimeMillis() - mRefTime); | ||||
|  |             long interval = INITIAL_UPDATE_INTERVAL; | ||||
|  |             if (difference > DateUtils.WEEK_IN_MILLIS) { | ||||
|  |                 interval = DateUtils.WEEK_IN_MILLIS; | ||||
|  |             } else if (difference > DateUtils.DAY_IN_MILLIS) { | ||||
|  |                 interval = DateUtils.DAY_IN_MILLIS; | ||||
|  |             } else if (difference > DateUtils.HOUR_IN_MILLIS) { | ||||
|  |                 interval = DateUtils.HOUR_IN_MILLIS; | ||||
|  |             } | ||||
|  |             rttv.updateTextDisplay(); | ||||
|  |             rttv.mHandler.postDelayed(this, interval); | ||||
|  | 
 | ||||
|  |         } | ||||
|  |     } | ||||
|  | } | ||||
| @ -0,0 +1,63 @@ | |||||
|  | package gr.thmmy.mthmmy.utils.parsing; | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | import android.os.Build; | ||||
|  | 
 | ||||
|  | import androidx.annotation.RequiresApi; | ||||
|  | 
 | ||||
|  | import org.joda.time.DateTime; | ||||
|  | import org.joda.time.DateTimeZone; | ||||
|  | import org.joda.time.format.DateTimeFormat; | ||||
|  | import org.joda.time.format.DateTimeFormatter; | ||||
|  | import org.joda.time.format.DateTimeFormatterBuilder; | ||||
|  | import org.joda.time.format.DateTimeParser; | ||||
|  | 
 | ||||
|  | import java.util.Locale; | ||||
|  | 
 | ||||
|  | import gr.thmmy.mthmmy.base.BaseApplication; | ||||
|  | import timber.log.Timber; | ||||
|  | 
 | ||||
|  | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) | ||||
|  | public class ThmmyDateTimeParser { | ||||
|  |     private static final DateTimeParser[] parsers = { | ||||
|  |             DateTimeFormat.forPattern("HH:mm:ss").getParser(), | ||||
|  |             DateTimeFormat.forPattern("HH:mm:ss a").getParser(), | ||||
|  |             DateTimeFormat.forPattern("MMMM d, Y, HH:mm:ss").getParser(), | ||||
|  |             DateTimeFormat.forPattern("MMMM d, Y, HH:mm:ss a").getParser() | ||||
|  |     }; | ||||
|  | 
 | ||||
|  |     private static final DateTimeFormatter formatter = new DateTimeFormatterBuilder() | ||||
|  |             .append(null, parsers) | ||||
|  |             .toFormatter(); | ||||
|  | 
 | ||||
|  |     private static final Locale greekLocale = Locale.forLanguageTag("el-GR"); | ||||
|  |     private static final Locale englishLocale = Locale.forLanguageTag("en-US"); | ||||
|  | 
 | ||||
|  |     public static String convertToTimestamp(String thmmyDateTime){ | ||||
|  |         DateTimeZone dtz; | ||||
|  |         if(!BaseApplication.getInstance().getSessionManager().isLoggedIn()) | ||||
|  |             dtz = DateTimeZone.forID("Europe/Athens"); | ||||
|  |         else | ||||
|  |             dtz = DateTimeZone.getDefault(); | ||||
|  | 
 | ||||
|  |         //Add today's date for the first two cases
 | ||||
|  |         if(Character.isDigit(thmmyDateTime.charAt(0))) | ||||
|  |             thmmyDateTime = (new DateTime()).toString("MMMM d, Y, ") + thmmyDateTime; | ||||
|  | 
 | ||||
|  |         DateTime dateTime; | ||||
|  |         try{ | ||||
|  |             dateTime=formatter.withZone(dtz).withLocale(greekLocale).parseDateTime(thmmyDateTime); | ||||
|  |         } | ||||
|  |         catch (IllegalArgumentException e1){ | ||||
|  |             Timber.i("Parsing DateTime using Greek Locale failed."); | ||||
|  |             try{ | ||||
|  |                 dateTime=formatter.withZone(dtz).withLocale(englishLocale).parseDateTime(thmmyDateTime); | ||||
|  |             } | ||||
|  |             catch (IllegalArgumentException e2){ | ||||
|  |                 Timber.e("Couldn't parse DateTime %s", thmmyDateTime); | ||||
|  |                 return null; | ||||
|  |             } | ||||
|  |         } | ||||
|  |         return Long.toString(dateTime.getMillis()); | ||||
|  |     } | ||||
|  | } | ||||
| @ -0,0 +1,43 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|  |     xmlns:app="http://schemas.android.com/apk/res-auto"> | ||||
|  | 
 | ||||
|  |     <androidx.preference.PreferenceCategory | ||||
|  |         android:title="@string/pref_category_app" | ||||
|  |         app:iconSpaceReserved="false"> | ||||
|  |         <androidx.preference.ListPreference | ||||
|  |             android:defaultValue="0" | ||||
|  |             android:dialogTitle="@string/pref_app_main_default_tab_dialog_title" | ||||
|  |             android:entries="@array/pref_app_main_default_tab_entries" | ||||
|  |             android:entryValues="@array/pref_app_main_default_tab_values" | ||||
|  |             android:key="@string/pref_app_main_default_tab_key" | ||||
|  |             android:title="@string/pref_title_app_main_default_tab" | ||||
|  |             android:summary="@string/pref_summary_app_main_default_tab" | ||||
|  |             app:iconSpaceReserved="false" /> | ||||
|  |         <androidx.preference.SwitchPreferenceCompat | ||||
|  |             android:defaultValue="false" | ||||
|  |             android:key="@string/pref_app_display_relative_time_key" | ||||
|  |             android:title="@string/pref_title_display_relative_time" | ||||
|  |             android:summary="@string/pref_summary_display_relative_time" | ||||
|  |             app:iconSpaceReserved="false" /> | ||||
|  |     </androidx.preference.PreferenceCategory> | ||||
|  | 
 | ||||
|  |     <androidx.preference.PreferenceCategory | ||||
|  |         android:key="@string/pref_category_privacy_key" | ||||
|  |         android:title="@string/pref_category_privacy" | ||||
|  |         app:iconSpaceReserved="false"> | ||||
|  |         <androidx.preference.SwitchPreferenceCompat | ||||
|  |             android:defaultValue="false" | ||||
|  |             android:key="@string/pref_privacy_crashlytics_enable_key" | ||||
|  |             android:title="@string/pref_title_privacy_crashlytics_enable" | ||||
|  |             android:summary="@string/pref_summary_privacy_crashlytics_enable" | ||||
|  |             app:iconSpaceReserved="false" /> | ||||
|  |         <androidx.preference.SwitchPreferenceCompat | ||||
|  |             android:defaultValue="false" | ||||
|  |             android:key="@string/pref_privacy_analytics_enable_key" | ||||
|  |             android:title="@string/pref_title_privacy_analytics_enable" | ||||
|  |             android:summary="@string/pref_summary_privacy_analytics_enable" | ||||
|  |             app:iconSpaceReserved="false" /> | ||||
|  |     </androidx.preference.PreferenceCategory> | ||||
|  | 
 | ||||
|  | </androidx.preference.PreferenceScreen> | ||||
| @ -0,0 +1,66 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|  |     xmlns:app="http://schemas.android.com/apk/res-auto"> | ||||
|  | 
 | ||||
|  |     <androidx.preference.PreferenceCategory | ||||
|  |         android:title="@string/pref_category_app" | ||||
|  |         app:iconSpaceReserved="false"> | ||||
|  |         <androidx.preference.ListPreference | ||||
|  |             android:defaultValue="0" | ||||
|  |             android:dialogTitle="@string/pref_app_main_default_tab_dialog_title" | ||||
|  |             android:entries="@array/pref_app_main_default_tab_entries" | ||||
|  |             android:entryValues="@array/pref_app_main_default_tab_values" | ||||
|  |             android:key="@string/pref_app_main_default_tab_key" | ||||
|  |             android:title="@string/pref_title_app_main_default_tab" | ||||
|  |             android:summary="@string/pref_summary_app_main_default_tab" | ||||
|  |             app:iconSpaceReserved="false" /> | ||||
|  |         <androidx.preference.SwitchPreferenceCompat | ||||
|  |             android:defaultValue="false" | ||||
|  |             android:key="@string/pref_app_display_relative_time_key" | ||||
|  |             android:title="@string/pref_title_display_relative_time" | ||||
|  |             android:summary="@string/pref_summary_display_relative_time" | ||||
|  |             app:iconSpaceReserved="false" /> | ||||
|  |     </androidx.preference.PreferenceCategory> | ||||
|  | 
 | ||||
|  |     <androidx.preference.PreferenceCategory | ||||
|  |         android:key="@string/pref_category_posting_key" | ||||
|  |         android:title="@string/pref_category_posting" | ||||
|  |         app:iconSpaceReserved="false"> | ||||
|  |         <androidx.preference.SwitchPreferenceCompat | ||||
|  |             android:defaultValue="true" | ||||
|  |             android:key="@string/pref_posting_app_signature_enable_key" | ||||
|  |             android:title="@string/pref_title_posting_app_signature_enable" | ||||
|  |             android:summary="@string/pref_summary_posting_app_signature_enable" | ||||
|  |             app:iconSpaceReserved="false" /> | ||||
|  |     </androidx.preference.PreferenceCategory> | ||||
|  | 
 | ||||
|  |     <androidx.preference.PreferenceCategory | ||||
|  |         android:key="@string/pref_category_uploading_key" | ||||
|  |         android:title="@string/pref_category_uploading" | ||||
|  |         app:iconSpaceReserved="false"> | ||||
|  |         <androidx.preference.SwitchPreferenceCompat | ||||
|  |             android:defaultValue="true" | ||||
|  |             android:key="@string/pref_uploading_app_signature_enable_key" | ||||
|  |             android:title="@string/pref_title_uploading_app_signature_enable" | ||||
|  |             android:summary="@string/pref_summary_uploading_app_signature_enable" | ||||
|  |             app:iconSpaceReserved="false" /> | ||||
|  |     </androidx.preference.PreferenceCategory> | ||||
|  | 
 | ||||
|  |     <androidx.preference.PreferenceCategory | ||||
|  |         android:key="@string/pref_category_privacy_key" | ||||
|  |         android:title="@string/pref_category_privacy" | ||||
|  |         app:iconSpaceReserved="false"> | ||||
|  |         <androidx.preference.SwitchPreferenceCompat | ||||
|  |             android:defaultValue="false" | ||||
|  |             android:key="@string/pref_privacy_crashlytics_enable_key" | ||||
|  |             android:title="@string/pref_title_privacy_crashlytics_enable" | ||||
|  |             android:summary="@string/pref_summary_privacy_crashlytics_enable" | ||||
|  |             app:iconSpaceReserved="false" /> | ||||
|  |         <androidx.preference.SwitchPreferenceCompat | ||||
|  |             android:defaultValue="false" | ||||
|  |             android:key="@string/pref_privacy_analytics_enable_key" | ||||
|  |             android:title="@string/pref_title_privacy_analytics_enable" | ||||
|  |             android:summary="@string/pref_summary_privacy_analytics_enable" | ||||
|  |             app:iconSpaceReserved="false" /> | ||||
|  |     </androidx.preference.PreferenceCategory> | ||||
|  | </androidx.preference.PreferenceScreen> | ||||
					Loading…
					
					
				
		Reference in new issue