use Locale from DynamicLanguage for displaying dates

1) fixed DateUtils to use SimpleDateFormat for everything because it respects Locale
2) added getCurrentLocale() method to DynamicLanguage
3) allow PassphraseRequiredActionBarActivity.initFragment() to accept a Locale
4) updated classes that depend on DateUtils to pass down Locale from DynamicLanguage

Fixes #2684
Closes #2725
// FREEBIE
This commit is contained in:
Rhodey Orbits 2015-03-19 13:08:48 -07:00 committed by Jake McGinty
parent 424a463b21
commit d8521637bb
12 changed files with 75 additions and 33 deletions

View File

@ -173,7 +173,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
setContentView(R.layout.conversation_activity);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
fragment = initFragment(R.id.fragment_content, new ConversationFragment(), masterSecret);
fragment = initFragment(R.id.fragment_content, new ConversationFragment(), masterSecret, dynamicLanguage.getCurrentLocale());
initializeReceivers();
initializeViews();

View File

@ -18,7 +18,6 @@ package org.thoughtcrime.securesms;
import android.content.Context;
import android.database.Cursor;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -36,6 +35,7 @@ import org.thoughtcrime.securesms.util.LRUCache;
import java.lang.ref.SoftReference;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
@ -64,16 +64,19 @@ public class ConversationAdapter extends CursorAdapter implements AbsListView.Re
private final SelectionClickListener selectionClickListener;
private final Context context;
private final MasterSecret masterSecret;
private final Locale locale;
private final boolean groupThread;
private final boolean pushDestination;
private final LayoutInflater inflater;
public ConversationAdapter(Context context, MasterSecret masterSecret, SelectionClickListener selectionClickListener,
boolean groupThread, boolean pushDestination)
public ConversationAdapter(Context context, MasterSecret masterSecret, Locale locale,
SelectionClickListener selectionClickListener, boolean groupThread,
boolean pushDestination)
{
super(context, null, 0);
this.context = context;
this.masterSecret = masterSecret;
this.locale = locale;
this.selectionClickListener = selectionClickListener;
this.groupThread = groupThread;
this.pushDestination = pushDestination;
@ -87,7 +90,7 @@ public class ConversationAdapter extends CursorAdapter implements AbsListView.Re
String type = cursor.getString(cursor.getColumnIndexOrThrow(MmsSmsDatabase.TRANSPORT));
MessageRecord messageRecord = getMessageRecord(id, cursor, type);
item.set(masterSecret, messageRecord, batchSelected, selectionClickListener,
item.set(masterSecret, messageRecord, locale, batchSelected, selectionClickListener,
groupThread, pushDestination);
}

View File

@ -45,6 +45,7 @@ import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
public class ConversationFragment extends ListFragment
implements LoaderManager.LoaderCallbacks<Cursor>
@ -60,11 +61,13 @@ public class ConversationFragment extends ListFragment
private Recipients recipients;
private long threadId;
private ActionMode actionMode;
private Locale locale;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
this.masterSecret = getArguments().getParcelable("master_secret");
this.locale = (Locale) getArguments().getSerializable(PassphraseRequiredActionBarActivity.LOCALE_EXTRA);
}
@Override
@ -116,7 +119,7 @@ public class ConversationFragment extends ListFragment
private void initializeListAdapter() {
if (this.recipients != null && this.threadId != -1) {
this.setListAdapter(new ConversationAdapter(getActivity(), masterSecret, selectionClickListener,
this.setListAdapter(new ConversationAdapter(getActivity(), masterSecret, locale, selectionClickListener,
(!this.recipients.isSingleRecipient()) || this.recipients.isGroupRecipient(),
DirectoryHelper.isPushDestination(getActivity(), this.recipients)));
getListView().setRecyclerListener((ConversationAdapter)getListAdapter());

View File

@ -58,6 +58,7 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.Emoji;
import java.util.Locale;
import java.util.Set;
/**
@ -73,6 +74,7 @@ public class ConversationItem extends LinearLayout {
private MessageRecord messageRecord;
private MasterSecret masterSecret;
private Locale locale;
private boolean groupThread;
private boolean pushDestination;
@ -138,12 +140,14 @@ public class ConversationItem extends LinearLayout {
public void set(@NonNull MasterSecret masterSecret,
@NonNull MessageRecord messageRecord,
@NonNull Locale locale,
@NonNull Set<MessageRecord> batchSelected,
@NonNull SelectionClickListener selectionClickListener,
boolean groupThread, boolean pushDestination)
{
this.masterSecret = masterSecret;
this.messageRecord = messageRecord;
this.locale = locale;
this.batchSelected = batchSelected;
this.selectionClickListener = selectionClickListener;
this.groupThread = groupThread;
@ -287,7 +291,7 @@ public class ConversationItem extends LinearLayout {
if (messageRecord.isPush()) timestamp = messageRecord.getDateSent();
else timestamp = messageRecord.getDateReceived();
dateText.setText(DateUtils.getExtendedRelativeTimeSpanString(getContext(), timestamp));
dateText.setText(DateUtils.getExtendedRelativeTimeSpanString(getContext(), locale, timestamp));
}
private void setFailedStatusIcons() {

View File

@ -42,7 +42,6 @@ import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
public class ConversationListActivity extends PassphraseRequiredActionBarActivity
implements ConversationListFragment.ConversationSelectedListener
{
@ -67,7 +66,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE);
getSupportActionBar().setTitle(R.string.app_name);
fragment = initFragment(android.R.id.content, new ConversationListFragment(), masterSecret);
fragment = initFragment(android.R.id.content, new ConversationListFragment(), masterSecret, dynamicLanguage.getCurrentLocale());
initializeContactUpdatesReceiver();

View File

@ -36,6 +36,7 @@ import org.thoughtcrime.securesms.database.model.ThreadRecord;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
/**
@ -47,6 +48,7 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter<Conversat
private final ThreadDatabase threadDatabase;
private final MasterCipher masterCipher;
private final Locale locale;
private final Context context;
private final LayoutInflater inflater;
private final ItemClickListener clickListener;
@ -80,12 +82,14 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter<Conversat
public ConversationListAdapter(@NonNull Context context,
@NonNull MasterSecret masterSecret,
@NonNull Locale locale,
@Nullable Cursor cursor,
@Nullable ItemClickListener clickListener) {
super(context, cursor);
this.masterCipher = new MasterCipher(masterSecret);
this.context = context;
this.threadDatabase = DatabaseFactory.getThreadDatabase(context);
this.locale = locale;
this.inflater = LayoutInflater.from(context);
this.clickListener = clickListener;
}
@ -101,7 +105,7 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter<Conversat
ThreadDatabase.Reader reader = threadDatabase.readerFor(cursor, masterCipher);
ThreadRecord record = reader.getCurrent();
viewHolder.getItem().set(record, batchSet, batchMode);
viewHolder.getItem().set(record, locale, batchSet, batchMode);
}
public void toggleThreadInBatchSet(long threadId) {

View File

@ -56,24 +56,26 @@ import org.thoughtcrime.securesms.database.loaders.ConversationListLoader;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipients;
import java.util.Locale;
import java.util.Set;
public class ConversationListFragment extends Fragment
implements LoaderManager.LoaderCallbacks<Cursor>, ActionMode.Callback, ItemClickListener
{
private MasterSecret masterSecret;
private ActionMode actionMode;
private RecyclerView list;
private ReminderView reminderView;
private FloatingActionButton fab;
private Locale locale;
private String queryFilter = "";
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
masterSecret = getArguments().getParcelable("master_secret");
locale = (Locale) getArguments().getSerializable(PassphraseRequiredActionBarActivity.LOCALE_EXTRA);
}
@Override
@ -140,7 +142,7 @@ public class ConversationListFragment extends Fragment
}
private void initializeListAdapter() {
list.setAdapter(new ConversationListAdapter(getActivity(), masterSecret, null, this));
list.setAdapter(new ConversationListAdapter(getActivity(), masterSecret, locale, null, this));
list.setRecyclerListener(new RecyclerListener() {
@Override
public void onViewRecycled(ViewHolder holder) {

View File

@ -33,6 +33,7 @@ import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.Emoji;
import org.thoughtcrime.securesms.util.RecipientViewUtil;
import java.util.Locale;
import java.util.Set;
import static org.thoughtcrime.securesms.util.SpanUtil.color;
@ -86,7 +87,7 @@ public class ConversationListItem extends RelativeLayout
initializeContactWidgetVisibility();
}
public void set(ThreadRecord thread, Set<Long> selectedThreads, boolean batchMode) {
public void set(ThreadRecord thread, Locale locale, Set<Long> selectedThreads, boolean batchMode) {
this.selectedThreads = selectedThreads;
this.recipients = thread.getRecipients();
this.threadId = thread.getThreadId();
@ -103,7 +104,7 @@ public class ConversationListItem extends RelativeLayout
this.subjectView.setTypeface(read ? LIGHT_TYPEFACE : BOLD_TYPEFACE);
if (thread.getDate() > 0) {
CharSequence date = DateUtils.getBriefRelativeTimeSpanString(context, thread.getDate());
CharSequence date = DateUtils.getBriefRelativeTimeSpanString(context, locale, thread.getDate());
dateView.setText(read ? date : color(getResources().getColor(R.color.textsecure_primary), date));
dateView.setTypeface(read ? LIGHT_TYPEFACE : BOLD_TYPEFACE);
}

View File

@ -54,6 +54,7 @@ import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Locale;
/**
* @author Jake McGinty
@ -147,7 +148,8 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
sentDate.setText("-");
receivedContainer.setVisibility(View.GONE);
} else {
SimpleDateFormat dateFormatter = DateUtils.getDetailedDateFormatter(this);
Locale dateLocale = dynamicLanguage.getCurrentLocale();
SimpleDateFormat dateFormatter = DateUtils.getDetailedDateFormatter(this, dateLocale);
sentDate.setText(dateFormatter.format(new Date(messageRecord.getDateSent())));
if (messageRecord.getDateReceived() != messageRecord.getDateSent() && !messageRecord.isOutgoing()) {
@ -169,7 +171,8 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
toFromRes = R.string.message_details_header__from;
}
toFrom.setText(toFromRes);
conversationItem.set(masterSecret, messageRecord, new HashSet<MessageRecord>(), new NullSelectionListener(),
conversationItem.set(masterSecret, messageRecord, dynamicLanguage.getCurrentLocale(),
new HashSet<MessageRecord>(), new NullSelectionListener(),
recipients != messageRecord.getRecipients(),
DirectoryHelper.isPushDestination(this, recipients));
recipientsList.setAdapter(new MessageDetailsRecipientAdapter(this, masterSecret, messageRecord,

View File

@ -19,9 +19,13 @@ import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.service.MessageRetrievalService;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.util.Locale;
public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarActivity implements MasterSecretListener {
private static final String TAG = PassphraseRequiredActionBarActivity.class.getSimpleName();
public static final String LOCALE_EXTRA = "locale_extra";
private static final int STATE_NORMAL = 0;
private static final int STATE_CREATE_PASSPHRASE = 1;
private static final int STATE_PROMPT_PASSPHRASE = 2;
@ -78,9 +82,12 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
protected <T extends Fragment> T initFragment(@IdRes int target,
@NonNull T fragment,
@NonNull MasterSecret masterSecret) {
@NonNull MasterSecret masterSecret,
@Nullable Locale locale) {
Bundle args = new Bundle();
args.putParcelable("master_secret", masterSecret);
args.putSerializable(LOCALE_EXTRA, locale);
fragment.setArguments(args);
getSupportFragmentManager().beginTransaction()
.replace(target, fragment)
@ -88,6 +95,12 @@ public abstract class PassphraseRequiredActionBarActivity extends BaseActionBarA
return fragment;
}
protected <T extends Fragment> T initFragment(@IdRes int target,
@NonNull T fragment,
@NonNull MasterSecret masterSecret) {
return initFragment(target, fragment, masterSecret, null);
}
private void routeApplicationState(MasterSecret masterSecret) {
Intent intent = getIntentForState(masterSecret, getApplicationState(masterSecret));
if (intent != null) {

View File

@ -24,6 +24,7 @@ import java.util.Locale;
import org.thoughtcrime.securesms.R;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
@ -39,7 +40,12 @@ public class DateUtils extends android.text.format.DateUtils {
return (int) to.convert(System.currentTimeMillis() - millis, TimeUnit.MILLISECONDS);
}
public static String getBriefRelativeTimeSpanString(final Context c, final long timestamp) {
private static String getFormattedDateTime(long time, String template, Locale locale) {
String localizedPattern = new SimpleDateFormat(template, locale).toLocalizedPattern();
return new SimpleDateFormat(localizedPattern, locale).format(new Date(time));
}
public static String getBriefRelativeTimeSpanString(final Context c, final Locale locale, final long timestamp) {
if (isWithin(timestamp, 1, TimeUnit.MINUTES)) {
return c.getString(R.string.DateUtils_now);
} else if (isWithin(timestamp, 1, TimeUnit.HOURS)) {
@ -49,34 +55,34 @@ public class DateUtils extends android.text.format.DateUtils {
int hours = convertDelta(timestamp, TimeUnit.HOURS);
return c.getResources().getQuantityString(R.plurals.hours_ago, hours, hours);
} else if (isWithin(timestamp, 6, TimeUnit.DAYS)) {
return formatDateTime(c, timestamp, DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_WEEKDAY);
return getFormattedDateTime(timestamp, "EEE", locale);
} else if (isWithin(timestamp, 365, TimeUnit.DAYS)) {
return formatDateTime(c, timestamp, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR | DateUtils.FORMAT_ABBREV_ALL);
return getFormattedDateTime(timestamp, "MMM d", locale);
} else {
return formatDateTime(c, timestamp, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_ALL);
return getFormattedDateTime(timestamp, "MMM d, yyyy", locale);
}
}
public static String getExtendedRelativeTimeSpanString(final Context c, final long timestamp) {
public static String getExtendedRelativeTimeSpanString(final Context c, final Locale locale, final long timestamp) {
if (isWithin(timestamp, 1, TimeUnit.MINUTES)) {
return c.getString(R.string.DateUtils_now);
} else if (isWithin(timestamp, 1, TimeUnit.HOURS)) {
int mins = (int)TimeUnit.MINUTES.convert(System.currentTimeMillis() - timestamp, TimeUnit.MILLISECONDS);
return c.getResources().getQuantityString(R.plurals.minutes_ago, mins, mins);
} else {
int formatFlags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_TIME;
if (isWithin(timestamp, 6, TimeUnit.DAYS)) {
formatFlags |= DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_ABBREV_WEEKDAY;
} else if (isWithin(timestamp, 365, TimeUnit.DAYS)) {
formatFlags |= DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR | DateUtils.FORMAT_ABBREV_ALL;
} else {
formatFlags |= DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_ALL;
}
return DateUtils.formatDateTime(c, timestamp, formatFlags);
StringBuilder format = new StringBuilder();
if (isWithin(timestamp, 6, TimeUnit.DAYS)) format.append("EEE ");
else if (isWithin(timestamp, 365, TimeUnit.DAYS)) format.append("MMM d, ");
else format.append("MMM d, yyyy, ");
if (DateFormat.is24HourFormat(c)) format.append("HH:mm");
else format.append("hh:mm a");
return getFormattedDateTime(timestamp, format.toString(), locale);
}
}
public static SimpleDateFormat getDetailedDateFormatter(Context context) {
public static SimpleDateFormat getDetailedDateFormatter(Context context, Locale locale) {
String dateFormatPattern;
if (DateFormat.is24HourFormat(context)) {
@ -85,7 +91,7 @@ public class DateUtils extends android.text.format.DateUtils {
dateFormatPattern = "MMM d, yyyy hh:mm:ss a zzz";
}
return new SimpleDateFormat(dateFormatPattern, Locale.getDefault());
return new SimpleDateFormat(dateFormatPattern, locale);
}
}

View File

@ -35,6 +35,10 @@ public class DynamicLanguage {
setContextLocale(service, currentLocale);
}
public Locale getCurrentLocale() {
return currentLocale;
}
private static void setContextLocale(Context context, Locale selectedLocale) {
Configuration configuration = context.getResources().getConfiguration();