Messaging: Add automation compose and rebrand as com.bnkode.notie.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+4
-4
@@ -88,12 +88,12 @@ android_app {
|
||||
"--version-code",
|
||||
"10001040",
|
||||
"--rename-manifest-package",
|
||||
"com.filabcorp.msgq",
|
||||
"com.bnkode.notie",
|
||||
],
|
||||
required: [
|
||||
"libframesequence",
|
||||
"libgiftranscode",
|
||||
"com.filabcorp.msgq.allowlist",
|
||||
"com.bnkode.notie.allowlist",
|
||||
],
|
||||
optimize: {
|
||||
obfuscate: true,
|
||||
@@ -107,9 +107,9 @@ android_app {
|
||||
}
|
||||
|
||||
prebuilt_etc {
|
||||
name: "com.filabcorp.msgq.allowlist",
|
||||
name: "com.bnkode.notie.allowlist",
|
||||
product_specific: true,
|
||||
sub_dir: "sysconfig",
|
||||
src: "com.filabcorp.msgq.allowlist.xml",
|
||||
src: "com.bnkode.notie.allowlist.xml",
|
||||
filename_from_src: true,
|
||||
}
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@ android {
|
||||
compileSdk 35
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'com.filabcorp.msgq'
|
||||
applicationId 'com.bnkode.notie'
|
||||
minSdk 33
|
||||
targetSdk 34
|
||||
versionCode 10001040
|
||||
@@ -106,5 +106,5 @@ tasks.register('launchMessaging', Exec) {
|
||||
description = "Launch Messaging on ${messagingAvdSerial}"
|
||||
dependsOn 'installMessaging'
|
||||
commandLine adbExecutable.absolutePath, '-s', messagingAvdSerial, 'shell', 'am', 'start',
|
||||
'-n', 'com.filabcorp.msgq/com.android.messaging.ui.conversationlist.ConversationListActivity'
|
||||
'-n', 'com.bnkode.notie/com.android.messaging.ui.conversationlist.ConversationListActivity'
|
||||
}
|
||||
|
||||
@@ -398,20 +398,20 @@
|
||||
|
||||
<provider
|
||||
android:name=".datamodel.MessagingContentProvider"
|
||||
android:authorities="com.filabcorp.msgq.datamodel.MessagingContentProvider"
|
||||
android:authorities="com.bnkode.notie.datamodel.MessagingContentProvider"
|
||||
android:exported="false"
|
||||
android:label="@string/app_name">
|
||||
</provider>
|
||||
|
||||
<provider
|
||||
android:name=".datamodel.MmsFileProvider"
|
||||
android:authorities="com.filabcorp.msgq.datamodel.MmsFileProvider"
|
||||
android:authorities="com.bnkode.notie.datamodel.MmsFileProvider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true" />
|
||||
|
||||
<provider
|
||||
android:name=".datamodel.MediaScratchFileProvider"
|
||||
android:authorities="com.filabcorp.msgq.datamodel.MediaScratchFileProvider"
|
||||
android:authorities="com.bnkode.notie.datamodel.MediaScratchFileProvider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true" />
|
||||
|
||||
@@ -467,18 +467,18 @@
|
||||
android:name=".receiver.SendStatusReceiver"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.filabcorp.msgq.receiver.SendStatusReceiver.MESSAGE_SENT" />
|
||||
<action android:name="com.bnkode.notie.receiver.SendStatusReceiver.MESSAGE_SENT" />
|
||||
<data android:scheme="content" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="com.filabcorp.msgq.receiver.SendStatusReceiver.MESSAGE_DELIVERED" />
|
||||
<action android:name="com.bnkode.notie.receiver.SendStatusReceiver.MESSAGE_DELIVERED" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="com.filabcorp.msgq.receiver.SendStatusReceiver.MMS_SENT" />
|
||||
<action android:name="com.bnkode.notie.receiver.SendStatusReceiver.MMS_SENT" />
|
||||
<data android:scheme="content" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="com.filabcorp.msgq.receiver.SendStatusReceiver.MMS_DOWNLOADED" />
|
||||
<action android:name="com.bnkode.notie.receiver.SendStatusReceiver.MMS_DOWNLOADED" />
|
||||
<data android:scheme="content" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
@@ -521,7 +521,7 @@
|
||||
android:name=".receiver.ScheduledMessageReceiver"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.filabcorp.msgq.SEND_SCHEDULED_MESSAGE" />
|
||||
<action android:name="com.bnkode.notie.SEND_SCHEDULED_MESSAGE" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
@@ -536,7 +536,7 @@
|
||||
android:name=".datamodel.action.ActionServiceImpl$PendingActionReceiver"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.filabcorp.msgq.datamodel.PENDING_ACTION" />
|
||||
<action android:name="com.bnkode.notie.datamodel.PENDING_ACTION" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
|
||||
@@ -700,7 +700,16 @@ public class BugleDatabaseOperations {
|
||||
sortTimestamp = cursor.getLong(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (sortTimestamp == 0) {
|
||||
try (Cursor existing = dbWrapper.query(DatabaseHelper.CONVERSATIONS_TABLE,
|
||||
new String[]{ ConversationColumns.SORT_TIMESTAMP },
|
||||
ConversationColumns._ID + "=?",
|
||||
new String[]{ conversationId }, null, null, null)) {
|
||||
if (existing.moveToFirst()) {
|
||||
sortTimestamp = existing.getLong(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final ContentValues values = new ContentValues();
|
||||
if (draftMessage == null || !draftMessage.hasContent()) {
|
||||
|
||||
@@ -46,7 +46,7 @@ public class MediaScratchFileProvider extends FileProvider {
|
||||
private static final SimpleArrayMap<Uri, String> sUriToDisplayNameMap = new SimpleArrayMap<>();
|
||||
|
||||
public static final String AUTHORITY =
|
||||
"com.filabcorp.msgq.datamodel.MediaScratchFileProvider";
|
||||
"com.bnkode.notie.datamodel.MediaScratchFileProvider";
|
||||
private static final String MEDIA_SCRATCH_SPACE_DIR = "mediascratchspace";
|
||||
|
||||
public static boolean isMediaScratchSpaceUri(final Uri uri) {
|
||||
|
||||
@@ -53,7 +53,7 @@ public class MessagingContentProvider extends ContentProvider {
|
||||
private static final String TAG = LogUtil.BUGLE_TAG;
|
||||
|
||||
public static final String AUTHORITY =
|
||||
"com.filabcorp.msgq.datamodel.MessagingContentProvider";
|
||||
"com.bnkode.notie.datamodel.MessagingContentProvider";
|
||||
private static final String CONTENT_AUTHORITY = "content://" + AUTHORITY + '/';
|
||||
|
||||
// Conversations query
|
||||
|
||||
@@ -32,7 +32,7 @@ import java.io.IOException;
|
||||
public class MmsFileProvider extends FileProvider {
|
||||
private static final String TAG = LogUtil.BUGLE_TAG;
|
||||
|
||||
static final String AUTHORITY = "com.filabcorp.msgq.datamodel.MmsFileProvider";
|
||||
static final String AUTHORITY = "com.bnkode.notie.datamodel.MmsFileProvider";
|
||||
private static final String RAW_MMS_DIR = "rawmms";
|
||||
|
||||
/**
|
||||
|
||||
@@ -137,7 +137,7 @@ public class ActionServiceImpl extends JobIntentService {
|
||||
* Broadcast receiver for alarms scheduled through ActionService.
|
||||
*/
|
||||
public static class PendingActionReceiver extends BroadcastReceiver {
|
||||
static final String ACTION = "com.filabcorp.msgq.datamodel.PENDING_ACTION";
|
||||
static final String ACTION = "com.bnkode.notie.datamodel.PENDING_ACTION";
|
||||
|
||||
/**
|
||||
* Allocate an intent with a specific opcode and alarm action.
|
||||
|
||||
@@ -11,7 +11,7 @@ import java.util.concurrent.Executors;
|
||||
|
||||
/** Fires a previously scheduled compose message when its AlarmManager time is reached. */
|
||||
public class ScheduledMessageReceiver extends BroadcastReceiver {
|
||||
public static final String ACTION_SEND = "com.filabcorp.msgq.SEND_SCHEDULED_MESSAGE";
|
||||
public static final String ACTION_SEND = "com.bnkode.notie.SEND_SCHEDULED_MESSAGE";
|
||||
public static final String EXTRA_ID = "scheduled_id";
|
||||
|
||||
@Override
|
||||
|
||||
@@ -38,13 +38,13 @@ import com.android.messaging.util.LogUtil;
|
||||
*/
|
||||
public class SendStatusReceiver extends BroadcastReceiver {
|
||||
public static final String MESSAGE_SENT_ACTION =
|
||||
"com.filabcorp.msgq.receiver.SendStatusReceiver.MESSAGE_SENT";
|
||||
"com.bnkode.notie.receiver.SendStatusReceiver.MESSAGE_SENT";
|
||||
public static final String MESSAGE_DELIVERED_ACTION =
|
||||
"com.filabcorp.msgq.receiver.SendStatusReceiver.MESSAGE_DELIVERED";
|
||||
"com.bnkode.notie.receiver.SendStatusReceiver.MESSAGE_DELIVERED";
|
||||
public static final String MMS_SENT_ACTION =
|
||||
"com.filabcorp.msgq.receiver.SendStatusReceiver.MMS_SENT";
|
||||
"com.bnkode.notie.receiver.SendStatusReceiver.MMS_SENT";
|
||||
public static final String MMS_DOWNLOADED_ACTION =
|
||||
"com.filabcorp.msgq.receiver.SendStatusReceiver.MMS_DOWNLOADED";
|
||||
"com.bnkode.notie.receiver.SendStatusReceiver.MMS_DOWNLOADED";
|
||||
|
||||
// Defined by platform, but no constant provided. See docs for SmsManager.sendTextMessage.
|
||||
public static final String EXTRA_ERROR_CODE = "errorCode";
|
||||
|
||||
@@ -71,7 +71,7 @@ public abstract class UIIntents {
|
||||
public static final String UI_INTENT_EXTRA_WITH_CUSTOM_TRANSITION = "with_custom_transition";
|
||||
|
||||
public static final String ACTION_RESET_NOTIFICATIONS =
|
||||
"com.filabcorp.msgq.reset_notifications";
|
||||
"com.bnkode.notie.reset_notifications";
|
||||
|
||||
// Sending VCard uri to VCard detail activity
|
||||
public static final String UI_INTENT_EXTRA_VCARD_URI = "vcard_uri";
|
||||
@@ -108,7 +108,7 @@ public abstract class UIIntents {
|
||||
public static final String UI_INTENT_EXTRA_LOCATION_IMAGE_URI = "location_image_uri";
|
||||
|
||||
public static final String ACTION_WIDGET_CONVERSATION =
|
||||
"com.filabcorp.msgq.widget_conversation:";
|
||||
"com.bnkode.notie.widget_conversation:";
|
||||
|
||||
public static final String UI_INTENT_EXTRA_REQUIRES_MMS = "requires_mms";
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import com.android.messaging.datamodel.DataModel;
|
||||
import com.android.messaging.datamodel.data.ContactListItemData;
|
||||
import com.android.messaging.datamodel.data.ParticipantData;
|
||||
import com.android.messaging.ui.ContactIconView;
|
||||
import com.android.messaging.ui.home.HomeAvatarOverlay;
|
||||
import com.android.messaging.util.Assert;
|
||||
import com.android.messaging.util.AvatarUriUtil;
|
||||
|
||||
@@ -44,6 +45,10 @@ public class ContactListItemView extends LinearLayout implements OnClickListener
|
||||
public interface HostInterface {
|
||||
void onContactListItemClicked(ContactListItemData item, ContactListItemView view);
|
||||
boolean isContactSelected(ContactListItemData item);
|
||||
|
||||
default boolean isContactSelectionMode() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final ContactListItemData mData;
|
||||
@@ -189,7 +194,8 @@ public class ContactListItemView extends LinearLayout implements OnClickListener
|
||||
mContactIconView.setImageResourceUri(avatarUri, mData.getContactId(),
|
||||
mData.getLookupKey(), destinationString);
|
||||
mContactIconView.setVisibility(VISIBLE);
|
||||
mContactCheckmarkView.setVisibility(GONE);
|
||||
applySelectionCheck(isContactChecked());
|
||||
bindAvatarClickTargets();
|
||||
mContactDetailTypeTextView.setVisibility(GONE);
|
||||
mContactDetailsTextView.setVisibility(GONE);
|
||||
mContactNameTextView.setVisibility(VISIBLE);
|
||||
@@ -202,7 +208,8 @@ public class ContactListItemView extends LinearLayout implements OnClickListener
|
||||
mContactNameTextView.setVisibility(VISIBLE);
|
||||
final boolean isSelected = mHostInterface.isContactSelected(mData);
|
||||
setSelected(isSelected);
|
||||
mContactCheckmarkView.setVisibility(isSelected ? VISIBLE : GONE);
|
||||
applySelectionCheck(isSelected);
|
||||
bindAvatarClickTargets();
|
||||
mContactDetailsTextView.setVisibility(VISIBLE);
|
||||
mContactDetailTypeTextView.setVisibility(VISIBLE);
|
||||
} else {
|
||||
@@ -211,7 +218,8 @@ public class ContactListItemView extends LinearLayout implements OnClickListener
|
||||
mContactNameTextView.setVisibility(GONE);
|
||||
final boolean isSelected = mHostInterface.isContactSelected(mData);
|
||||
setSelected(isSelected);
|
||||
mContactCheckmarkView.setVisibility(isSelected ? VISIBLE : GONE);
|
||||
applySelectionCheck(isSelected);
|
||||
bindAvatarClickTargets();
|
||||
mContactDetailsTextView.setVisibility(VISIBLE);
|
||||
mContactDetailTypeTextView.setVisibility(VISIBLE);
|
||||
}
|
||||
@@ -230,6 +238,34 @@ public class ContactListItemView extends LinearLayout implements OnClickListener
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isContactChecked() {
|
||||
return mHostInterface != null && mHostInterface.isContactSelected(mData);
|
||||
}
|
||||
|
||||
private void applySelectionCheck(final boolean selected) {
|
||||
HomeAvatarOverlay.apply(mContactCheckmarkView, isSelectionMode(), selected);
|
||||
}
|
||||
|
||||
private boolean isSelectionMode() {
|
||||
return mHostInterface != null && mHostInterface.isContactSelectionMode();
|
||||
}
|
||||
|
||||
private void bindAvatarClickTargets() {
|
||||
if (mContactIconView == null) {
|
||||
return;
|
||||
}
|
||||
mContactIconView.setImageClickHandlerDisabled(true);
|
||||
final boolean selectionMode = isSelectionMode();
|
||||
final OnClickListener selectRow = v -> performClick();
|
||||
if (mContactCheckmarkView != null) {
|
||||
mContactCheckmarkView.setOnClickListener(selectionMode ? selectRow : null);
|
||||
mContactCheckmarkView.setClickable(selectionMode);
|
||||
mContactCheckmarkView.setFocusable(false);
|
||||
}
|
||||
mContactIconView.setOnClickListener(selectionMode ? selectRow : null);
|
||||
mContactIconView.setClickable(selectionMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc} from OnClickListener
|
||||
*/
|
||||
|
||||
@@ -291,6 +291,13 @@ public class ContactPickerFragment extends Fragment implements ContactPickerData
|
||||
item.getRecipientEntry().getDestination()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContactSelectionMode() {
|
||||
return mContactPickingMode == MODE_PICK_INITIAL_CONTACT
|
||||
|| mContactPickingMode == MODE_PICK_MORE_CONTACTS
|
||||
|| mContactPickingMode == MODE_PICK_MAX_PARTICIPANTS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this immediately after attaching the fragment, or when there's a ui state change that
|
||||
* changes our host (i.e. restore from saved instance state).
|
||||
|
||||
+92
@@ -18,15 +18,29 @@ package com.android.messaging.ui.conversationlist;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.android.messaging.R;
|
||||
import com.android.messaging.ui.home.HomeAutomationHome;
|
||||
import com.android.messaging.ui.home.HomeEmptyState;
|
||||
import com.android.messaging.ui.home.HomeInboxMenu;
|
||||
import com.android.messaging.ui.home.HomeSubHeader;
|
||||
|
||||
public class ArchivedConversationListActivity extends AbstractConversationListActivity {
|
||||
|
||||
private static final String STATE_SHOW_RULES = "home_archived_show_rules";
|
||||
|
||||
private TextView mChatsTab;
|
||||
private TextView mRulesTab;
|
||||
private View mListHost;
|
||||
private View mRulesHost;
|
||||
private View mSearchCollapse;
|
||||
private boolean mShowRules;
|
||||
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -36,6 +50,11 @@ public class ArchivedConversationListActivity extends AbstractConversationListAc
|
||||
}
|
||||
HomeSubHeader.bind(this, R.string.home_archived_title, v -> onActionBarHome());
|
||||
HomeInboxMenu.bind(this, HomeInboxMenu.Screen.ARCHIVE);
|
||||
bindTabs();
|
||||
if (savedInstanceState != null) {
|
||||
mShowRules = savedInstanceState.getBoolean(STATE_SHOW_RULES, false);
|
||||
}
|
||||
showRules(mShowRules);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
mConversationListFragment =
|
||||
@@ -50,6 +69,79 @@ public class ArchivedConversationListActivity extends AbstractConversationListAc
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(final Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putBoolean(STATE_SHOW_RULES, mShowRules);
|
||||
}
|
||||
|
||||
private void bindTabs() {
|
||||
final View tabs = findViewById(R.id.home_archived_tabs);
|
||||
mChatsTab = findViewById(R.id.home_archived_tab_chats);
|
||||
mRulesTab = findViewById(R.id.home_archived_tab_rules);
|
||||
mListHost = findViewById(R.id.home_archived_list_host);
|
||||
mRulesHost = findViewById(R.id.home_archived_rules_host);
|
||||
mSearchCollapse = findViewById(R.id.home_sub_search_collapse);
|
||||
if (tabs != null) {
|
||||
tabs.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (mRulesHost != null) {
|
||||
HomeAutomationHome.bindArchive(mRulesHost);
|
||||
final HomeEmptyState empty = findViewById(R.id.home_archived_rules_empty);
|
||||
if (empty != null) {
|
||||
empty.setContent(R.drawable.ic_home_menu_archive,
|
||||
R.string.home_archived_rules_empty_title,
|
||||
R.string.home_archived_rules_empty_body);
|
||||
}
|
||||
}
|
||||
if (mChatsTab != null) {
|
||||
mChatsTab.setOnClickListener(v -> showRules(false));
|
||||
}
|
||||
if (mRulesTab != null) {
|
||||
mRulesTab.setOnClickListener(v -> showRules(true));
|
||||
}
|
||||
}
|
||||
|
||||
private void showRules(final boolean rules) {
|
||||
if (rules && isInConversationListSelectMode()) {
|
||||
exitMultiSelectState();
|
||||
}
|
||||
mShowRules = rules;
|
||||
applyPill(mChatsTab, !rules);
|
||||
applyPill(mRulesTab, rules);
|
||||
if (mListHost != null) {
|
||||
mListHost.setVisibility(rules ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
if (mRulesHost != null) {
|
||||
mRulesHost.setVisibility(rules ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
if (mSearchCollapse != null) {
|
||||
mSearchCollapse.setVisibility(rules ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
final View edit = findViewById(R.id.home_sub_header_edit);
|
||||
if (edit != null) {
|
||||
edit.setVisibility(rules ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
final View selectBar = findViewById(R.id.home_sub_select_bar);
|
||||
if (selectBar != null && rules) {
|
||||
selectBar.setVisibility(View.GONE);
|
||||
}
|
||||
if (rules && mRulesHost != null) {
|
||||
HomeAutomationHome.bindArchive(mRulesHost);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyPill(final TextView pill, final boolean selected) {
|
||||
if (pill == null) {
|
||||
return;
|
||||
}
|
||||
pill.setBackgroundResource(selected
|
||||
? R.drawable.home_bg_automation_pill_selected
|
||||
: R.drawable.home_bg_automation_pill);
|
||||
pill.setTextColor(ContextCompat.getColor(this,
|
||||
selected ? android.R.color.white : R.color.home_text_primary));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean useHomeSelectionChrome() {
|
||||
return true;
|
||||
|
||||
+5
@@ -79,6 +79,7 @@ import com.android.messaging.datamodel.data.ConversationListData.ConversationLis
|
||||
import com.android.messaging.datamodel.data.ConversationListItemData;
|
||||
import com.android.messaging.ui.ContactIconView;
|
||||
import com.android.messaging.ui.home.HomeAutomationHome;
|
||||
import com.android.messaging.ui.home.HomeDemoGroupSeed;
|
||||
import com.android.messaging.ui.home.HomeCategoryAddModal;
|
||||
import com.android.messaging.ui.home.HomeCategoryAssignSheet;
|
||||
import com.android.messaging.ui.home.HomeCategoryClassifier;
|
||||
@@ -306,6 +307,9 @@ public class ConversationListFragment extends Fragment implements ConversationLi
|
||||
updateHomeMainNavVisibility();
|
||||
refreshPinnedStrip();
|
||||
updateUi();
|
||||
if (mHomeAutomationPane != null) {
|
||||
HomeAutomationHome.applyVisibility(mHomeAutomationPane);
|
||||
}
|
||||
}
|
||||
|
||||
public void setScrolledToNewestConversationIfNeeded() {
|
||||
@@ -547,6 +551,7 @@ public class ConversationListFragment extends Fragment implements ConversationLi
|
||||
}
|
||||
selectHomeTab(mHomeTab);
|
||||
updateHomeEditButtonForPinnedMode();
|
||||
HomeDemoGroupSeed.ensure(requireContext());
|
||||
}
|
||||
|
||||
bindSubListSearch();
|
||||
|
||||
+66
-86
@@ -64,6 +64,7 @@ import com.android.messaging.ui.AudioAttachmentView;
|
||||
import com.android.messaging.ui.ContactIconView;
|
||||
import com.android.messaging.ui.SnackBar;
|
||||
import com.android.messaging.ui.SnackBarInteraction;
|
||||
import com.android.messaging.ui.home.HomeAvatarOverlay;
|
||||
import com.android.messaging.ui.home.HomeToast;
|
||||
import com.android.messaging.ui.home.MutedConversationStore;
|
||||
import com.android.messaging.util.Assert;
|
||||
@@ -172,6 +173,7 @@ public class ConversationListItemView extends FrameLayout implements OnClickList
|
||||
|
||||
private static final int SELECTION_TOGGLE_ANIM_MS = 180;
|
||||
private String mSelectionStateConversationId;
|
||||
private Boolean mSelectionStateMode;
|
||||
private Boolean mSelectionStateChecked;
|
||||
|
||||
public ConversationListItemView(final Context context, final AttributeSet attrs) {
|
||||
@@ -465,82 +467,57 @@ public class ConversationListItemView extends FrameLayout implements OnClickList
|
||||
|
||||
private void updateSelectionIndicator(final boolean selectionMode, final boolean isSelected,
|
||||
final Resources resources) {
|
||||
if (mSelectionIndicatorView == null || mSelectionRingView == null
|
||||
|| mSelectionCheckView == null) {
|
||||
return;
|
||||
}
|
||||
if (!selectionMode) {
|
||||
if (mSelectionIndicatorView != null) {
|
||||
mSelectionIndicatorView.animate().cancel();
|
||||
mSelectionCheckView.animate().cancel();
|
||||
mSelectionIndicatorView.setScaleX(1f);
|
||||
mSelectionIndicatorView.setScaleY(1f);
|
||||
mSelectionCheckView.setAlpha(1f);
|
||||
mSelectionCheckView.setScaleX(1f);
|
||||
mSelectionCheckView.setScaleY(1f);
|
||||
mSelectionIndicatorView.setVisibility(GONE);
|
||||
mSelectionStateConversationId = null;
|
||||
mSelectionStateChecked = null;
|
||||
}
|
||||
if (mContactCheckmarkView == null) {
|
||||
return;
|
||||
}
|
||||
mSelectionIndicatorView.setVisibility(VISIBLE);
|
||||
final String conversationId = mData.getConversationId();
|
||||
final boolean sameConversation = conversationId != null
|
||||
&& conversationId.equals(mSelectionStateConversationId);
|
||||
final boolean animateToggle = sameConversation && mSelectionStateChecked != null
|
||||
&& mSelectionStateChecked.booleanValue() != isSelected;
|
||||
final boolean wasMode = Boolean.TRUE.equals(mSelectionStateMode);
|
||||
final boolean wasSelected = Boolean.TRUE.equals(mSelectionStateChecked);
|
||||
final boolean animateToggle = sameConversation
|
||||
&& (wasMode != selectionMode || wasSelected != isSelected);
|
||||
mSelectionStateConversationId = conversationId;
|
||||
mSelectionStateMode = selectionMode;
|
||||
mSelectionStateChecked = isSelected;
|
||||
|
||||
mSelectionIndicatorView.animate().cancel();
|
||||
mSelectionCheckView.animate().cancel();
|
||||
|
||||
if (isSelected) {
|
||||
mSelectionRingView.setBackground(resources.getDrawable(
|
||||
R.drawable.home_bg_selection_ring_checked, getContext().getTheme()));
|
||||
mSelectionCheckView.setVisibility(VISIBLE);
|
||||
if (animateToggle) {
|
||||
mSelectionIndicatorView.setScaleX(0.88f);
|
||||
mSelectionIndicatorView.setScaleY(0.88f);
|
||||
mSelectionIndicatorView.animate()
|
||||
.scaleX(1f)
|
||||
.scaleY(1f)
|
||||
mContactCheckmarkView.animate().cancel();
|
||||
if (!selectionMode) {
|
||||
if (animateToggle && mContactCheckmarkView.getVisibility() == VISIBLE) {
|
||||
mContactCheckmarkView.animate()
|
||||
.alpha(0f)
|
||||
.scaleX(0.6f)
|
||||
.scaleY(0.6f)
|
||||
.setDuration(SELECTION_TOGGLE_ANIM_MS)
|
||||
.setInterpolator(new OvershootInterpolator(1.6f));
|
||||
mSelectionCheckView.setAlpha(0f);
|
||||
mSelectionCheckView.setScaleX(0.4f);
|
||||
mSelectionCheckView.setScaleY(0.4f);
|
||||
mSelectionCheckView.animate()
|
||||
.alpha(1f)
|
||||
.scaleX(1f)
|
||||
.scaleY(1f)
|
||||
.setDuration(SELECTION_TOGGLE_ANIM_MS)
|
||||
.setInterpolator(UiUtils.DEFAULT_INTERPOLATOR);
|
||||
.setInterpolator(UiUtils.DEFAULT_INTERPOLATOR)
|
||||
.withEndAction(() ->
|
||||
HomeAvatarOverlay.apply(mContactCheckmarkView, false, false))
|
||||
.start();
|
||||
} else {
|
||||
mSelectionIndicatorView.setScaleX(1f);
|
||||
mSelectionIndicatorView.setScaleY(1f);
|
||||
mSelectionCheckView.setAlpha(1f);
|
||||
mSelectionCheckView.setScaleX(1f);
|
||||
mSelectionCheckView.setScaleY(1f);
|
||||
HomeAvatarOverlay.apply(mContactCheckmarkView, false, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
HomeAvatarOverlay.apply(mContactCheckmarkView, true, isSelected);
|
||||
if (animateToggle && isSelected && !wasSelected) {
|
||||
mContactCheckmarkView.setAlpha(0f);
|
||||
mContactCheckmarkView.setScaleX(0.6f);
|
||||
mContactCheckmarkView.setScaleY(0.6f);
|
||||
mContactCheckmarkView.animate()
|
||||
.alpha(1f)
|
||||
.scaleX(1f)
|
||||
.scaleY(1f)
|
||||
.setDuration(SELECTION_TOGGLE_ANIM_MS)
|
||||
.setInterpolator(new OvershootInterpolator(1.6f))
|
||||
.start();
|
||||
} else {
|
||||
mSelectionRingView.setBackground(resources.getDrawable(
|
||||
R.drawable.home_bg_selection_ring, getContext().getTheme()));
|
||||
mSelectionCheckView.setVisibility(GONE);
|
||||
mSelectionCheckView.setAlpha(1f);
|
||||
mSelectionCheckView.setScaleX(1f);
|
||||
mSelectionCheckView.setScaleY(1f);
|
||||
if (animateToggle) {
|
||||
mSelectionIndicatorView.setScaleX(0.92f);
|
||||
mSelectionIndicatorView.setScaleY(0.92f);
|
||||
mSelectionIndicatorView.animate()
|
||||
.scaleX(1f)
|
||||
.scaleY(1f)
|
||||
.setDuration(SELECTION_TOGGLE_ANIM_MS)
|
||||
.setInterpolator(UiUtils.DEFAULT_INTERPOLATOR);
|
||||
} else {
|
||||
mSelectionIndicatorView.setScaleX(1f);
|
||||
mSelectionIndicatorView.setScaleY(1f);
|
||||
}
|
||||
mContactCheckmarkView.setAlpha(1f);
|
||||
mContactCheckmarkView.setScaleX(1f);
|
||||
mContactCheckmarkView.setScaleY(1f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,8 +558,7 @@ public class ConversationListItemView extends FrameLayout implements OnClickList
|
||||
}
|
||||
final ViewGroup.MarginLayoutParams layoutParams =
|
||||
(ViewGroup.MarginLayoutParams) mListDividerView.getLayoutParams();
|
||||
final int insetDp = selectionMode ? LIST_DIVIDER_INSET_SELECTION_DP
|
||||
: LIST_DIVIDER_INSET_DEFAULT_DP;
|
||||
final int insetDp = LIST_DIVIDER_INSET_DEFAULT_DP;
|
||||
final float density = getResources().getDisplayMetrics().density;
|
||||
final int insetPx = (int) (insetDp * density + 0.5f);
|
||||
if (layoutParams.leftMargin != insetPx) {
|
||||
@@ -788,7 +764,6 @@ public class ConversationListItemView extends FrameLayout implements OnClickList
|
||||
setSelected(isSelected);
|
||||
Uri iconUri = null;
|
||||
int contactIconVisibility = VISIBLE;
|
||||
int checkmarkVisiblity = GONE;
|
||||
int failStatusVisiblity = GONE;
|
||||
if (!isSelected) {
|
||||
// Only show the fail icon if it is not a group conversation.
|
||||
@@ -805,18 +780,8 @@ public class ConversationListItemView extends FrameLayout implements OnClickList
|
||||
mData.getParticipantLookupKey(), mData.getOtherParticipantNormalizedDestination());
|
||||
mContactIconView.setVisibility(contactIconVisibility);
|
||||
mContactIconView.setImageClickHandlerDisabled(true);
|
||||
mContactIconView.setOnLongClickListener(this);
|
||||
final boolean avatarInteractive = !mHostInterface.isSelectionMode();
|
||||
mContactIconView.setClickable(avatarInteractive);
|
||||
mContactIconView.setLongClickable(avatarInteractive);
|
||||
if (avatarInteractive) {
|
||||
mContactIconView.setOnClickListener(v -> mHostInterface.onConversationAvatarClicked(
|
||||
mData, mContactIconView));
|
||||
} else {
|
||||
mContactIconView.setOnClickListener(null);
|
||||
}
|
||||
bindAvatarClickTargets(selectionMode);
|
||||
|
||||
mContactCheckmarkView.setVisibility(checkmarkVisiblity);
|
||||
mFailedStatusIconView.setVisibility(failStatusVisiblity);
|
||||
final boolean muted = MutedConversationStore.isMuted(getContext(),
|
||||
mData.getConversationId());
|
||||
@@ -865,7 +830,9 @@ public class ConversationListItemView extends FrameLayout implements OnClickList
|
||||
ImageUtils.DEFAULT_CIRCLE_STROKE_COLOR /* circleStrokeColor */));
|
||||
mImagePreviewView.setOnLongClickListener(this);
|
||||
mImagePreviewView.setVisibility(previewImageVisibility);
|
||||
mImagePreviewView.setOnClickListener(previewClickListener);
|
||||
mImagePreviewView.setOnClickListener(selectionMode
|
||||
? v -> processClick(mSwipeableContainer, false)
|
||||
: previewClickListener);
|
||||
mAudioAttachmentView.setOnLongClickListener(this);
|
||||
mAudioAttachmentView.setVisibility(audioPreviewVisiblity);
|
||||
|
||||
@@ -888,14 +855,7 @@ public class ConversationListItemView extends FrameLayout implements OnClickList
|
||||
mData.getConversationId());
|
||||
setSelected(isSelected);
|
||||
updateSelectionIndicator(selectionMode, isSelected, resources);
|
||||
mContactIconView.setClickable(!selectionMode);
|
||||
mContactIconView.setLongClickable(!selectionMode);
|
||||
if (!selectionMode) {
|
||||
mContactIconView.setOnClickListener(v -> mHostInterface.onConversationAvatarClicked(
|
||||
mData, mContactIconView));
|
||||
} else {
|
||||
mContactIconView.setOnClickListener(null);
|
||||
}
|
||||
bindAvatarClickTargets(selectionMode);
|
||||
updatePinButton(selectionMode, resources);
|
||||
updateListDividerInset(selectionMode);
|
||||
}
|
||||
@@ -1093,8 +1053,28 @@ public class ConversationListItemView extends FrameLayout implements OnClickList
|
||||
return processClick(v, true);
|
||||
}
|
||||
|
||||
private void bindAvatarClickTargets(final boolean selectionMode) {
|
||||
final OnClickListener selectRow = v -> processClick(mSwipeableContainer, false);
|
||||
if (mContactCheckmarkView != null) {
|
||||
mContactCheckmarkView.setOnClickListener(selectionMode ? selectRow : null);
|
||||
mContactCheckmarkView.setClickable(selectionMode);
|
||||
mContactCheckmarkView.setFocusable(false);
|
||||
}
|
||||
mContactIconView.setOnLongClickListener(this);
|
||||
if (selectionMode) {
|
||||
mContactIconView.setOnClickListener(selectRow);
|
||||
mContactIconView.setClickable(true);
|
||||
mContactIconView.setLongClickable(false);
|
||||
} else {
|
||||
mContactIconView.setOnClickListener(v -> mHostInterface.onConversationAvatarClicked(
|
||||
mData, mContactIconView));
|
||||
mContactIconView.setClickable(true);
|
||||
mContactIconView.setLongClickable(true);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean processClick(final View v, final boolean isLongClick) {
|
||||
if (v == mContactIconView) {
|
||||
if (!mHostInterface.isSelectionMode() && v == mContactIconView) {
|
||||
return false;
|
||||
}
|
||||
Assert.isTrue(v == mSwipeableContainer || v == mImagePreviewView);
|
||||
|
||||
+359
-10
@@ -15,16 +15,50 @@
|
||||
*/
|
||||
package com.android.messaging.ui.home;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.android.messaging.R;
|
||||
import com.android.messaging.ui.BugleActionBarActivity;
|
||||
import com.android.messaging.ui.ContactIconView;
|
||||
|
||||
/** Sheet to create a new automation task. */
|
||||
import java.util.ArrayList;
|
||||
|
||||
/** Sheet to create a new automation rule. */
|
||||
public class HomeAutomationCreateActivity extends BugleActionBarActivity {
|
||||
|
||||
private View mTriggerMissed;
|
||||
private View mTriggerThanks;
|
||||
private View mTriggerSchedule;
|
||||
private View mTriggerKeyword;
|
||||
private TextView mRecipientAll;
|
||||
private TextView mRecipientContacts;
|
||||
private TextView mRecipientUnknown;
|
||||
private TextView mSelectContacts;
|
||||
private HomeFadeScrollView mRecipientScroll;
|
||||
private View mTargetChipHost;
|
||||
private View mTargetChipScroll;
|
||||
private LinearLayout mTargetChips;
|
||||
|
||||
private static final String STATE_TRIGGER = "home_automation_trigger";
|
||||
private static final String STATE_RECIPIENT = "home_automation_recipient";
|
||||
private static final String STATE_TARGETS = "home_automation_targets";
|
||||
|
||||
private int mTrigger;
|
||||
private int mRecipient;
|
||||
private final ArrayList<HomeAutomationTarget> mTargets = new ArrayList<>();
|
||||
private boolean mRestorePromptOpen;
|
||||
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -33,21 +67,336 @@ public class HomeAutomationCreateActivity extends BugleActionBarActivity {
|
||||
getSupportActionBar().hide();
|
||||
}
|
||||
|
||||
final ImageButton back = findViewById(R.id.home_sub_header_back);
|
||||
if (back != null) {
|
||||
back.setVisibility(View.GONE);
|
||||
}
|
||||
final ImageButton close = findViewById(R.id.home_sub_header_close);
|
||||
final View close = findViewById(R.id.home_sub_header_close);
|
||||
if (close != null) {
|
||||
close.setVisibility(View.VISIBLE);
|
||||
close.setOnClickListener(v -> finish());
|
||||
}
|
||||
HomeSubHeader.bind(this, R.string.home_automation_create_title, v -> finish());
|
||||
|
||||
final View scrim = findViewById(R.id.home_automation_create_scrim);
|
||||
if (scrim != null) {
|
||||
scrim.setOnClickListener(v -> finish());
|
||||
}
|
||||
|
||||
mTriggerMissed = bindTriggerRow(R.id.home_automation_trigger_missed,
|
||||
R.drawable.ic_home_automation_phone,
|
||||
R.string.home_automation_trigger_missed_title,
|
||||
R.string.home_automation_trigger_missed_body, true, 0);
|
||||
mTriggerThanks = bindTriggerRow(R.id.home_automation_trigger_thanks,
|
||||
R.drawable.ic_home_automation_phone,
|
||||
R.string.home_automation_trigger_thanks_title,
|
||||
R.string.home_automation_trigger_thanks_body, false, 1);
|
||||
mTriggerSchedule = bindTriggerTile(R.id.home_automation_trigger_schedule,
|
||||
R.drawable.ic_home_schedule_line,
|
||||
R.string.home_automation_trigger_schedule_title,
|
||||
R.string.home_automation_trigger_schedule_body, 2);
|
||||
mTriggerKeyword = bindTriggerTile(R.id.home_automation_trigger_keyword,
|
||||
R.drawable.ic_home_automation_chat,
|
||||
R.string.home_automation_trigger_keyword_title,
|
||||
R.string.home_automation_trigger_keyword_body, 3);
|
||||
|
||||
mRecipientScroll = findViewById(R.id.home_automation_recipient_scroll);
|
||||
mRecipientAll = findViewById(R.id.home_automation_recipient_all);
|
||||
mRecipientContacts = findViewById(R.id.home_automation_recipient_contacts);
|
||||
mRecipientUnknown = findViewById(R.id.home_automation_recipient_unknown);
|
||||
bindRecipient(mRecipientAll, 0);
|
||||
bindRecipient(mRecipientContacts, 1);
|
||||
bindRecipient(mRecipientUnknown, 2);
|
||||
|
||||
mSelectContacts = findViewById(R.id.home_automation_select_contacts);
|
||||
mTargetChipHost = findViewById(R.id.home_automation_target_chip_host);
|
||||
mTargetChipScroll = findViewById(R.id.home_automation_target_chip_scroll);
|
||||
mTargetChips = findViewById(R.id.home_automation_target_chips);
|
||||
getSupportFragmentManager().setFragmentResultListener(
|
||||
HomeAutomationTargetPickerSheet.REQUEST_KEY, this, (key, bundle) -> {
|
||||
final ArrayList<HomeAutomationTarget> selected = bundle
|
||||
.getParcelableArrayList(HomeAutomationTargetPickerSheet.EXTRA_TARGETS);
|
||||
mTargets.clear();
|
||||
if (selected != null) {
|
||||
mTargets.addAll(selected);
|
||||
}
|
||||
bindTargets();
|
||||
});
|
||||
if (mSelectContacts != null) {
|
||||
mSelectContacts.setOnClickListener(v -> openTargetPicker());
|
||||
}
|
||||
|
||||
comingSoon(R.id.home_automation_preview);
|
||||
comingSoon(R.id.home_automation_activate);
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
restoreState(savedInstanceState);
|
||||
} else if (HomeAutomationDraftStore.hasDraft(this)) {
|
||||
promptRestoreDraft();
|
||||
}
|
||||
|
||||
applyTrigger();
|
||||
applyRecipient();
|
||||
bindTargets();
|
||||
}
|
||||
|
||||
private View bindTriggerRow(final int id, @DrawableRes final int icon,
|
||||
@StringRes final int title, @StringRes final int body, final boolean recommended,
|
||||
final int triggerIndex) {
|
||||
final View row = findViewById(id);
|
||||
if (row == null) {
|
||||
return null;
|
||||
}
|
||||
final ImageView iconView = row.findViewById(R.id.home_automation_trigger_icon);
|
||||
if (iconView != null) {
|
||||
iconView.setImageResource(icon);
|
||||
}
|
||||
final TextView titleView = row.findViewById(R.id.home_automation_trigger_title);
|
||||
if (titleView != null) {
|
||||
titleView.setText(title);
|
||||
}
|
||||
final TextView bodyView = row.findViewById(R.id.home_automation_trigger_body);
|
||||
if (bodyView != null) {
|
||||
bodyView.setText(body);
|
||||
}
|
||||
final View badge = row.findViewById(R.id.home_automation_trigger_badge);
|
||||
if (badge != null) {
|
||||
badge.setVisibility(recommended ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
if (triggerIndex >= 0) {
|
||||
row.setOnClickListener(v -> selectTrigger(triggerIndex));
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
private View bindTriggerTile(final int id, @DrawableRes final int icon,
|
||||
@StringRes final int title, @StringRes final int body, final int triggerIndex) {
|
||||
final View tile = findViewById(id);
|
||||
if (tile == null) {
|
||||
return null;
|
||||
}
|
||||
final ImageView iconView = tile.findViewById(R.id.home_automation_trigger_icon);
|
||||
if (iconView != null) {
|
||||
iconView.setImageResource(icon);
|
||||
}
|
||||
final TextView titleView = tile.findViewById(R.id.home_automation_trigger_title);
|
||||
if (titleView != null) {
|
||||
titleView.setText(title);
|
||||
}
|
||||
final TextView bodyView = tile.findViewById(R.id.home_automation_trigger_body);
|
||||
if (bodyView != null) {
|
||||
bodyView.setText(body);
|
||||
}
|
||||
tile.setOnClickListener(v -> selectTrigger(triggerIndex));
|
||||
return tile;
|
||||
}
|
||||
|
||||
private void bindRecipient(final TextView pill, final int index) {
|
||||
if (pill != null) {
|
||||
pill.setOnClickListener(v -> selectRecipient(index));
|
||||
}
|
||||
}
|
||||
|
||||
private void comingSoon(final int id) {
|
||||
final View view = findViewById(id);
|
||||
if (view != null) {
|
||||
view.setOnClickListener(v -> HomeToast.show(this, R.string.home_automate_coming_soon));
|
||||
}
|
||||
}
|
||||
|
||||
private void selectTrigger(final int index) {
|
||||
if (mTrigger == index) {
|
||||
return;
|
||||
}
|
||||
mTrigger = index;
|
||||
applyTrigger();
|
||||
}
|
||||
|
||||
private void selectRecipient(final int index) {
|
||||
if (mRecipient == index) {
|
||||
return;
|
||||
}
|
||||
mRecipient = index;
|
||||
applyRecipient();
|
||||
}
|
||||
|
||||
private void applyTrigger() {
|
||||
applyTriggerRow(mTriggerMissed, mTrigger == 0, true);
|
||||
applyTriggerRow(mTriggerThanks, mTrigger == 1, true);
|
||||
applyTriggerTile(mTriggerSchedule, mTrigger == 2);
|
||||
applyTriggerTile(mTriggerKeyword, mTrigger == 3);
|
||||
}
|
||||
|
||||
private void applyRecipient() {
|
||||
applyPill(mRecipientAll, mRecipient == 0);
|
||||
applyPill(mRecipientContacts, mRecipient == 1);
|
||||
applyPill(mRecipientUnknown, mRecipient == 2);
|
||||
if (mRecipientScroll != null) {
|
||||
mRecipientScroll.centerChild(mRecipient == 0 ? mRecipientAll
|
||||
: mRecipient == 1 ? mRecipientContacts : mRecipientUnknown);
|
||||
}
|
||||
}
|
||||
|
||||
private void applySelectContacts() {
|
||||
final boolean selected = !mTargets.isEmpty();
|
||||
applyPill(mSelectContacts, selected);
|
||||
if (selected && mRecipientScroll != null) {
|
||||
mRecipientScroll.centerChild(mSelectContacts);
|
||||
}
|
||||
}
|
||||
|
||||
private void openTargetPicker() {
|
||||
HomeAutomationTargetPickerSheet.show(getSupportFragmentManager(),
|
||||
new ArrayList<>(mTargets));
|
||||
}
|
||||
|
||||
private void bindTargets() {
|
||||
if (mTargetChips == null) {
|
||||
return;
|
||||
}
|
||||
mTargetChips.removeAllViews();
|
||||
final boolean empty = mTargets.isEmpty();
|
||||
if (mTargetChipHost != null) {
|
||||
mTargetChipHost.setVisibility(empty ? View.GONE : View.VISIBLE);
|
||||
} else if (mTargetChipScroll != null) {
|
||||
mTargetChipScroll.setVisibility(empty ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
applySelectContacts();
|
||||
if (empty) {
|
||||
return;
|
||||
}
|
||||
final LayoutInflater inflater = LayoutInflater.from(this);
|
||||
for (final HomeAutomationTarget target : mTargets) {
|
||||
final View chip = inflater.inflate(R.layout.home_automation_target_chip, mTargetChips,
|
||||
false);
|
||||
final ContactIconView avatar = chip.findViewById(R.id.home_compose_chip_avatar);
|
||||
if (!TextUtils.isEmpty(target.iconUri)) {
|
||||
avatar.setImageResourceUri(Uri.parse(target.iconUri), target.contactId,
|
||||
target.lookupKey, target.destination);
|
||||
}
|
||||
avatar.setImageClickHandlerDisabled(true);
|
||||
final TextView name = chip.findViewById(R.id.home_compose_chip_name);
|
||||
name.setText(target.displayName());
|
||||
final View remove = chip.findViewById(R.id.home_automation_target_chip_remove);
|
||||
if (remove != null) {
|
||||
remove.setOnClickListener(v -> {
|
||||
mTargets.remove(target);
|
||||
bindTargets();
|
||||
});
|
||||
}
|
||||
final LinearLayout.LayoutParams params =
|
||||
(LinearLayout.LayoutParams) chip.getLayoutParams();
|
||||
params.setMarginEnd(getResources().getDimensionPixelSize(R.dimen.looply_space_xs));
|
||||
mTargetChips.addView(chip, params);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyTriggerRow(final View row, final boolean selected, final boolean tintIcon) {
|
||||
if (row == null) {
|
||||
return;
|
||||
}
|
||||
row.setBackgroundResource(selected
|
||||
? R.drawable.home_bg_automation_option_selected
|
||||
: R.drawable.home_bg_automation_option);
|
||||
final ImageView icon = row.findViewById(R.id.home_automation_trigger_icon);
|
||||
if (icon != null && tintIcon) {
|
||||
if (selected) {
|
||||
icon.setBackgroundResource(R.drawable.home_bg_automation_icon_on);
|
||||
icon.setColorFilter(ContextCompat.getColor(this, android.R.color.white));
|
||||
} else {
|
||||
icon.setBackground(null);
|
||||
icon.setColorFilter(ContextCompat.getColor(this, R.color.home_text_primary));
|
||||
}
|
||||
}
|
||||
applyCheck(row.findViewById(R.id.home_automation_trigger_check), selected);
|
||||
}
|
||||
|
||||
private void applyTriggerTile(final View tile, final boolean selected) {
|
||||
if (tile == null) {
|
||||
return;
|
||||
}
|
||||
tile.setBackgroundResource(selected
|
||||
? R.drawable.home_bg_automation_option_selected
|
||||
: R.drawable.home_bg_automation_option);
|
||||
}
|
||||
|
||||
private void applyPill(final TextView pill, final boolean selected) {
|
||||
if (pill == null) {
|
||||
return;
|
||||
}
|
||||
pill.setBackgroundResource(selected
|
||||
? R.drawable.home_bg_automation_pill_selected
|
||||
: R.drawable.home_bg_automation_pill);
|
||||
pill.setTextColor(ContextCompat.getColor(this,
|
||||
selected ? android.R.color.white : R.color.home_text_primary));
|
||||
}
|
||||
|
||||
private void applyCheck(final ImageView check, final boolean selected) {
|
||||
if (check == null) {
|
||||
return;
|
||||
}
|
||||
if (selected) {
|
||||
check.setBackgroundResource(R.drawable.home_bg_selection_ring_checked);
|
||||
check.setImageResource(R.drawable.ic_home_check);
|
||||
check.setColorFilter(ContextCompat.getColor(this, android.R.color.white));
|
||||
check.setPadding(4, 4, 4, 4);
|
||||
} else {
|
||||
check.setBackgroundResource(R.drawable.home_bg_selection_ring);
|
||||
check.setImageDrawable(null);
|
||||
check.setColorFilter(null);
|
||||
check.setPadding(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void promptRestoreDraft() {
|
||||
mRestorePromptOpen = true;
|
||||
final HomeModal.Handle handle = HomeModal.builder(this)
|
||||
.icon(R.drawable.ic_home_nav_automate)
|
||||
.title(R.string.home_automation_draft_title)
|
||||
.message(R.string.home_automation_draft_body)
|
||||
.positive(R.string.home_automation_draft_resume, this::applyStoredDraft)
|
||||
.negative(R.string.home_automation_draft_start_new, () ->
|
||||
HomeAutomationDraftStore.clear(this))
|
||||
.show();
|
||||
handle.dialog.setOnDismissListener(dialog -> mRestorePromptOpen = false);
|
||||
}
|
||||
|
||||
private void applyStoredDraft() {
|
||||
final HomeAutomationDraftStore.Draft draft = HomeAutomationDraftStore.load(this);
|
||||
if (draft == null) {
|
||||
return;
|
||||
}
|
||||
applyDraft(draft.trigger, draft.recipient, draft.targets);
|
||||
}
|
||||
|
||||
private void restoreState(final Bundle savedInstanceState) {
|
||||
final ArrayList<HomeAutomationTarget> targets =
|
||||
savedInstanceState.getParcelableArrayList(STATE_TARGETS);
|
||||
applyDraft(savedInstanceState.getInt(STATE_TRIGGER, 0),
|
||||
savedInstanceState.getInt(STATE_RECIPIENT, 0), targets);
|
||||
}
|
||||
|
||||
private void applyDraft(final int trigger, final int recipient,
|
||||
final ArrayList<HomeAutomationTarget> targets) {
|
||||
mTrigger = trigger;
|
||||
mRecipient = recipient;
|
||||
mTargets.clear();
|
||||
if (targets != null) {
|
||||
mTargets.addAll(targets);
|
||||
}
|
||||
applyTrigger();
|
||||
applyRecipient();
|
||||
bindTargets();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(final Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putInt(STATE_TRIGGER, mTrigger);
|
||||
outState.putInt(STATE_RECIPIENT, mRecipient);
|
||||
outState.putParcelableArrayList(STATE_TARGETS, new ArrayList<>(mTargets));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
if (mRestorePromptOpen) {
|
||||
return;
|
||||
}
|
||||
HomeAutomationDraftStore.save(this, mTrigger, mRecipient, mTargets);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2026 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.messaging.ui.home;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/** Local draft for an automation rule that was left unfinished. */
|
||||
public final class HomeAutomationDraftStore {
|
||||
|
||||
private static final String PREFS_NAME = "home_automation_draft";
|
||||
private static final String KEY_JSON = "draft_json";
|
||||
|
||||
public static final class Draft {
|
||||
public final int trigger;
|
||||
public final int recipient;
|
||||
public final ArrayList<HomeAutomationTarget> targets;
|
||||
|
||||
public Draft(final int trigger, final int recipient,
|
||||
final ArrayList<HomeAutomationTarget> targets) {
|
||||
this.trigger = trigger;
|
||||
this.recipient = recipient;
|
||||
this.targets = targets == null ? new ArrayList<>() : targets;
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return trigger != 0 || recipient != 0 || !targets.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
private HomeAutomationDraftStore() {
|
||||
}
|
||||
|
||||
public static boolean hasDraft(final Context context) {
|
||||
final Draft draft = load(context);
|
||||
return draft != null && draft.isDirty();
|
||||
}
|
||||
|
||||
public static Draft load(final Context context) {
|
||||
final String json = prefs(context).getString(KEY_JSON, null);
|
||||
if (TextUtils.isEmpty(json)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
final JSONObject object = new JSONObject(json);
|
||||
final ArrayList<HomeAutomationTarget> targets = new ArrayList<>();
|
||||
final JSONArray array = object.optJSONArray("targets");
|
||||
if (array != null) {
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
final JSONObject item = array.optJSONObject(i);
|
||||
if (item == null) {
|
||||
continue;
|
||||
}
|
||||
targets.add(new HomeAutomationTarget(
|
||||
item.optString("name", null),
|
||||
item.optString("destination", null),
|
||||
item.optBoolean("group", false),
|
||||
item.optLong("contactId", -1),
|
||||
emptyToNull(item.optString("lookupKey", null)),
|
||||
emptyToNull(item.optString("iconUri", null))));
|
||||
}
|
||||
}
|
||||
return new Draft(object.optInt("trigger", 0), object.optInt("recipient", 0), targets);
|
||||
} catch (final Exception ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void save(final Context context, final int trigger, final int recipient,
|
||||
final ArrayList<HomeAutomationTarget> targets) {
|
||||
final Draft draft = new Draft(trigger, recipient, targets);
|
||||
if (!draft.isDirty()) {
|
||||
clear(context);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final JSONObject object = new JSONObject();
|
||||
object.put("trigger", trigger);
|
||||
object.put("recipient", recipient);
|
||||
final JSONArray array = new JSONArray();
|
||||
for (final HomeAutomationTarget target : draft.targets) {
|
||||
if (target == null) {
|
||||
continue;
|
||||
}
|
||||
final JSONObject item = new JSONObject();
|
||||
item.put("name", target.name);
|
||||
item.put("destination", target.destination);
|
||||
item.put("group", target.group);
|
||||
item.put("contactId", target.contactId);
|
||||
item.put("lookupKey", target.lookupKey);
|
||||
item.put("iconUri", target.iconUri);
|
||||
array.put(item);
|
||||
}
|
||||
object.put("targets", array);
|
||||
prefs(context).edit().putString(KEY_JSON, object.toString()).apply();
|
||||
} catch (final Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public static void clear(final Context context) {
|
||||
prefs(context).edit().remove(KEY_JSON).apply();
|
||||
}
|
||||
|
||||
private static String emptyToNull(final String value) {
|
||||
return TextUtils.isEmpty(value) ? null : value;
|
||||
}
|
||||
|
||||
private static SharedPreferences prefs(final Context context) {
|
||||
return context.getApplicationContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||
}
|
||||
}
|
||||
@@ -21,13 +21,25 @@ import android.widget.TextView;
|
||||
|
||||
import com.android.messaging.R;
|
||||
|
||||
/** Binds the Automation home preview: modes, sample rules, and local toggles. */
|
||||
/** Binds the Automation home preview and archived-rule list. */
|
||||
public final class HomeAutomationHome {
|
||||
|
||||
private HomeAutomationHome() {
|
||||
}
|
||||
|
||||
public static void bind(final View root) {
|
||||
bind(root, false);
|
||||
}
|
||||
|
||||
public static void bindArchive(final View root) {
|
||||
bind(root, true);
|
||||
}
|
||||
|
||||
public static void applyVisibility(final View root) {
|
||||
applyVisibility(root, false);
|
||||
}
|
||||
|
||||
private static void bind(final View root, final boolean archiveList) {
|
||||
if (root == null) {
|
||||
return;
|
||||
}
|
||||
@@ -44,10 +56,12 @@ public final class HomeAutomationHome {
|
||||
bindChip(root, R.id.home_automation_rule_weekly_chip2,
|
||||
R.string.home_automation_rule_weekly_chip2);
|
||||
|
||||
comingSoon(root, R.id.home_automation_modes_more);
|
||||
comingSoon(root, R.id.home_automation_mode_call);
|
||||
comingSoon(root, R.id.home_automation_mode_cards);
|
||||
comingSoon(root, R.id.home_automation_rules_sort);
|
||||
if (!archiveList) {
|
||||
comingSoon(root, R.id.home_automation_modes_more);
|
||||
comingSoon(root, R.id.home_automation_mode_call);
|
||||
comingSoon(root, R.id.home_automation_mode_cards);
|
||||
comingSoon(root, R.id.home_automation_rules_sort);
|
||||
}
|
||||
comingSoon(root, R.id.home_automation_rule_missed);
|
||||
comingSoon(root, R.id.home_automation_rule_thanks);
|
||||
comingSoon(root, R.id.home_automation_rule_weekly);
|
||||
@@ -55,6 +69,80 @@ public final class HomeAutomationHome {
|
||||
bindSwitch(root, R.id.home_automation_rule_missed_switch, true);
|
||||
bindSwitch(root, R.id.home_automation_rule_thanks_switch, true);
|
||||
bindSwitch(root, R.id.home_automation_rule_weekly_switch, true);
|
||||
|
||||
bindSwipe(root, R.id.home_automation_rule_missed, archiveList);
|
||||
bindSwipe(root, R.id.home_automation_rule_thanks, archiveList);
|
||||
bindSwipe(root, R.id.home_automation_rule_weekly, archiveList);
|
||||
applyVisibility(root, archiveList);
|
||||
}
|
||||
|
||||
private static void bindSwipe(final View root, final int id, final boolean archiveList) {
|
||||
final View card = root.findViewById(id);
|
||||
if (card == null || card.getParent() instanceof HomeSwipeCard) {
|
||||
return;
|
||||
}
|
||||
final String key = HomeAutomationRuleStore.keyForView(id);
|
||||
HomeSwipeCard.install(card, new HomeSwipeCard.Listener() {
|
||||
@Override
|
||||
public void onArchive(final HomeSwipeCard swipe) {
|
||||
if (archiveList) {
|
||||
HomeAutomationRuleStore.unarchive(root.getContext(), key);
|
||||
HomeToast.show(root.getContext(), R.string.home_automation_rule_restored);
|
||||
} else {
|
||||
HomeAutomationRuleStore.archive(root.getContext(), key);
|
||||
HomeToast.show(root.getContext(), R.string.home_automation_rule_archived);
|
||||
}
|
||||
applyVisibility(root, archiveList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDelete(final HomeSwipeCard swipe) {
|
||||
HomeAutomationRuleStore.delete(root.getContext(), key);
|
||||
HomeToast.show(root.getContext(), R.string.home_automation_rule_deleted);
|
||||
applyVisibility(root, archiveList);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void applyVisibility(final View root, final boolean archiveList) {
|
||||
if (root == null) {
|
||||
return;
|
||||
}
|
||||
int visible = 0;
|
||||
for (final int id : HomeAutomationRuleStore.RULE_VIEW_IDS) {
|
||||
visible += applyRuleVisibility(root, id, archiveList) ? 1 : 0;
|
||||
}
|
||||
final TextView count = root.findViewById(R.id.home_automation_rules_count);
|
||||
if (count != null) {
|
||||
count.setText(String.valueOf(visible));
|
||||
count.setVisibility(visible > 0 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
final View empty = root.findViewById(R.id.home_archived_rules_empty);
|
||||
if (empty != null) {
|
||||
empty.setVisibility(archiveList && visible == 0 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean applyRuleVisibility(final View root, final int id,
|
||||
final boolean archiveList) {
|
||||
View card = root.findViewById(id);
|
||||
if (card == null) {
|
||||
return false;
|
||||
}
|
||||
if (card.getParent() instanceof HomeSwipeCard) {
|
||||
card = (View) card.getParent();
|
||||
}
|
||||
final String key = HomeAutomationRuleStore.keyForView(id);
|
||||
final boolean deleted = HomeAutomationRuleStore.isDeleted(root.getContext(), key);
|
||||
final boolean archived = HomeAutomationRuleStore.isArchived(root.getContext(), key);
|
||||
final boolean show = archiveList ? (!deleted && archived) : (!deleted && !archived);
|
||||
if (card instanceof HomeSwipeCard) {
|
||||
if (show) {
|
||||
((HomeSwipeCard) card).setSwipeTranslationX(0f);
|
||||
}
|
||||
}
|
||||
card.setVisibility(show ? View.VISIBLE : View.GONE);
|
||||
return show;
|
||||
}
|
||||
|
||||
private static void bindChip(final View root, final int chipId, final int labelId) {
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2026 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.messaging.ui.home;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import com.android.messaging.R;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/** Local archive/delete flags for the demo automation rules. */
|
||||
public final class HomeAutomationRuleStore {
|
||||
public static final String MISSED = "missed";
|
||||
public static final String THANKS = "thanks";
|
||||
public static final String WEEKLY = "weekly";
|
||||
|
||||
static final int[] RULE_VIEW_IDS = {
|
||||
R.id.home_automation_rule_missed,
|
||||
R.id.home_automation_rule_thanks,
|
||||
R.id.home_automation_rule_weekly
|
||||
};
|
||||
|
||||
private static final String PREFS = "home_automation_rules";
|
||||
private static final String KEY_ARCHIVED = "archived";
|
||||
private static final String KEY_DELETED = "deleted";
|
||||
|
||||
private HomeAutomationRuleStore() {
|
||||
}
|
||||
|
||||
static String keyForView(final int viewId) {
|
||||
if (viewId == R.id.home_automation_rule_missed) {
|
||||
return MISSED;
|
||||
}
|
||||
if (viewId == R.id.home_automation_rule_thanks) {
|
||||
return THANKS;
|
||||
}
|
||||
if (viewId == R.id.home_automation_rule_weekly) {
|
||||
return WEEKLY;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isArchived(final Context context, final String key) {
|
||||
return set(context, KEY_ARCHIVED).contains(key);
|
||||
}
|
||||
|
||||
public static boolean isDeleted(final Context context, final String key) {
|
||||
return set(context, KEY_DELETED).contains(key);
|
||||
}
|
||||
|
||||
public static void archive(final Context context, final String key) {
|
||||
add(context, KEY_ARCHIVED, key);
|
||||
remove(context, KEY_DELETED, key);
|
||||
}
|
||||
|
||||
public static void unarchive(final Context context, final String key) {
|
||||
remove(context, KEY_ARCHIVED, key);
|
||||
}
|
||||
|
||||
public static void delete(final Context context, final String key) {
|
||||
add(context, KEY_DELETED, key);
|
||||
remove(context, KEY_ARCHIVED, key);
|
||||
}
|
||||
|
||||
public static boolean hasArchived(final Context context) {
|
||||
if (context == null) {
|
||||
return false;
|
||||
}
|
||||
for (final String key : set(context, KEY_ARCHIVED)) {
|
||||
if (!isDeleted(context, key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Set<String> set(final Context context, final String key) {
|
||||
return new HashSet<>(prefs(context).getStringSet(key, Collections.emptySet()));
|
||||
}
|
||||
|
||||
private static void add(final Context context, final String key, final String value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
final Set<String> next = set(context, key);
|
||||
if (next.add(value)) {
|
||||
prefs(context).edit().putStringSet(key, next).apply();
|
||||
}
|
||||
}
|
||||
|
||||
private static void remove(final Context context, final String key, final String value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
final Set<String> next = set(context, key);
|
||||
if (next.remove(value)) {
|
||||
prefs(context).edit().putStringSet(key, next).apply();
|
||||
}
|
||||
}
|
||||
|
||||
private static SharedPreferences prefs(final Context context) {
|
||||
return context.getApplicationContext().getSharedPreferences(PREFS, Context.MODE_PRIVATE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2026 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.messaging.ui.home;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
/** A contact or group chosen as an automation include/exclude target. */
|
||||
public final class HomeAutomationTarget implements Parcelable {
|
||||
|
||||
public final String name;
|
||||
public final String destination;
|
||||
public final boolean group;
|
||||
public final long contactId;
|
||||
public final String lookupKey;
|
||||
public final String iconUri;
|
||||
|
||||
public HomeAutomationTarget(final String name, final String destination, final boolean group,
|
||||
final long contactId, final String lookupKey, final String iconUri) {
|
||||
this.name = name;
|
||||
this.destination = destination;
|
||||
this.group = group;
|
||||
this.contactId = contactId;
|
||||
this.lookupKey = lookupKey;
|
||||
this.iconUri = iconUri;
|
||||
}
|
||||
|
||||
protected HomeAutomationTarget(final Parcel in) {
|
||||
name = in.readString();
|
||||
destination = in.readString();
|
||||
group = in.readInt() == 1;
|
||||
contactId = in.readLong();
|
||||
lookupKey = in.readString();
|
||||
iconUri = in.readString();
|
||||
}
|
||||
|
||||
public String key() {
|
||||
return (group ? "g:" : "c:") + (destination == null ? "" : destination);
|
||||
}
|
||||
|
||||
public String displayName() {
|
||||
return TextUtils.isEmpty(name) ? destination : name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(final Parcel dest, final int flags) {
|
||||
dest.writeString(name);
|
||||
dest.writeString(destination);
|
||||
dest.writeInt(group ? 1 : 0);
|
||||
dest.writeLong(contactId);
|
||||
dest.writeString(lookupKey);
|
||||
dest.writeString(iconUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Creator<HomeAutomationTarget> CREATOR =
|
||||
new Creator<HomeAutomationTarget>() {
|
||||
@Override
|
||||
public HomeAutomationTarget createFromParcel(final Parcel in) {
|
||||
return new HomeAutomationTarget(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HomeAutomationTarget[] newArray(final int size) {
|
||||
return new HomeAutomationTarget[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
* Copyright (C) 2026 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.messaging.ui.home;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.CursorLoader;
|
||||
import androidx.loader.content.Loader;
|
||||
|
||||
import com.android.ex.chips.RecipientEntry;
|
||||
import com.android.messaging.R;
|
||||
import com.android.messaging.datamodel.data.ParticipantData;
|
||||
import com.android.messaging.ui.ContactIconView;
|
||||
import com.android.messaging.util.AvatarUriUtil;
|
||||
import com.android.messaging.util.ContactRecipientEntryUtils;
|
||||
import com.android.messaging.util.ContactUtil;
|
||||
import com.android.messaging.util.PhoneUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
/** In-window sheet to pick contacts and contact groups as automation targets. */
|
||||
public class HomeAutomationTargetPickerSheet extends Fragment
|
||||
implements HomeContactsFragment.GroupSelectionHost, LoaderManager.LoaderCallbacks<Cursor> {
|
||||
|
||||
public static final String REQUEST_KEY = "home_automation_target_picker";
|
||||
public static final String EXTRA_TARGETS = "home_automation_targets";
|
||||
|
||||
private static final String TAG = "home_automation_target_picker";
|
||||
private static final int GROUPS_LOADER = 1;
|
||||
|
||||
private View mDim;
|
||||
private View mPanel;
|
||||
private boolean mClosing;
|
||||
private TextView mContactsTab;
|
||||
private TextView mGroupsTab;
|
||||
private View mContactsHost;
|
||||
private ListView mGroupsList;
|
||||
private HomeEmptyState mGroupsEmpty;
|
||||
private final LinkedHashMap<String, HomeAutomationTarget> mSelectedGroups =
|
||||
new LinkedHashMap<>();
|
||||
private final ArrayList<HomeContactGroups.Item> mGroups = new ArrayList<>();
|
||||
private final GroupAdapter mGroupAdapter = new GroupAdapter();
|
||||
private boolean mShowGroups;
|
||||
private boolean mContactsSeeded;
|
||||
|
||||
public static void show(@NonNull final FragmentManager fragmentManager,
|
||||
@Nullable final ArrayList<HomeAutomationTarget> incoming) {
|
||||
final HomeAutomationTargetPickerSheet sheet = new HomeAutomationTargetPickerSheet();
|
||||
final Bundle args = new Bundle();
|
||||
args.putParcelableArrayList(EXTRA_TARGETS, incoming);
|
||||
if (fragmentManager.findFragmentByTag(TAG) != null) {
|
||||
return;
|
||||
}
|
||||
sheet.setArguments(args);
|
||||
fragmentManager.beginTransaction()
|
||||
.replace(R.id.home_automation_picker_host, sheet, TAG)
|
||||
.commit();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull final LayoutInflater inflater,
|
||||
@Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.home_automation_target_picker_sheet, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
mDim = view.findViewById(R.id.home_automation_picker_dim);
|
||||
mPanel = view.findViewById(R.id.home_automation_picker_panel);
|
||||
if (mDim != null) {
|
||||
mDim.setOnClickListener(v -> dismissSheet());
|
||||
}
|
||||
view.findViewById(R.id.home_automation_picker_close).setOnClickListener(v -> dismissSheet());
|
||||
view.findViewById(R.id.home_automation_picker_done).setOnClickListener(v -> finishWithResult());
|
||||
final View host = requireActivity().findViewById(R.id.home_automation_picker_host);
|
||||
if (host != null) {
|
||||
host.setVisibility(View.VISIBLE);
|
||||
}
|
||||
requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(),
|
||||
new OnBackPressedCallback(true) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
dismissSheet();
|
||||
}
|
||||
});
|
||||
if (savedInstanceState == null) {
|
||||
view.post(() -> HomeUiMotion.gallerySheetOpen(mDim, mPanel));
|
||||
}
|
||||
|
||||
mContactsTab = view.findViewById(R.id.home_automation_picker_contacts);
|
||||
mGroupsTab = view.findViewById(R.id.home_automation_picker_groups);
|
||||
mContactsHost = view.findViewById(R.id.home_automation_picker_contacts_host);
|
||||
mGroupsList = view.findViewById(R.id.home_automation_picker_groups_list);
|
||||
mGroupsEmpty = view.findViewById(R.id.home_automation_picker_groups_empty);
|
||||
mGroupsList.setAdapter(mGroupAdapter);
|
||||
if (mGroupsEmpty != null) {
|
||||
mGroupsEmpty.setContent(R.drawable.ic_home_automation_person,
|
||||
R.string.home_automation_no_groups_title,
|
||||
R.string.home_automation_no_groups_body);
|
||||
}
|
||||
|
||||
HomeContactGroups.ensureDemo(requireContext());
|
||||
seedIncoming(getArguments() == null ? null
|
||||
: getArguments().getParcelableArrayList(EXTRA_TARGETS));
|
||||
mContactsTab.setOnClickListener(v -> showGroups(false));
|
||||
mGroupsTab.setOnClickListener(v -> showGroups(true));
|
||||
showGroups(false);
|
||||
|
||||
prepareContactsFragment();
|
||||
if (ContactUtil.hasReadContactsPermission()) {
|
||||
LoaderManager.getInstance(this).initLoader(GROUPS_LOADER, null, this);
|
||||
}
|
||||
}
|
||||
|
||||
private void dismissSheet() {
|
||||
if (mClosing || !isAdded()) {
|
||||
return;
|
||||
}
|
||||
mClosing = true;
|
||||
HomeUiMotion.gallerySheetClose(mDim, mPanel, () -> {
|
||||
if (!isAdded()) {
|
||||
return;
|
||||
}
|
||||
final View host = requireActivity().findViewById(R.id.home_automation_picker_host);
|
||||
getParentFragmentManager().beginTransaction().remove(this).commitAllowingStateLoss();
|
||||
if (host != null) {
|
||||
host.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void prepareContactsFragment() {
|
||||
HomeContactsFragment fragment = getContactsFragment();
|
||||
if (fragment == null) {
|
||||
fragment = new HomeContactsFragment();
|
||||
getChildFragmentManager().beginTransaction()
|
||||
.replace(R.id.home_automation_picker_contacts_host, fragment)
|
||||
.commitNow();
|
||||
}
|
||||
fragment.setGroupMode(true);
|
||||
if (!mContactsSeeded) {
|
||||
fragment.seedSelection(contactSeeds());
|
||||
mContactsSeeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayList<String> contactSeeds() {
|
||||
final ArrayList<HomeAutomationTarget> incoming = getArguments() == null
|
||||
? null : getArguments().getParcelableArrayList(EXTRA_TARGETS);
|
||||
final ArrayList<String> seeds = new ArrayList<>();
|
||||
if (incoming == null) {
|
||||
return seeds;
|
||||
}
|
||||
for (final HomeAutomationTarget target : incoming) {
|
||||
if (target != null && !target.group && target.destination != null) {
|
||||
seeds.add(target.destination);
|
||||
}
|
||||
}
|
||||
return seeds;
|
||||
}
|
||||
|
||||
private void seedIncoming(final ArrayList<HomeAutomationTarget> incoming) {
|
||||
mSelectedGroups.clear();
|
||||
if (incoming == null) {
|
||||
return;
|
||||
}
|
||||
for (final HomeAutomationTarget target : incoming) {
|
||||
if (target != null && target.group && target.destination != null) {
|
||||
mSelectedGroups.put(target.destination, target);
|
||||
}
|
||||
}
|
||||
mGroupAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private HomeContactsFragment getContactsFragment() {
|
||||
return (HomeContactsFragment) getChildFragmentManager()
|
||||
.findFragmentById(R.id.home_automation_picker_contacts_host);
|
||||
}
|
||||
|
||||
private void showGroups(final boolean groups) {
|
||||
mShowGroups = groups;
|
||||
applyPill(mContactsTab, !groups);
|
||||
applyPill(mGroupsTab, groups);
|
||||
if (mContactsHost != null) {
|
||||
mContactsHost.setVisibility(groups ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
updateGroupsVisibility();
|
||||
}
|
||||
|
||||
private void updateGroupsVisibility() {
|
||||
final boolean empty = mGroups.isEmpty();
|
||||
if (mGroupsList != null) {
|
||||
mGroupsList.setVisibility(mShowGroups && !empty ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
if (mGroupsEmpty != null) {
|
||||
mGroupsEmpty.setVisibility(mShowGroups && empty ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyPill(final TextView pill, final boolean selected) {
|
||||
if (pill == null) {
|
||||
return;
|
||||
}
|
||||
pill.setBackgroundResource(selected
|
||||
? R.drawable.home_bg_automation_pill_selected
|
||||
: R.drawable.home_bg_automation_pill);
|
||||
pill.setTextColor(ContextCompat.getColor(requireContext(),
|
||||
selected ? android.R.color.white : R.color.home_text_primary));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGroupSelectionChanged(final List<RecipientEntry> selected) {
|
||||
// Selection is read from the fragment when Done is pressed.
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(final int id, @Nullable final Bundle args) {
|
||||
return new CursorLoader(requireContext(), HomeContactGroups.SUMMARY_URI,
|
||||
HomeContactGroups.PROJECTION, HomeContactGroups.SELECTION, null,
|
||||
HomeContactGroups.SORT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(@NonNull final Loader<Cursor> loader, final Cursor data) {
|
||||
mGroups.clear();
|
||||
if (data != null && data.moveToFirst()) {
|
||||
do {
|
||||
final HomeContactGroups.Item item = HomeContactGroups.fromCursor(data);
|
||||
if (!item.title.isEmpty()) {
|
||||
mGroups.add(item);
|
||||
}
|
||||
} while (data.moveToNext());
|
||||
}
|
||||
mGroupAdapter.notifyDataSetChanged();
|
||||
updateGroupsVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(@NonNull final Loader<Cursor> loader) {
|
||||
mGroups.clear();
|
||||
mGroupAdapter.notifyDataSetChanged();
|
||||
updateGroupsVisibility();
|
||||
}
|
||||
|
||||
private void finishWithResult() {
|
||||
final LinkedHashMap<String, HomeAutomationTarget> targets = new LinkedHashMap<>();
|
||||
final HomeContactsFragment fragment = getContactsFragment();
|
||||
if (fragment != null) {
|
||||
for (final RecipientEntry entry : fragment.getSelectedEntries()) {
|
||||
final HomeAutomationTarget target = fromEntry(entry);
|
||||
targets.put(target.key(), target);
|
||||
}
|
||||
}
|
||||
for (final HomeAutomationTarget group : mSelectedGroups.values()) {
|
||||
targets.put(group.key(), group);
|
||||
}
|
||||
final Bundle result = new Bundle();
|
||||
result.putParcelableArrayList(EXTRA_TARGETS, new ArrayList<>(targets.values()));
|
||||
getParentFragmentManager().setFragmentResult(REQUEST_KEY, result);
|
||||
dismissSheet();
|
||||
}
|
||||
|
||||
private static HomeAutomationTarget fromEntry(final RecipientEntry entry) {
|
||||
final ParticipantData participant = ParticipantData.getFromRecipientEntry(entry);
|
||||
final Uri icon = AvatarUriUtil.createAvatarUri(participant);
|
||||
return new HomeAutomationTarget(
|
||||
ContactRecipientEntryUtils.getDisplayNameForContactList(entry),
|
||||
PhoneUtils.getDefault().getCanonicalBySystemLocale(entry.getDestination()),
|
||||
false,
|
||||
participant.getContactId(),
|
||||
participant.getLookupKey(),
|
||||
icon == null ? null : icon.toString());
|
||||
}
|
||||
|
||||
private static HomeAutomationTarget fromGroup(final HomeContactGroups.Item item) {
|
||||
final Uri icon = item.avatarUri();
|
||||
return new HomeAutomationTarget(item.title, item.destination(), true, 0, null,
|
||||
icon == null ? null : icon.toString());
|
||||
}
|
||||
|
||||
private void applyCheck(final View check, final boolean selected) {
|
||||
if (check instanceof ImageView) {
|
||||
HomeAvatarOverlay.apply((ImageView) check, true, selected);
|
||||
}
|
||||
}
|
||||
|
||||
private final class GroupAdapter extends BaseAdapter {
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mGroups.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HomeContactGroups.Item getItem(final int position) {
|
||||
return mGroups.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(final int position) {
|
||||
return getItem(position).id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final int position, final View convertView, final ViewGroup parent) {
|
||||
final View row = convertView != null ? convertView
|
||||
: LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.home_automation_target_row, parent, false);
|
||||
final HomeContactGroups.Item item = getItem(position);
|
||||
final ContactIconView avatar = row.findViewById(R.id.home_automation_target_avatar);
|
||||
final TextView name = row.findViewById(R.id.home_automation_target_name);
|
||||
final TextView meta = row.findViewById(R.id.home_automation_target_meta);
|
||||
final View check = row.findViewById(R.id.home_automation_target_check);
|
||||
avatar.setImageResourceUri(item.avatarUri());
|
||||
avatar.setImageClickHandlerDisabled(true);
|
||||
name.setText(item.title);
|
||||
if (meta != null) {
|
||||
if (item.memberCount > 0) {
|
||||
meta.setVisibility(View.VISIBLE);
|
||||
meta.setText(getResources().getQuantityString(
|
||||
R.plurals.home_automation_group_member_count, item.memberCount,
|
||||
item.memberCount));
|
||||
} else {
|
||||
meta.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
final boolean selected = mSelectedGroups.containsKey(item.destination());
|
||||
applyCheck(check, selected);
|
||||
row.setOnClickListener(v -> {
|
||||
final String id = item.destination();
|
||||
if (mSelectedGroups.remove(id) == null) {
|
||||
mSelectedGroups.put(id, fromGroup(item));
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
});
|
||||
return row;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2026 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License and the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.messaging.ui.home;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.android.messaging.R;
|
||||
|
||||
/** Avatar wash + check used while a people/message list is in edit/selection mode. */
|
||||
public final class HomeAvatarOverlay {
|
||||
private HomeAvatarOverlay() {
|
||||
}
|
||||
|
||||
public static void apply(final ImageView overlay, final boolean selectionMode,
|
||||
final boolean selected) {
|
||||
if (overlay == null) {
|
||||
return;
|
||||
}
|
||||
if (!selectionMode) {
|
||||
overlay.animate().cancel();
|
||||
overlay.setBackground(null);
|
||||
overlay.setImageDrawable(null);
|
||||
overlay.setPadding(0, 0, 0, 0);
|
||||
overlay.setVisibility(View.GONE);
|
||||
overlay.setAlpha(1f);
|
||||
overlay.setScaleX(1f);
|
||||
overlay.setScaleY(1f);
|
||||
return;
|
||||
}
|
||||
overlay.setBackgroundResource(selected
|
||||
? R.drawable.home_bg_avatar_selected_wash
|
||||
: R.drawable.home_bg_avatar_edit);
|
||||
if (selected) {
|
||||
overlay.setScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||
applyHeaderCheckRatio(overlay);
|
||||
overlay.setImageResource(R.drawable.ic_home_check_stroke);
|
||||
} else {
|
||||
overlay.setPadding(0, 0, 0, 0);
|
||||
overlay.setImageDrawable(null);
|
||||
}
|
||||
overlay.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches {@code ic_checkmark_circle_primary}: the tick is 16.3/42 of the circle. The
|
||||
* stroke asset has extra viewport padding, so inset is reduced to keep that same visible size.
|
||||
*/
|
||||
private static void applyHeaderCheckRatio(final ImageView overlay) {
|
||||
int side = overlay.getWidth();
|
||||
if (side <= 0 && overlay.getLayoutParams() != null) {
|
||||
side = overlay.getLayoutParams().width;
|
||||
}
|
||||
if (side <= 0) {
|
||||
side = overlay.getResources().getDimensionPixelSize(R.dimen.home_list_avatar_size);
|
||||
}
|
||||
final int inset = Math.round(side * ((42f - 16.3f) / 42f / 2f) * (16f / 24f));
|
||||
overlay.setPadding(inset, inset, inset, inset);
|
||||
}
|
||||
}
|
||||
@@ -69,17 +69,8 @@ public final class HomeCategoryScroller extends HorizontalScrollView {
|
||||
return;
|
||||
}
|
||||
final View host = (View) parent;
|
||||
final View start = host.findViewById(R.id.home_category_fade_start);
|
||||
final View end = host.findViewById(R.id.home_category_fade_end);
|
||||
final boolean overflow = canScrollContent();
|
||||
final int startVis = overflow && getScrollX() > 0 ? VISIBLE : GONE;
|
||||
final int endVis = overflow ? VISIBLE : GONE;
|
||||
if (start != null && start.getVisibility() != startVis) {
|
||||
start.setVisibility(startVis);
|
||||
}
|
||||
if (end != null && end.getVisibility() != endVis) {
|
||||
end.setVisibility(endVis);
|
||||
}
|
||||
HomeScrollEdgeFades.apply(this, host.findViewById(R.id.home_category_fade_start),
|
||||
host.findViewById(R.id.home_category_fade_end));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -254,6 +254,7 @@ public final class HomeComposeAttachPanel {
|
||||
int imeBottom;
|
||||
final int dockBaseBottomPadding;
|
||||
final int originalStatusBarColor;
|
||||
final int originalNavigationBarColor;
|
||||
boolean expanded;
|
||||
boolean closing;
|
||||
boolean pendingComposeKeyboard;
|
||||
@@ -300,6 +301,7 @@ public final class HomeComposeAttachPanel {
|
||||
allItems.addAll(items);
|
||||
albums.addAll(collectAlbums(items));
|
||||
originalStatusBarColor = activity.getWindow().getStatusBarColor();
|
||||
originalNavigationBarColor = activity.getWindow().getNavigationBarColor();
|
||||
}
|
||||
|
||||
void open() {
|
||||
@@ -320,8 +322,10 @@ public final class HomeComposeAttachPanel {
|
||||
final int screenHeight = activity.getResources().getDisplayMetrics().heightPixels;
|
||||
if (scrim != null) {
|
||||
scrim.setAlpha(0f);
|
||||
scrim.setOnClickListener(null);
|
||||
scrim.setClickable(false);
|
||||
scrim.setOnClickListener(v -> dismiss());
|
||||
}
|
||||
if (activity.getWindow() != null) {
|
||||
activity.getWindow().setNavigationBarColor(Color.TRANSPARENT);
|
||||
}
|
||||
sheet.setTranslationY(screenHeight);
|
||||
grid.setLayoutManager(new GridLayoutManager(activity, SPAN_COUNT));
|
||||
@@ -424,11 +428,8 @@ public final class HomeComposeAttachPanel {
|
||||
final int height = sheet.getHeight() > 0
|
||||
? sheet.getHeight() : screenHeight;
|
||||
sheet.setTranslationY(height);
|
||||
if (scrim != null) {
|
||||
scrim.setAlpha(0f);
|
||||
}
|
||||
applyDockInsets();
|
||||
HomeUiMotion.gallerySheetOpen(null, sheet, peekY,
|
||||
HomeUiMotion.gallerySheetOpen(scrim, sheet, peekY,
|
||||
Session.this::notifyChatExtent);
|
||||
return false;
|
||||
}
|
||||
@@ -488,7 +489,7 @@ public final class HomeComposeAttachPanel {
|
||||
host.onDismiss();
|
||||
final boolean openKeyboard = pendingComposeKeyboard;
|
||||
pendingComposeKeyboard = false;
|
||||
HomeUiMotion.gallerySheetClose(null, sheet, () -> {
|
||||
HomeUiMotion.gallerySheetClose(scrim, sheet, () -> {
|
||||
host.onAttachSheetExtentChanged(0);
|
||||
if (overlay.getParent() instanceof ViewGroup) {
|
||||
((ViewGroup) overlay.getParent()).removeView(overlay);
|
||||
@@ -591,6 +592,7 @@ public final class HomeComposeAttachPanel {
|
||||
void applyWindowInsets(final WindowInsetsCompat insets) {
|
||||
statusBarTop = insets.getInsets(WindowInsetsCompat.Type.statusBars()).top;
|
||||
navigationBarBottom = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;
|
||||
applyBottomMargin(sheet, sheetBottomInset());
|
||||
applyImeLift(Math.max(
|
||||
insets.getInsets(WindowInsetsCompat.Type.ime()).bottom,
|
||||
inferredImeHeight()));
|
||||
@@ -613,13 +615,18 @@ public final class HomeComposeAttachPanel {
|
||||
return;
|
||||
}
|
||||
imeBottom = ime;
|
||||
applyBottomMargin(sheet, imeBottom);
|
||||
applyBottomMargin(sheet, sheetBottomInset());
|
||||
applyBottomMargin(dock, imeBottom);
|
||||
applyDockInsets();
|
||||
applyExpandHeaderInsets(expanded);
|
||||
}
|
||||
|
||||
int sheetBottomInset() {
|
||||
return imeBottom > 0 ? imeBottom : navigationBarBottom;
|
||||
}
|
||||
|
||||
void applyDockInsets() {
|
||||
applyBottomMargin(sheet, sheetBottomInset());
|
||||
if (dock != null) {
|
||||
final int bottom = dockBaseBottomPadding
|
||||
+ (imeBottom > 0 ? 0 : navigationBarBottom);
|
||||
@@ -703,6 +710,7 @@ public final class HomeComposeAttachPanel {
|
||||
void restoreStatusBar() {
|
||||
if (activity.getWindow() != null) {
|
||||
activity.getWindow().setStatusBarColor(originalStatusBarColor);
|
||||
activity.getWindow().setNavigationBarColor(originalNavigationBarColor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1338,10 +1346,17 @@ public final class HomeComposeAttachPanel {
|
||||
|
||||
private static void updateScrimForDrag(final View scrim, final float translation,
|
||||
final float peekY, final int height) {
|
||||
if (scrim == null) {
|
||||
if (scrim == null || height <= 0) {
|
||||
return;
|
||||
}
|
||||
scrim.setAlpha(0f);
|
||||
final float peek = peekY > 0f ? peekY : height * 0.45f;
|
||||
final float alpha;
|
||||
if (translation <= peek) {
|
||||
alpha = 1f;
|
||||
} else {
|
||||
alpha = 1f - (translation - peek) / Math.max(height - peek, 1f);
|
||||
}
|
||||
scrim.setAlpha(clamp(alpha, 0f, 1f));
|
||||
}
|
||||
|
||||
private static float clamp(final float value, final float min, final float max) {
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (C) 2026 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.messaging.ui.home;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.ContactsContract;
|
||||
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
||||
import android.provider.ContactsContract.Groups;
|
||||
import android.provider.ContactsContract.RawContacts;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.messaging.util.AvatarUriUtil;
|
||||
import com.android.messaging.util.ContactUtil;
|
||||
import com.android.messaging.util.OsUtil;
|
||||
|
||||
/** Android Contacts groups (not chat threads) for automation include/exclude. */
|
||||
final class HomeContactGroups {
|
||||
static final String[] PROJECTION = {
|
||||
Groups._ID,
|
||||
Groups.TITLE,
|
||||
Groups.SUMMARY_COUNT,
|
||||
Groups.SUMMARY_WITH_PHONES
|
||||
};
|
||||
static final String SELECTION = Groups.DELETED + "=0 AND (" + Groups.AUTO_ADD
|
||||
+ "=0 OR " + Groups.AUTO_ADD + " IS NULL)";
|
||||
static final String SORT = Groups.TITLE + " COLLATE LOCALIZED ASC";
|
||||
static final Uri SUMMARY_URI = Groups.CONTENT_SUMMARY_URI;
|
||||
|
||||
private static final String PREFS = "home_demo";
|
||||
private static final String KEY_SEEDED = "contact_groups_seeded_v1";
|
||||
private static final String DEST_PREFIX = "cg:";
|
||||
|
||||
private HomeContactGroups() {
|
||||
}
|
||||
|
||||
static void ensureDemo(final Context context) {
|
||||
if (context == null || !OsUtil.hasPermission(Manifest.permission.WRITE_CONTACTS)
|
||||
|| !ContactUtil.hasReadContactsPermission()) {
|
||||
return;
|
||||
}
|
||||
final SharedPreferences prefs =
|
||||
context.getSharedPreferences(PREFS, Context.MODE_PRIVATE);
|
||||
if (prefs.getBoolean(KEY_SEEDED, false)) {
|
||||
return;
|
||||
}
|
||||
final ContentResolver resolver = context.getContentResolver();
|
||||
seedGroup(resolver, "Family",
|
||||
"+15551230008", "+15551230003", "+15551230023", "+15551230005");
|
||||
seedGroup(resolver, "Friends",
|
||||
"+15551230006", "+15551230012", "+15551230015", "+15551230018",
|
||||
"+15551230020", "+15551230007");
|
||||
seedGroup(resolver, "Work",
|
||||
"+15551230001", "+15551230002", "+15551230004", "+15551230011",
|
||||
"+15551230016", "+15551230013");
|
||||
seedGroup(resolver, "Clients",
|
||||
"+15551230009", "+15551230010", "+15551230014", "+15551230017",
|
||||
"+15551230021", "+15551230022");
|
||||
prefs.edit().putBoolean(KEY_SEEDED, true).apply();
|
||||
}
|
||||
|
||||
static Item fromCursor(final Cursor cursor) {
|
||||
final long id = cursor.getLong(0);
|
||||
final String title = cursor.getString(1);
|
||||
int count = 0;
|
||||
if (!cursor.isNull(3)) {
|
||||
count = cursor.getInt(3);
|
||||
} else if (!cursor.isNull(2)) {
|
||||
count = cursor.getInt(2);
|
||||
}
|
||||
return new Item(id, title, count);
|
||||
}
|
||||
|
||||
static final class Item {
|
||||
final long id;
|
||||
final String title;
|
||||
final int memberCount;
|
||||
|
||||
Item(final long id, final String title, final int memberCount) {
|
||||
this.id = id;
|
||||
this.title = title == null ? "" : title;
|
||||
this.memberCount = memberCount;
|
||||
}
|
||||
|
||||
String destination() {
|
||||
return DEST_PREFIX + id;
|
||||
}
|
||||
|
||||
Uri avatarUri() {
|
||||
if (TextUtils.isEmpty(title)) {
|
||||
return AvatarUriUtil.createAvatarUri(null, null, destination(), null);
|
||||
}
|
||||
return AvatarUriUtil.createAvatarUri(null, title, destination(), null);
|
||||
}
|
||||
}
|
||||
|
||||
private static void seedGroup(final ContentResolver resolver, final String title,
|
||||
final String... numbers) {
|
||||
if (findGroupId(resolver, title) >= 0) {
|
||||
return;
|
||||
}
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(Groups.TITLE, title);
|
||||
values.put(Groups.GROUP_VISIBLE, 1);
|
||||
bindAccount(resolver, values);
|
||||
final Uri inserted = resolver.insert(Groups.CONTENT_URI, values);
|
||||
if (inserted == null) {
|
||||
return;
|
||||
}
|
||||
final long groupId = android.content.ContentUris.parseId(inserted);
|
||||
if (groupId <= 0 || numbers == null) {
|
||||
return;
|
||||
}
|
||||
for (final String number : numbers) {
|
||||
final long rawId = findRawContactId(resolver, number);
|
||||
if (rawId > 0) {
|
||||
addMembership(resolver, rawId, groupId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static long findGroupId(final ContentResolver resolver, final String title) {
|
||||
try (Cursor cursor = resolver.query(Groups.CONTENT_URI,
|
||||
new String[] { Groups._ID },
|
||||
Groups.DELETED + "=0 AND " + Groups.TITLE + "=?",
|
||||
new String[] { title }, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return cursor.getLong(0);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static void bindAccount(final ContentResolver resolver, final ContentValues values) {
|
||||
try (Cursor cursor = resolver.query(RawContacts.CONTENT_URI,
|
||||
new String[] { RawContacts.ACCOUNT_NAME, RawContacts.ACCOUNT_TYPE },
|
||||
RawContacts.DELETED + "=0", null, RawContacts._ID + " ASC")) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
final String name = cursor.getString(0);
|
||||
final String type = cursor.getString(1);
|
||||
if (!TextUtils.isEmpty(type)) {
|
||||
values.put(Groups.ACCOUNT_NAME, name);
|
||||
values.put(Groups.ACCOUNT_TYPE, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static long findRawContactId(final ContentResolver resolver, final String number) {
|
||||
if (TextUtils.isEmpty(number)) {
|
||||
return -1;
|
||||
}
|
||||
final String digits = digitsOnly(number);
|
||||
try (Cursor cursor = resolver.query(Phone.CONTENT_URI,
|
||||
new String[] { Phone.RAW_CONTACT_ID, Phone.NORMALIZED_NUMBER, Phone.NUMBER },
|
||||
null, null, null)) {
|
||||
if (cursor == null) {
|
||||
return -1;
|
||||
}
|
||||
while (cursor.moveToNext()) {
|
||||
final String normalized = cursor.getString(1);
|
||||
final String raw = cursor.getString(2);
|
||||
if (sameNumber(digits, normalized) || sameNumber(digits, raw)) {
|
||||
return cursor.getLong(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static void addMembership(final ContentResolver resolver, final long rawContactId,
|
||||
final long groupId) {
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
|
||||
values.put(ContactsContract.Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE);
|
||||
values.put(GroupMembership.GROUP_ROW_ID, groupId);
|
||||
resolver.insert(ContactsContract.Data.CONTENT_URI, values);
|
||||
}
|
||||
|
||||
private static boolean sameNumber(final String expectedDigits, final String candidate) {
|
||||
if (TextUtils.isEmpty(candidate)) {
|
||||
return false;
|
||||
}
|
||||
return TextUtils.equals(expectedDigits, digitsOnly(candidate));
|
||||
}
|
||||
|
||||
private static String digitsOnly(final String value) {
|
||||
final StringBuilder out = new StringBuilder(value.length());
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
final char c = value.charAt(i);
|
||||
if (c >= '0' && c <= '9') {
|
||||
out.append(c);
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import android.database.Cursor;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.CursorAdapter;
|
||||
import android.widget.SectionIndexer;
|
||||
|
||||
@@ -47,6 +48,7 @@ public class HomeContactListAdapter extends CursorAdapter implements SectionInde
|
||||
final ContactListItemView itemView = (ContactListItemView) view;
|
||||
itemView.bind(cursor, mHost, mNeedAlphabetHeader, alphabetHeader);
|
||||
itemView.setSectionBox(sectionRole(cursor.getPosition()));
|
||||
wrapListRow(itemView);
|
||||
}
|
||||
|
||||
private int sectionRole(final int position) {
|
||||
@@ -78,8 +80,21 @@ public class HomeContactListAdapter extends CursorAdapter implements SectionInde
|
||||
|
||||
@Override
|
||||
public View newView(final Context context, final Cursor cursor, final ViewGroup parent) {
|
||||
return LayoutInflater.from(context).inflate(R.layout.home_contacts_list_item, parent,
|
||||
false);
|
||||
final View view = LayoutInflater.from(context).inflate(R.layout.home_contacts_list_item,
|
||||
parent, false);
|
||||
wrapListRow(view);
|
||||
return view;
|
||||
}
|
||||
|
||||
private static void wrapListRow(final View view) {
|
||||
ViewGroup.LayoutParams params = view.getLayoutParams();
|
||||
if (params instanceof AbsListView.LayoutParams) {
|
||||
params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
view.setLayoutParams(params);
|
||||
return;
|
||||
}
|
||||
view.setLayoutParams(new AbsListView.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -60,6 +60,7 @@ public class HomeContactsFragment extends Fragment implements ContactPickerDataL
|
||||
private Cursor mAllContactsCursor;
|
||||
private String mFilterText;
|
||||
private boolean mGroupMode;
|
||||
private java.util.Set<String> mPendingSeed;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||
@@ -85,6 +86,10 @@ public class HomeContactsFragment extends Fragment implements ContactPickerDataL
|
||||
mSendToView = view.findViewById(R.id.home_contacts_send_to);
|
||||
mAdapter = new HomeContactListAdapter(requireContext(), null, this);
|
||||
listView.setAdapter(mAdapter);
|
||||
if (getParentFragment() instanceof GroupSelectionHost
|
||||
|| getActivity() instanceof GroupSelectionHost) {
|
||||
mGroupMode = true;
|
||||
}
|
||||
updateResultViews();
|
||||
}
|
||||
|
||||
@@ -103,6 +108,16 @@ public class HomeContactsFragment extends Fragment implements ContactPickerDataL
|
||||
}
|
||||
}
|
||||
|
||||
public List<RecipientEntry> getSelectedEntries() {
|
||||
return new ArrayList<>(mSelected.values());
|
||||
}
|
||||
|
||||
public void seedSelection(final List<String> destinations) {
|
||||
mPendingSeed = destinations == null
|
||||
? null : new java.util.LinkedHashSet<>(destinations);
|
||||
applyPendingSeed();
|
||||
}
|
||||
|
||||
public ArrayList<ParticipantData> getSelectedParticipants() {
|
||||
final ArrayList<ParticipantData> participants = new ArrayList<>(mSelected.size());
|
||||
for (final RecipientEntry entry : mSelected.values()) {
|
||||
@@ -163,6 +178,7 @@ public class HomeContactsFragment extends Fragment implements ContactPickerDataL
|
||||
mAllContactsCursor = data;
|
||||
if (TextUtils.isEmpty(mFilterText)) {
|
||||
mAdapter.changeCursor(data);
|
||||
applyPendingSeed();
|
||||
updateResultViews();
|
||||
}
|
||||
}
|
||||
@@ -172,6 +188,7 @@ public class HomeContactsFragment extends Fragment implements ContactPickerDataL
|
||||
mBinding.ensureBound();
|
||||
// A null cursor means the search was cleared, so fall back to the full list.
|
||||
mAdapter.changeCursor(data != null ? data : mAllContactsCursor);
|
||||
applyPendingSeed();
|
||||
updateResultViews();
|
||||
}
|
||||
|
||||
@@ -204,12 +221,40 @@ public class HomeContactsFragment extends Fragment implements ContactPickerDataL
|
||||
}
|
||||
}
|
||||
|
||||
private void applyPendingSeed() {
|
||||
if (mPendingSeed == null || mPendingSeed.isEmpty() || mAdapter == null) {
|
||||
return;
|
||||
}
|
||||
final Cursor cursor = mAdapter.getCursor();
|
||||
if (cursor == null || cursor.getCount() == 0) {
|
||||
return;
|
||||
}
|
||||
final ContactListItemData item = DataModel.get().createContactListItemData();
|
||||
final int position = cursor.getPosition();
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
item.bind(cursor, null);
|
||||
final RecipientEntry entry = item.getRecipientEntry();
|
||||
final String key = selectionKey(entry);
|
||||
if (mPendingSeed.remove(key)) {
|
||||
mSelected.put(key, entry);
|
||||
}
|
||||
} while (cursor.moveToNext() && !mPendingSeed.isEmpty());
|
||||
}
|
||||
cursor.moveToPosition(position);
|
||||
notifyGroupSelectionChanged();
|
||||
mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private static String selectionKey(final RecipientEntry entry) {
|
||||
return PhoneUtils.getDefault().getCanonicalBySystemLocale(entry.getDestination());
|
||||
}
|
||||
|
||||
private void notifyGroupSelectionChanged() {
|
||||
if (getActivity() instanceof GroupSelectionHost) {
|
||||
if (getParentFragment() instanceof GroupSelectionHost) {
|
||||
((GroupSelectionHost) getParentFragment()).onGroupSelectionChanged(
|
||||
new ArrayList<>(mSelected.values()));
|
||||
} else if (getActivity() instanceof GroupSelectionHost) {
|
||||
((GroupSelectionHost) getActivity()).onGroupSelectionChanged(
|
||||
new ArrayList<>(mSelected.values()));
|
||||
}
|
||||
@@ -229,6 +274,12 @@ public class HomeContactsFragment extends Fragment implements ContactPickerDataL
|
||||
return mGroupMode && mSelected.containsKey(selectionKey(item.getRecipientEntry()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContactSelectionMode() {
|
||||
return mGroupMode || getParentFragment() instanceof GroupSelectionHost
|
||||
|| getActivity() instanceof HomeComposeActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
@RunsOnMainThread
|
||||
public void onGetOrCreateConversationSucceeded(final ActionMonitor monitor, final Object data,
|
||||
@@ -270,7 +321,20 @@ public class HomeContactsFragment extends Fragment implements ContactPickerDataL
|
||||
mSendToView.bind(entry, getString(R.string.home_compose_send_to,
|
||||
ContactRecipientEntryUtils.formatDestination(entry)), null, this, true, false);
|
||||
// The RecipientEntry bind path is meant for dropdowns, which handle clicks themselves.
|
||||
mSendToView.setOnClickListener(v -> startConversation(entry));
|
||||
mSendToView.setOnClickListener(v -> {
|
||||
if (mGroupMode) {
|
||||
final String key = selectionKey(entry);
|
||||
if (mSelected.remove(key) == null) {
|
||||
mSelected.put(key, entry);
|
||||
}
|
||||
notifyGroupSelectionChanged();
|
||||
if (mAdapter != null) {
|
||||
mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
} else {
|
||||
startConversation(entry);
|
||||
}
|
||||
});
|
||||
mSendToView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mSendToView.setVisibility(View.GONE);
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (C) 2026 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License and the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.messaging.ui.home;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.provider.Telephony;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.messaging.Factory;
|
||||
import com.android.messaging.datamodel.BugleDatabaseOperations;
|
||||
import com.android.messaging.datamodel.DataModel;
|
||||
import com.android.messaging.datamodel.DatabaseHelper.ConversationColumns;
|
||||
import com.android.messaging.datamodel.DatabaseWrapper;
|
||||
import com.android.messaging.datamodel.MessagingContentProvider;
|
||||
import com.android.messaging.datamodel.action.Action;
|
||||
import com.android.messaging.datamodel.data.ConversationListItemData;
|
||||
import com.android.messaging.datamodel.data.MessageData;
|
||||
import com.android.messaging.datamodel.data.ParticipantData;
|
||||
import com.android.messaging.sms.MmsUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/** One-shot demo groups for the emulator preview (Weekend hike, Family, Looply launch, Game night). */
|
||||
public final class HomeDemoGroupSeed extends Action {
|
||||
private static final String PREFS = "home_demo";
|
||||
private static final String KEY_SEEDED = "groups_seeded_v2";
|
||||
|
||||
public static void ensure(final Context context) {
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
if (context.getSharedPreferences(PREFS, Context.MODE_PRIVATE).getBoolean(KEY_SEEDED,
|
||||
false)) {
|
||||
return;
|
||||
}
|
||||
new HomeDemoGroupSeed().start();
|
||||
}
|
||||
|
||||
private HomeDemoGroupSeed() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object executeAction() {
|
||||
final Context context = Factory.get().getApplicationContext();
|
||||
final SharedPreferences prefs = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE);
|
||||
if (prefs.getBoolean(KEY_SEEDED, false)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final long now = System.currentTimeMillis();
|
||||
seed(context, "Weekend hike", "Bring extra water.", now,
|
||||
"+15551230006", "+15551230012", "+15551230007");
|
||||
seed(context, "Family", "Dinner this Sunday?", now - 60_000L,
|
||||
"+15551230008", "+15551230005", "+15551230003");
|
||||
seed(context, "Looply launch", "Ship checklist looks good.", now - 120_000L,
|
||||
"+15551230002", "+15551230016", "+15551230011");
|
||||
seed(context, "Game night", "Friday at 8?", now - 180_000L,
|
||||
"+15551230015", "+15551230018", "+15551230020");
|
||||
|
||||
prefs.edit().putBoolean(KEY_SEEDED, true).apply();
|
||||
MessagingContentProvider.notifyConversationListChanged();
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void seed(final Context context, final String name, final String snippet,
|
||||
final long timestamp, final String... numbers) {
|
||||
final ArrayList<ParticipantData> participants = new ArrayList<>();
|
||||
for (final String number : numbers) {
|
||||
participants.add(ParticipantData.getFromRawPhoneBySystemLocale(number));
|
||||
}
|
||||
BugleDatabaseOperations.sanitizeConversationParticipants(participants);
|
||||
final ArrayList<String> recipients =
|
||||
BugleDatabaseOperations.getRecipientsFromConversationParticipants(participants);
|
||||
final long threadId = MmsUtils.getOrCreateThreadId(context, recipients);
|
||||
if (threadId < 0) {
|
||||
return;
|
||||
}
|
||||
final DatabaseWrapper db = DataModel.get().getDatabase();
|
||||
final String conversationId = BugleDatabaseOperations.getOrCreateConversation(
|
||||
db, threadId, false, participants);
|
||||
if (conversationId == null) {
|
||||
return;
|
||||
}
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(ConversationColumns.NAME, name);
|
||||
values.put(ConversationColumns.SNIPPET_TEXT, snippet);
|
||||
values.put(ConversationColumns.SORT_TIMESTAMP, timestamp);
|
||||
values.put(ConversationColumns.LAST_READ_TIMESTAMP, timestamp);
|
||||
BugleDatabaseOperations.updateConversationRowIfExists(db, conversationId, values);
|
||||
insertSeedMessage(context, db, conversationId, threadId, numbers[0], snippet, timestamp);
|
||||
values.clear();
|
||||
values.put(ConversationColumns.NAME, name);
|
||||
BugleDatabaseOperations.updateConversationRowIfExists(db, conversationId, values);
|
||||
}
|
||||
|
||||
private static void insertSeedMessage(final Context context, final DatabaseWrapper db,
|
||||
final String conversationId, final long threadId, final String sender,
|
||||
final String snippet, final long timestamp) {
|
||||
final ContentValues sms = new ContentValues();
|
||||
sms.put(Telephony.Sms.ADDRESS, sender);
|
||||
sms.put(Telephony.Sms.BODY, snippet);
|
||||
sms.put(Telephony.Sms.DATE, timestamp);
|
||||
sms.put(Telephony.Sms.DATE_SENT, timestamp);
|
||||
sms.put(Telephony.Sms.READ, 1);
|
||||
sms.put(Telephony.Sms.SEEN, 1);
|
||||
sms.put(Telephony.Sms.TYPE, Telephony.Sms.MESSAGE_TYPE_INBOX);
|
||||
sms.put(Telephony.Sms.THREAD_ID, threadId);
|
||||
final Uri smsUri = context.getContentResolver().insert(Telephony.Sms.CONTENT_URI, sms);
|
||||
if (smsUri == null) {
|
||||
return;
|
||||
}
|
||||
final ConversationListItemData conversation =
|
||||
ConversationListItemData.getExistingConversation(db, conversationId);
|
||||
final ArrayList<ParticipantData> members =
|
||||
BugleDatabaseOperations.getParticipantsForConversation(db, conversationId);
|
||||
if (conversation == null || members.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final MessageData message = MessageData.createReceivedSmsMessage(
|
||||
smsUri, conversationId, members.get(0).getId(), conversation.getSelfId(),
|
||||
snippet, null, timestamp, timestamp, true, true);
|
||||
db.beginTransaction();
|
||||
try {
|
||||
BugleDatabaseOperations.insertNewMessageInTransaction(db, message);
|
||||
BugleDatabaseOperations.updateConversationMetadataInTransaction(
|
||||
db, conversationId, message.getMessageId(), timestamp, false, false);
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
private HomeDemoGroupSeed(final Parcel in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<HomeDemoGroupSeed> CREATOR =
|
||||
new Parcelable.Creator<>() {
|
||||
@Override
|
||||
public HomeDemoGroupSeed createFromParcel(final Parcel in) {
|
||||
return new HomeDemoGroupSeed(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HomeDemoGroupSeed[] newArray(final int size) {
|
||||
return new HomeDemoGroupSeed[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull final Parcel parcel, final int flags) {
|
||||
writeActionToParcel(parcel, flags);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2026 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.messaging.ui.home;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.HorizontalScrollView;
|
||||
|
||||
/** Horizontal scroller that shows sibling start/end fades except at the first and last offsets. */
|
||||
public final class HomeFadeScrollView extends HorizontalScrollView {
|
||||
|
||||
public HomeFadeScrollView(final Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public HomeFadeScrollView(final Context context, final AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public HomeFadeScrollView(final Context context, final AttributeSet attrs,
|
||||
final int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setHorizontalScrollBarEnabled(false);
|
||||
setHorizontalFadingEdgeEnabled(false);
|
||||
setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);
|
||||
}
|
||||
|
||||
public void centerChild(final View child) {
|
||||
if (child == null) {
|
||||
return;
|
||||
}
|
||||
post(() -> {
|
||||
if (getWidth() == 0 || child.getWidth() == 0) {
|
||||
return;
|
||||
}
|
||||
final int childCenter = offsetToScrollContent(child) + child.getWidth() / 2;
|
||||
final int target = childCenter - getWidth() / 2;
|
||||
final int max = HomeScrollEdgeFades.maxScrollX(this);
|
||||
smoothScrollTo(Math.max(0, Math.min(target, max)), 0);
|
||||
});
|
||||
}
|
||||
|
||||
private int offsetToScrollContent(final View child) {
|
||||
int offset = child.getLeft();
|
||||
View parent = child.getParent() instanceof View ? (View) child.getParent() : null;
|
||||
final View content = getChildCount() == 0 ? null : getChildAt(0);
|
||||
while (parent != null && parent != this && parent != content) {
|
||||
offset += parent.getLeft();
|
||||
parent = parent.getParent() instanceof View ? (View) parent.getParent() : null;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(final boolean changed, final int l, final int t, final int r,
|
||||
final int b) {
|
||||
super.onLayout(changed, l, t, r, b);
|
||||
HomeScrollEdgeFades.applyFromParent(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onScrollChanged(final int l, final int t, final int oldl, final int oldt) {
|
||||
super.onScrollChanged(l, t, oldl, oldt);
|
||||
HomeScrollEdgeFades.applyFromParent(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2026 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.messaging.ui.home;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.HorizontalScrollView;
|
||||
|
||||
/** Left/right edge fades while scrolling; hidden at the absolute start and end. */
|
||||
final class HomeScrollEdgeFades {
|
||||
private static final String TAG_START = "home_fade_start";
|
||||
private static final String TAG_END = "home_fade_end";
|
||||
|
||||
private HomeScrollEdgeFades() {
|
||||
}
|
||||
|
||||
static void applyFromParent(final HorizontalScrollView scroll) {
|
||||
if (scroll == null || !(scroll.getParent() instanceof View)) {
|
||||
return;
|
||||
}
|
||||
final View host = (View) scroll.getParent();
|
||||
apply(scroll, host.findViewWithTag(TAG_START), host.findViewWithTag(TAG_END));
|
||||
}
|
||||
|
||||
static void apply(final HorizontalScrollView scroll, final View start, final View end) {
|
||||
if (scroll == null) {
|
||||
return;
|
||||
}
|
||||
final int max = maxScrollX(scroll);
|
||||
final boolean overflow = max > 0;
|
||||
final int x = scroll.getScrollX();
|
||||
setVisible(start, overflow && x > 0);
|
||||
setVisible(end, overflow && x < max);
|
||||
}
|
||||
|
||||
static int maxScrollX(final HorizontalScrollView scroll) {
|
||||
if (scroll.getChildCount() == 0) {
|
||||
return 0;
|
||||
}
|
||||
final View child = scroll.getChildAt(0);
|
||||
return Math.max(0, child.getWidth()
|
||||
- (scroll.getWidth() - scroll.getPaddingLeft() - scroll.getPaddingRight()));
|
||||
}
|
||||
|
||||
private static void setVisible(final View fade, final boolean visible) {
|
||||
if (fade == null) {
|
||||
return;
|
||||
}
|
||||
final int vis = visible ? View.VISIBLE : View.GONE;
|
||||
if (fade.getVisibility() != vis) {
|
||||
fade.setVisibility(vis);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -402,9 +402,7 @@ public class HomeSpamFragment extends Fragment implements BlockedParticipantsDat
|
||||
private final TextView mName;
|
||||
private final TextView mDetails;
|
||||
private final View mUnblock;
|
||||
private final View mIndicator;
|
||||
private final View mRing;
|
||||
private final ImageView mCheck;
|
||||
private final ImageView mAvatarCheck;
|
||||
private ParticipantListItemData mData;
|
||||
|
||||
SpamHolder(final View itemView) {
|
||||
@@ -413,9 +411,7 @@ public class HomeSpamFragment extends Fragment implements BlockedParticipantsDat
|
||||
mName = itemView.findViewById(R.id.home_spam_name);
|
||||
mDetails = itemView.findViewById(R.id.home_spam_details);
|
||||
mUnblock = itemView.findViewById(R.id.home_spam_unblock);
|
||||
mIndicator = itemView.findViewById(R.id.home_spam_selection_indicator);
|
||||
mRing = itemView.findViewById(R.id.home_spam_selection_ring);
|
||||
mCheck = itemView.findViewById(R.id.home_spam_selection_check);
|
||||
mAvatarCheck = itemView.findViewById(R.id.home_spam_avatar_check);
|
||||
itemView.setOnClickListener(v -> onRowClicked(mData));
|
||||
mUnblock.setOnClickListener(v -> confirmUnblock(mData));
|
||||
}
|
||||
@@ -434,18 +430,7 @@ public class HomeSpamFragment extends Fragment implements BlockedParticipantsDat
|
||||
data.getLookupKey(), data.getNormalizedDestination());
|
||||
mAvatar.setClickable(!mSelecting);
|
||||
mUnblock.setVisibility(mSelecting ? View.GONE : View.VISIBLE);
|
||||
if (mIndicator != null) {
|
||||
mIndicator.setVisibility(mSelecting ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
final boolean selected = mSelecting && isSelected(data);
|
||||
if (mRing != null) {
|
||||
mRing.setBackgroundResource(selected
|
||||
? R.drawable.home_bg_selection_ring_checked
|
||||
: R.drawable.home_bg_selection_ring);
|
||||
}
|
||||
if (mCheck != null) {
|
||||
mCheck.setVisibility(selected ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
HomeAvatarOverlay.apply(mAvatarCheck, mSelecting, mSelecting && isSelected(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* Copyright (C) 2026 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.messaging.ui.home;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.messaging.R;
|
||||
import com.android.messaging.util.UiUtils;
|
||||
|
||||
/** Home-style swipe actions (archive / delete) without the notification mute button. */
|
||||
public final class HomeSwipeCard extends FrameLayout {
|
||||
|
||||
public interface Listener {
|
||||
void onArchive(HomeSwipeCard card);
|
||||
void onDelete(HomeSwipeCard card);
|
||||
}
|
||||
|
||||
private static HomeSwipeCard sOpenCard;
|
||||
|
||||
private View mBackground;
|
||||
private View mArchive;
|
||||
private View mDelete;
|
||||
private View mContent;
|
||||
private Listener mListener;
|
||||
private float mTranslation;
|
||||
private float mDownX;
|
||||
private float mDownY;
|
||||
private float mStartTranslation;
|
||||
private boolean mDragging;
|
||||
private boolean mDidSwipe;
|
||||
private final int mTouchSlop;
|
||||
private final int mMinFling;
|
||||
private VelocityTracker mVelocityTracker;
|
||||
|
||||
public HomeSwipeCard(final Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public HomeSwipeCard(final Context context, final AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public HomeSwipeCard(final Context context, final AttributeSet attrs, final int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
|
||||
mMinFling = ViewConfiguration.get(context).getScaledMinimumFlingVelocity();
|
||||
setClipChildren(true);
|
||||
setClipToPadding(true);
|
||||
LayoutInflater.from(context).inflate(R.layout.home_swipe_card_actions, this, true);
|
||||
mBackground = findViewById(R.id.home_swipe_background);
|
||||
mArchive = findViewById(R.id.home_swipe_archive);
|
||||
mDelete = findViewById(R.id.home_swipe_delete);
|
||||
if (mDelete != null) {
|
||||
mDelete.setOnClickListener(v -> finishDelete());
|
||||
}
|
||||
}
|
||||
|
||||
public static HomeSwipeCard install(final View content, final Listener listener) {
|
||||
if (content == null || !(content.getParent() instanceof ViewGroup)) {
|
||||
return null;
|
||||
}
|
||||
final ViewGroup parent = (ViewGroup) content.getParent();
|
||||
final int index = parent.indexOfChild(content);
|
||||
final ViewGroup.LayoutParams lp = content.getLayoutParams();
|
||||
parent.removeView(content);
|
||||
final HomeSwipeCard card = new HomeSwipeCard(content.getContext());
|
||||
card.mContent = content;
|
||||
card.mListener = listener;
|
||||
content.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
|
||||
LayoutParams.WRAP_CONTENT));
|
||||
card.addView(content);
|
||||
parent.addView(card, index, lp);
|
||||
return card;
|
||||
}
|
||||
|
||||
public float getSwipeTranslationX() {
|
||||
return mTranslation;
|
||||
}
|
||||
|
||||
public void setSwipeTranslationX(final float translationX) {
|
||||
mTranslation = translationX;
|
||||
if (mContent != null) {
|
||||
mContent.setTranslationX(translationX);
|
||||
}
|
||||
if (mBackground == null) {
|
||||
return;
|
||||
}
|
||||
if (translationX == 0f) {
|
||||
mBackground.setVisibility(GONE);
|
||||
if (mArchive != null) {
|
||||
mArchive.setVisibility(GONE);
|
||||
}
|
||||
if (mDelete != null) {
|
||||
mDelete.setVisibility(GONE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
mBackground.setVisibility(VISIBLE);
|
||||
if (translationX > 0f) {
|
||||
if (mArchive != null) {
|
||||
mArchive.setVisibility(VISIBLE);
|
||||
}
|
||||
if (mDelete != null) {
|
||||
mDelete.setVisibility(GONE);
|
||||
}
|
||||
} else {
|
||||
if (mArchive != null) {
|
||||
mArchive.setVisibility(GONE);
|
||||
}
|
||||
if (mDelete != null) {
|
||||
mDelete.setVisibility(VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(final MotionEvent ev) {
|
||||
switch (ev.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mDownX = ev.getX();
|
||||
mDownY = ev.getY();
|
||||
mStartTranslation = mTranslation;
|
||||
mDragging = false;
|
||||
mDidSwipe = false;
|
||||
if (isTouchOnDelete(ev)) {
|
||||
return false;
|
||||
}
|
||||
obtainTracker().addMovement(ev);
|
||||
if (sOpenCard != null && sOpenCard != this) {
|
||||
sOpenCard.animateRestore();
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (isHorizontalDrag(ev)) {
|
||||
mDragging = true;
|
||||
mDidSwipe = true;
|
||||
disallowParent(true);
|
||||
closeOthers();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return mDragging;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(final MotionEvent ev) {
|
||||
obtainTracker().addMovement(ev);
|
||||
switch (ev.getActionMasked()) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (mDragging || isHorizontalDrag(ev)) {
|
||||
mDragging = true;
|
||||
mDidSwipe = true;
|
||||
disallowParent(true);
|
||||
setSwipeTranslationX(clamp(ev.getX() - mDownX + mStartTranslation));
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
if (mDragging) {
|
||||
settle(ev.getActionMasked() == MotionEvent.ACTION_CANCEL);
|
||||
} else if (mTranslation != 0f && !isTouchOnDelete(ev)) {
|
||||
animateRestore();
|
||||
}
|
||||
mDragging = false;
|
||||
disallowParent(false);
|
||||
recycleTracker();
|
||||
return mDidSwipe;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return mDragging || super.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
private boolean isOpen() {
|
||||
return mTranslation <= -revealWidth() * 0.85f;
|
||||
}
|
||||
|
||||
private float revealWidth() {
|
||||
final int button = getResources().getDimensionPixelSize(
|
||||
R.dimen.home_swipe_action_size);
|
||||
return button + getResources().getDimensionPixelSize(R.dimen.looply_space_lg);
|
||||
}
|
||||
|
||||
private float clamp(final float translationX) {
|
||||
if (translationX < 0f) {
|
||||
return Math.max(translationX, -revealWidth() * 1.2f);
|
||||
}
|
||||
return translationX;
|
||||
}
|
||||
|
||||
private boolean isHorizontalDrag(final MotionEvent ev) {
|
||||
final float dx = Math.abs(ev.getX() - mDownX);
|
||||
final float dy = Math.abs(ev.getY() - mDownY);
|
||||
return dx > mTouchSlop && dx > dy;
|
||||
}
|
||||
|
||||
private boolean isTouchOnDelete(final MotionEvent ev) {
|
||||
if (mDelete == null || mDelete.getVisibility() != VISIBLE || !isOpen()) {
|
||||
return false;
|
||||
}
|
||||
final int[] parentLoc = new int[2];
|
||||
getLocationOnScreen(parentLoc);
|
||||
final int[] deleteLoc = new int[2];
|
||||
mDelete.getLocationOnScreen(deleteLoc);
|
||||
final float x = parentLoc[0] + ev.getX();
|
||||
final float y = parentLoc[1] + ev.getY();
|
||||
return x >= deleteLoc[0] && x <= deleteLoc[0] + mDelete.getWidth()
|
||||
&& y >= deleteLoc[1] && y <= deleteLoc[1] + mDelete.getHeight();
|
||||
}
|
||||
|
||||
private void settle(final boolean cancel) {
|
||||
mVelocityTracker.computeCurrentVelocity(1000);
|
||||
final float vx = mVelocityTracker.getXVelocity();
|
||||
final boolean fast = Math.abs(vx) > mMinFling && Math.abs(vx) > Math.abs(
|
||||
mVelocityTracker.getYVelocity());
|
||||
if (!cancel && mTranslation > 0f
|
||||
&& (mTranslation > getWidth() * 0.4f || (fast && vx > 0f))) {
|
||||
finishArchive();
|
||||
return;
|
||||
}
|
||||
if (!cancel && mTranslation < 0f
|
||||
&& Math.abs(mTranslation) > revealWidth() * 0.45f) {
|
||||
animateReveal();
|
||||
return;
|
||||
}
|
||||
animateRestore();
|
||||
}
|
||||
|
||||
private void animateReveal() {
|
||||
sOpenCard = this;
|
||||
animateTo(-revealWidth(), null);
|
||||
}
|
||||
|
||||
private void animateRestore() {
|
||||
if (sOpenCard == this) {
|
||||
sOpenCard = null;
|
||||
}
|
||||
animateTo(0f, null);
|
||||
}
|
||||
|
||||
private void finishArchive() {
|
||||
if (sOpenCard == this) {
|
||||
sOpenCard = null;
|
||||
}
|
||||
animateTo(getWidth(), () -> {
|
||||
setVisibility(GONE);
|
||||
if (mListener != null) {
|
||||
mListener.onArchive(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void finishDelete() {
|
||||
if (sOpenCard == this) {
|
||||
sOpenCard = null;
|
||||
}
|
||||
animateTo(-getWidth(), () -> {
|
||||
setVisibility(GONE);
|
||||
if (mListener != null) {
|
||||
mListener.onDelete(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void animateTo(final float target, final Runnable end) {
|
||||
final ObjectAnimator animator = ObjectAnimator.ofFloat(this, "swipeTranslationX",
|
||||
mTranslation, target);
|
||||
animator.setDuration(getResources().getInteger(R.integer.swipe_duration_ms));
|
||||
animator.setInterpolator(UiUtils.DEFAULT_INTERPOLATOR);
|
||||
animator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(final Animator animation) {
|
||||
if (end != null) {
|
||||
end.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
animator.start();
|
||||
}
|
||||
|
||||
private void closeOthers() {
|
||||
if (sOpenCard != null && sOpenCard != this) {
|
||||
sOpenCard.animateRestore();
|
||||
}
|
||||
}
|
||||
|
||||
private void disallowParent(final boolean disallow) {
|
||||
final ViewParent parent = getParent();
|
||||
if (parent != null) {
|
||||
parent.requestDisallowInterceptTouchEvent(disallow);
|
||||
}
|
||||
}
|
||||
|
||||
private VelocityTracker obtainTracker() {
|
||||
if (mVelocityTracker == null) {
|
||||
mVelocityTracker = VelocityTracker.obtain();
|
||||
}
|
||||
return mVelocityTracker;
|
||||
}
|
||||
|
||||
private void recycleTracker() {
|
||||
if (mVelocityTracker != null) {
|
||||
mVelocityTracker.recycle();
|
||||
mVelocityTracker = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="@dimen/looply_radius_sm" />
|
||||
<solid android:color="@color/home_accent" />
|
||||
</shape>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="#14000000">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="@dimen/looply_radius_xl" />
|
||||
<solid android:color="@color/home_row_bg" />
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="#14000000">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="@dimen/looply_radius_xl" />
|
||||
<solid android:color="@color/home_row_bg" />
|
||||
<stroke
|
||||
android:width="2dp"
|
||||
android:color="@color/home_accent" />
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="#14000000">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="@dimen/looply_radius_pill" />
|
||||
<solid android:color="@color/home_row_bg" />
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/home_accent_soft">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="@dimen/looply_radius_pill" />
|
||||
<solid android:color="@color/home_accent" />
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="#14000000">
|
||||
<item>
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="@color/home_row_bg" />
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="@dimen/looply_radius_pill" />
|
||||
<solid android:color="@color/home_accent_soft" />
|
||||
</shape>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="#14000000">
|
||||
<item android:id="@android:id/mask">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#FFFFFFFF" />
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="@color/home_avatar_edit_wash" />
|
||||
</shape>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="@color/home_avatar_selected_wash" />
|
||||
</shape>
|
||||
</item>
|
||||
<item
|
||||
android:drawable="@drawable/ic_home_check_stroke"
|
||||
android:gravity="center"
|
||||
android:width="14dp"
|
||||
android:height="14dp" />
|
||||
</layer-list>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="@color/home_avatar_selected_wash" />
|
||||
</shape>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/transparent"
|
||||
android:pathData="M21,15a2,2 0,0 1,-2 2H7l-4,4V5a2,2 0,0 1,2 -2h14a2,2 0,0 1,2 2z"
|
||||
android:strokeWidth="1.6"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
</vector>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/transparent"
|
||||
android:pathData="M12,7m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"
|
||||
android:strokeWidth="1.6"
|
||||
android:strokeColor="#000000" />
|
||||
<path
|
||||
android:fillColor="@android:color/transparent"
|
||||
android:pathData="M5.5,19v-1.2c0,-2.4 2.9,-3.8 6.5,-3.8s6.5,1.4 6.5,3.8V19"
|
||||
android:strokeWidth="1.6"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round" />
|
||||
</vector>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/transparent"
|
||||
android:pathData="M22,16.92v3a2,2 0,0 1,-2.18 2,19.79 19.79,0 0,1 -8.63,-3.07 19.5,19.5 0,0 1,-6 -6,19.79 19.79,0 0,1 -3.07,-8.67A2,2 0,0 1,4.11 2h3a2,2 0,0 1,2 1.72,12.84 12.84,0 0,0 0.7,2.81 2,2 0,0 1,-0.45 2.11L8.09,9.91a16,16 0,0 0,6 6l1.27,-1.27a2,2 0,0 1,2.11 -0.45,12.84 12.84,0 0,0 2.81,0.7A2,2 0,0 1,22 16.92z"
|
||||
android:strokeWidth="1.6"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
</vector>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/transparent"
|
||||
android:pathData="M4,12.6111L8.92308,17.5L20,6.5"
|
||||
android:strokeWidth="2"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
</vector>
|
||||
@@ -44,27 +44,28 @@
|
||||
android:visibility="gone" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="@dimen/looply_avatar_size"
|
||||
android:layout_height="@dimen/looply_avatar_size"
|
||||
android:layout_gravity="center_vertical">
|
||||
|
||||
<com.android.messaging.ui.ContactIconView
|
||||
android:id="@+id/contact_icon"
|
||||
android:layout_width="@dimen/looply_avatar_size"
|
||||
android:layout_height="@dimen/looply_avatar_size"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:importantForAccessibility="no"
|
||||
app:contactIconSize="normal"
|
||||
android:clickable="true" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/contact_checkmark"
|
||||
android:layout_width="@dimen/looply_avatar_size"
|
||||
android:layout_height="@dimen/looply_avatar_size"
|
||||
android:src="@drawable/ic_checkmark_circle_blue"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:contentDescription="@null"
|
||||
android:importantForAccessibility="no"
|
||||
android:contentDescription="@null"/>
|
||||
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:src="@drawable/home_bg_avatar_selected"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
||||
@@ -167,10 +167,12 @@
|
||||
android:id="@+id/conversation_checkmark"
|
||||
android:layout_width="@dimen/home_list_avatar_size"
|
||||
android:layout_height="@dimen/home_list_avatar_size"
|
||||
android:src="@drawable/ic_checkmark_circle_blue"
|
||||
android:visibility="gone"
|
||||
android:background="@android:color/transparent"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:importantForAccessibility="no"
|
||||
android:background="@android:color/transparent" />
|
||||
android:src="@drawable/home_bg_avatar_selected"
|
||||
android:visibility="gone" />
|
||||
<ImageView
|
||||
android:id="@+id/conversation_failed_status_icon"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -10,6 +10,43 @@
|
||||
|
||||
<include layout="@layout/home_sub_header" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/home_archived_tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="@dimen/looply_screen_padding"
|
||||
android:paddingTop="@dimen/looply_space_sm"
|
||||
android:paddingEnd="@dimen/looply_screen_padding"
|
||||
android:paddingBottom="@dimen/looply_space_sm"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_archived_tab_chats"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/home_archived_tab_chats"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_archived_tab_rules"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/home_archived_tab_rules"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/home_sub_search_collapse"
|
||||
android:layout_width="match_parent"
|
||||
@@ -36,6 +73,13 @@
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false" />
|
||||
|
||||
<include
|
||||
android:id="@+id/home_archived_rules_host"
|
||||
layout="@layout/home_archived_rules"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone" />
|
||||
|
||||
<include layout="@layout/home_sub_select_bar" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/home_bg">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:fillViewport="true"
|
||||
android:overScrollMode="ifContentScrolls"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="@dimen/looply_screen_padding"
|
||||
android:paddingTop="@dimen/looply_space_sm"
|
||||
android:paddingEnd="@dimen/looply_screen_padding"
|
||||
android:paddingBottom="@dimen/home_empty_dock_padding">
|
||||
|
||||
<include
|
||||
layout="@layout/home_automation_rule_missed"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_sm" />
|
||||
|
||||
<include
|
||||
layout="@layout/home_automation_rule_thanks"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md" />
|
||||
|
||||
<include
|
||||
layout="@layout/home_automation_rule_weekly"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
<include
|
||||
android:id="@+id/home_archived_rules_empty"
|
||||
layout="@layout/home_empty_state"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/home_sheet_scrim"
|
||||
@@ -16,33 +17,399 @@
|
||||
android:background="@drawable/home_bg_sheet_full"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include layout="@layout/home_sub_header" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/home_automation_create_name"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/looply_space_md"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:layout_marginEnd="@dimen/looply_space_md"
|
||||
android:background="@drawable/home_bg_input_field"
|
||||
android:hint="@string/home_automation_create_name_hint"
|
||||
android:inputType="textCapSentences"
|
||||
android:minHeight="@dimen/home_compose_field_height"
|
||||
android:paddingStart="@dimen/looply_space_lg"
|
||||
android:paddingEnd="@dimen/looply_space_lg"
|
||||
android:textColor="@color/home_text_primary"
|
||||
android:textColorHint="@color/home_search_hint"
|
||||
android:textSize="16sp" />
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="@dimen/home_header_height"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingEnd="12dp">
|
||||
|
||||
<TextView
|
||||
<include
|
||||
android:id="@+id/home_sub_header_close"
|
||||
layout="@layout/home_close_button" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_sub_header_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/looply_space_sm"
|
||||
android:layout_weight="1"
|
||||
android:ellipsize="end"
|
||||
android:includeFontPadding="false"
|
||||
android:maxLines="1"
|
||||
android:text="@string/home_automation_create_title"
|
||||
android:textColor="@color/home_text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:overScrollMode="ifContentScrolls"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="@dimen/looply_screen_padding"
|
||||
android:paddingTop="@dimen/looply_space_sm"
|
||||
android:paddingEnd="@dimen/looply_screen_padding"
|
||||
android:paddingBottom="@dimen/home_empty_dock_padding">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/home_bg_automation_banner"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/looply_space_lg">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:background="@drawable/home_bg_automation_icon"
|
||||
android:contentDescription="@null"
|
||||
android:padding="8dp"
|
||||
android:src="@drawable/ic_home_nav_automate"
|
||||
app:tint="@color/home_accent" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/looply_space_md"
|
||||
android:layout_weight="1"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_create_banner"
|
||||
android:textColor="@color/home_text_primary"
|
||||
android:textSize="13sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_xl"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_step_trigger"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_step_trigger_meta"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_sm"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_step_trigger_question"
|
||||
android:textColor="@color/home_text_primary"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<include
|
||||
android:id="@+id/home_automation_trigger_missed"
|
||||
layout="@layout/home_automation_trigger_row"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md" />
|
||||
|
||||
<include
|
||||
android:id="@+id/home_automation_trigger_thanks"
|
||||
layout="@layout/home_automation_trigger_row"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_sm" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_sm"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<include
|
||||
android:id="@+id/home_automation_trigger_schedule"
|
||||
layout="@layout/home_automation_trigger_tile"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<include
|
||||
android:id="@+id/home_automation_trigger_keyword"
|
||||
layout="@layout/home_automation_trigger_tile"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="6dp"
|
||||
android:layout_weight="1" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_xl"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_step_recipients"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_step_recipients_meta"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_sm"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_step_recipients_question"
|
||||
android:textColor="@color/home_text_primary"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:orientation="vertical">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="true">
|
||||
|
||||
<com.android.messaging.ui.home.HomeFadeScrollView
|
||||
android:id="@+id/home_automation_recipient_scroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:overScrollMode="ifContentScrolls"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_automation_recipient_all"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/home_automation_recipient_all"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_automation_recipient_contacts"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/home_automation_recipient_contacts"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_automation_recipient_unknown"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/home_automation_recipient_unknown"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_automation_select_contacts"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/home_automation_select_contacts"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
</com.android.messaging.ui.home.HomeFadeScrollView>
|
||||
|
||||
<View
|
||||
android:layout_width="@dimen/home_category_fade_width"
|
||||
android:layout_height="36dp"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:background="@drawable/home_bg_category_fade_start"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:tag="home_fade_start"
|
||||
android:visibility="gone" />
|
||||
|
||||
<View
|
||||
android:layout_width="@dimen/home_category_fade_width"
|
||||
android:layout_height="36dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:background="@drawable/home_bg_category_fade_end"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:tag="home_fade_end"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/home_automation_target_chip_host"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:clipChildren="true"
|
||||
android:visibility="gone">
|
||||
|
||||
<com.android.messaging.ui.home.HomeFadeScrollView
|
||||
android:id="@+id/home_automation_target_chip_scroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/home_automation_target_chips"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal" />
|
||||
</com.android.messaging.ui.home.HomeFadeScrollView>
|
||||
|
||||
<View
|
||||
android:layout_width="@dimen/home_category_fade_width"
|
||||
android:layout_height="@dimen/home_automation_target_chip_height"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:background="@drawable/home_bg_category_fade_start"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:tag="home_fade_start"
|
||||
android:visibility="gone" />
|
||||
|
||||
<View
|
||||
android:layout_width="@dimen/home_category_fade_width"
|
||||
android:layout_height="@dimen/home_automation_target_chip_height"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:background="@drawable/home_bg_category_fade_end"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:tag="home_fade_end"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginStart="@dimen/looply_space_md"
|
||||
android:layout_marginTop="@dimen/looply_space_lg"
|
||||
android:layout_marginEnd="@dimen/looply_space_md"
|
||||
android:text="@string/home_automation_create_body"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="15sp" />
|
||||
android:layout_marginBottom="@dimen/looply_space_md"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_automation_activate"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/looply_fab_size"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/home_bg_nav_active_primary"
|
||||
android:drawableEnd="@drawable/ic_home_arrow_forward"
|
||||
android:drawablePadding="6dp"
|
||||
android:elevation="5dp"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:outlineAmbientShadowColor="@color/home_pill_shadow_ambient"
|
||||
android:outlineSpotShadowColor="@color/home_pill_shadow_spot"
|
||||
android:paddingStart="@dimen/looply_space_lg"
|
||||
android:paddingEnd="@dimen/looply_space_lg"
|
||||
android:text="@string/home_automation_next"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/home_automation_preview"
|
||||
android:layout_width="@dimen/home_bottom_dock_height"
|
||||
android:layout_height="@dimen/home_bottom_dock_height"
|
||||
android:background="@drawable/home_bg_bottom_dock_fab"
|
||||
android:contentDescription="@string/home_automation_preview"
|
||||
android:elevation="5dp"
|
||||
android:outlineAmbientShadowColor="@color/home_pill_shadow_ambient"
|
||||
android:outlineSpotShadowColor="@color/home_pill_shadow_spot"
|
||||
android:paddingStart="3dp"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingEnd="3dp"
|
||||
android:paddingBottom="@dimen/home_bottom_dock_shadow_inset"
|
||||
android:scaleType="centerInside"
|
||||
android:src="@drawable/ic_home_visibility"
|
||||
app:tint="@color/home_nav_inactive" />
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/home_automation_picker_host"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:elevation="16dp"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/ic_home_nav_calls"
|
||||
android:src="@drawable/ic_home_automation_phone"
|
||||
app:tint="@color/home_text_primary" />
|
||||
|
||||
<Space
|
||||
@@ -233,6 +233,7 @@
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_automation_rules_count"
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="6dp"
|
||||
@@ -262,268 +263,22 @@
|
||||
android:textSize="13sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/home_automation_rule_missed"
|
||||
<include
|
||||
layout="@layout/home_automation_rule_missed"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:background="@drawable/home_bg_automation_card"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/looply_space_lg">
|
||||
android:layout_marginTop="@dimen/looply_space_md" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<include
|
||||
android:id="@+id/home_automation_rule_missed_chip1"
|
||||
layout="@layout/home_automation_chip" />
|
||||
|
||||
<include
|
||||
android:id="@+id/home_automation_rule_missed_chip2"
|
||||
layout="@layout/home_automation_chip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="6dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_automation_rule_missed_switch"
|
||||
android:layout_width="@dimen/home_switch_width"
|
||||
android:layout_height="@dimen/home_switch_height"
|
||||
android:contentDescription="@string/home_automation_on"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/home_switch" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_rule_missed_title"
|
||||
android:textColor="@color/home_text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_sm"
|
||||
android:background="@drawable/home_bg_automation_quote"
|
||||
android:includeFontPadding="false"
|
||||
android:padding="@dimen/looply_space_md"
|
||||
android:text="@string/home_automation_rule_missed_quote"
|
||||
android:textColor="@color/home_text_snippet"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_rule_missed_target"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_rule_missed_sent"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/home_automation_rule_thanks"
|
||||
<include
|
||||
layout="@layout/home_automation_rule_thanks"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:background="@drawable/home_bg_automation_card"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/looply_space_lg">
|
||||
android:layout_marginTop="@dimen/looply_space_md" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<include
|
||||
android:id="@+id/home_automation_rule_thanks_chip1"
|
||||
layout="@layout/home_automation_chip" />
|
||||
|
||||
<include
|
||||
android:id="@+id/home_automation_rule_thanks_chip2"
|
||||
layout="@layout/home_automation_chip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="6dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_automation_rule_thanks_switch"
|
||||
android:layout_width="@dimen/home_switch_width"
|
||||
android:layout_height="@dimen/home_switch_height"
|
||||
android:contentDescription="@string/home_automation_on"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/home_switch" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_rule_thanks_title"
|
||||
android:textColor="@color/home_text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_sm"
|
||||
android:background="@drawable/home_bg_automation_quote"
|
||||
android:includeFontPadding="false"
|
||||
android:padding="@dimen/looply_space_md"
|
||||
android:text="@string/home_automation_rule_thanks_quote"
|
||||
android:textColor="@color/home_text_snippet"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_rule_thanks_target"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_rule_thanks_sent"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/home_automation_rule_weekly"
|
||||
<include
|
||||
layout="@layout/home_automation_rule_weekly"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:background="@drawable/home_bg_automation_card"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/looply_space_lg">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<include
|
||||
android:id="@+id/home_automation_rule_weekly_chip1"
|
||||
layout="@layout/home_automation_chip" />
|
||||
|
||||
<include
|
||||
android:id="@+id/home_automation_rule_weekly_chip2"
|
||||
layout="@layout/home_automation_chip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="6dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_automation_rule_weekly_switch"
|
||||
android:layout_width="@dimen/home_switch_width"
|
||||
android:layout_height="@dimen/home_switch_height"
|
||||
android:contentDescription="@string/home_automation_on"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/home_switch" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_rule_weekly_title"
|
||||
android:textColor="@color/home_text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_sm"
|
||||
android:background="@drawable/home_bg_automation_quote"
|
||||
android:includeFontPadding="false"
|
||||
android:padding="@dimen/looply_space_md"
|
||||
android:text="@string/home_automation_rule_weekly_quote"
|
||||
android:textColor="@color/home_text_snippet"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_rule_weekly_target"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_rule_weekly_sent"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
android:layout_marginTop="@dimen/looply_space_md" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/home_automation_rule_missed"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/home_bg_automation_card"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/looply_space_lg">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<include
|
||||
android:id="@+id/home_automation_rule_missed_chip1"
|
||||
layout="@layout/home_automation_chip" />
|
||||
|
||||
<include
|
||||
android:id="@+id/home_automation_rule_missed_chip2"
|
||||
layout="@layout/home_automation_chip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="6dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_automation_rule_missed_switch"
|
||||
android:layout_width="@dimen/home_switch_width"
|
||||
android:layout_height="@dimen/home_switch_height"
|
||||
android:contentDescription="@string/home_automation_on"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/home_switch" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_rule_missed_title"
|
||||
android:textColor="@color/home_text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_sm"
|
||||
android:background="@drawable/home_bg_automation_quote"
|
||||
android:includeFontPadding="false"
|
||||
android:padding="@dimen/looply_space_md"
|
||||
android:text="@string/home_automation_rule_missed_quote"
|
||||
android:textColor="@color/home_text_snippet"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_rule_missed_target"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_rule_missed_sent"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/home_automation_rule_thanks"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/home_bg_automation_card"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/looply_space_lg">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<include
|
||||
android:id="@+id/home_automation_rule_thanks_chip1"
|
||||
layout="@layout/home_automation_chip" />
|
||||
|
||||
<include
|
||||
android:id="@+id/home_automation_rule_thanks_chip2"
|
||||
layout="@layout/home_automation_chip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="6dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_automation_rule_thanks_switch"
|
||||
android:layout_width="@dimen/home_switch_width"
|
||||
android:layout_height="@dimen/home_switch_height"
|
||||
android:contentDescription="@string/home_automation_on"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/home_switch" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_rule_thanks_title"
|
||||
android:textColor="@color/home_text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_sm"
|
||||
android:background="@drawable/home_bg_automation_quote"
|
||||
android:includeFontPadding="false"
|
||||
android:padding="@dimen/looply_space_md"
|
||||
android:text="@string/home_automation_rule_thanks_quote"
|
||||
android:textColor="@color/home_text_snippet"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_rule_thanks_target"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_rule_thanks_sent"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/home_automation_rule_weekly"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/home_bg_automation_card"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/looply_space_lg">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<include
|
||||
android:id="@+id/home_automation_rule_weekly_chip1"
|
||||
layout="@layout/home_automation_chip" />
|
||||
|
||||
<include
|
||||
android:id="@+id/home_automation_rule_weekly_chip2"
|
||||
layout="@layout/home_automation_chip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="6dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_automation_rule_weekly_switch"
|
||||
android:layout_width="@dimen/home_switch_width"
|
||||
android:layout_height="@dimen/home_switch_height"
|
||||
android:contentDescription="@string/home_automation_on"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/home_switch" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_rule_weekly_title"
|
||||
android:textColor="@color/home_text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_sm"
|
||||
android:background="@drawable/home_bg_automation_quote"
|
||||
android:includeFontPadding="false"
|
||||
android:padding="@dimen/looply_space_md"
|
||||
android:text="@string/home_automation_rule_weekly_quote"
|
||||
android:textColor="@color/home_text_snippet"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_rule_weekly_target"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_rule_weekly_sent"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/home_automation_target_chip_height"
|
||||
android:background="@drawable/home_bg_compose_chip"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingEnd="4dp">
|
||||
|
||||
<com.android.messaging.ui.ContactIconView
|
||||
android:id="@+id/home_compose_chip_avatar"
|
||||
android:layout_width="@dimen/home_automation_target_chip_avatar_size"
|
||||
android:layout_height="@dimen/home_automation_target_chip_avatar_size"
|
||||
android:contentDescription="@null"
|
||||
app:contactIconSize="small" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_compose_chip_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:ellipsize="end"
|
||||
android:includeFontPadding="false"
|
||||
android:maxWidth="88dp"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/home_text_primary"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/home_automation_target_chip_remove"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="2dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:contentDescription="@string/home_automation_target_remove"
|
||||
android:padding="0dp"
|
||||
android:scaleType="fitCenter"
|
||||
app:srcCompat="@drawable/ic_home_close" />
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,140 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/home_automation_picker_root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
|
||||
<View
|
||||
android:id="@+id/home_automation_picker_dim"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/home_sheet_scrim"
|
||||
android:clickable="true"
|
||||
android:focusable="true" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/home_automation_picker_panel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginTop="@dimen/home_header_height"
|
||||
android:background="@drawable/home_bg_bottom_sheet"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="@dimen/looply_space_sm">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="36dp"
|
||||
android:paddingStart="@dimen/looply_screen_padding"
|
||||
android:paddingEnd="@dimen/looply_screen_padding">
|
||||
|
||||
<View
|
||||
android:layout_width="@dimen/home_gallery_handle_width"
|
||||
android:layout_height="@dimen/home_gallery_handle_height"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/home_bg_gallery_handle" />
|
||||
|
||||
<include
|
||||
android:id="@+id/home_automation_picker_close"
|
||||
layout="@layout/home_close_button"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="start|center_vertical" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/home_automation_picker_done"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:background="@android:color/transparent"
|
||||
android:contentDescription="@string/home_automation_pick_done"
|
||||
android:padding="0dp"
|
||||
android:scaleType="fitCenter"
|
||||
app:srcCompat="@drawable/ic_checkmark_circle_primary" />
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_automation_picker_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/looply_screen_padding"
|
||||
android:layout_marginTop="@dimen/looply_space_sm"
|
||||
android:layout_marginEnd="@dimen/looply_screen_padding"
|
||||
android:includeFontPadding="false"
|
||||
android:text="@string/home_automation_pick_targets"
|
||||
android:textColor="@color/home_text_primary"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/looply_screen_padding"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:layout_marginEnd="@dimen/looply_screen_padding"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_automation_picker_contacts"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/home_automation_pick_contacts"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_automation_picker_groups"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/home_automation_pick_groups"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="@dimen/looply_space_sm"
|
||||
android:layout_weight="1">
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/home_automation_picker_contacts_host"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<ListView
|
||||
android:id="@+id/home_automation_picker_groups_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:divider="@null"
|
||||
android:dividerHeight="0dp"
|
||||
android:paddingStart="@dimen/looply_screen_padding"
|
||||
android:paddingEnd="@dimen/looply_screen_padding"
|
||||
android:paddingBottom="16dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<include
|
||||
android:id="@+id/home_automation_picker_groups_empty"
|
||||
layout="@layout/home_empty_state"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/home_bg_automation_row_ripple"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="56dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="@dimen/looply_space_sm"
|
||||
android:paddingEnd="@dimen/looply_space_md">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="@dimen/home_list_avatar_size"
|
||||
android:layout_height="@dimen/home_list_avatar_size">
|
||||
|
||||
<com.android.messaging.ui.ContactIconView
|
||||
android:id="@+id/home_automation_target_avatar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:contentDescription="@null"
|
||||
app:contactIconSize="normal" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_automation_target_check"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:contentDescription="@null"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:src="@drawable/home_bg_avatar_selected"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/looply_space_md"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_automation_target_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:includeFontPadding="false"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/home_text_primary"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_automation_target_meta"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:ellipsize="end"
|
||||
android:includeFontPadding="false"
|
||||
android:maxLines="1"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="13sp"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/home_bg_automation_option"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/looply_space_lg">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_automation_trigger_icon"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:contentDescription="@null"
|
||||
android:padding="9dp"
|
||||
android:scaleType="fitCenter"
|
||||
app:tint="@color/home_text_primary" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/looply_space_md"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_automation_trigger_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:includeFontPadding="false"
|
||||
android:textColor="@color/home_text_primary"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_automation_trigger_badge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:background="@drawable/home_bg_automation_recommended"
|
||||
android:includeFontPadding="false"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="2dp"
|
||||
android:text="@string/home_automation_recommended"
|
||||
android:textColor="@color/home_accent"
|
||||
android:textSize="11sp"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_automation_trigger_body"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:includeFontPadding="false"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="13sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_automation_trigger_check"
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:layout_marginStart="@dimen/looply_space_sm"
|
||||
android:contentDescription="@null"
|
||||
android:scaleType="fitCenter" />
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/home_bg_automation_option"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/looply_space_lg">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_automation_trigger_icon"
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:contentDescription="@null"
|
||||
android:scaleType="fitCenter"
|
||||
app:tint="@color/home_text_primary" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_automation_trigger_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/looply_space_md"
|
||||
android:includeFontPadding="false"
|
||||
android:textColor="@color/home_text_primary"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_automation_trigger_body"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:includeFontPadding="false"
|
||||
android:textColor="@color/home_text_secondary"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
@@ -25,7 +25,7 @@
|
||||
layout="@layout/home_close_button"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="end|center_vertical" />
|
||||
android:layout_gravity="start|center_vertical" />
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
android:id="@+id/home_compose_attach_scrim"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/transparent"
|
||||
android:clickable="false"
|
||||
android:focusable="false" />
|
||||
android:background="@color/home_sheet_scrim"
|
||||
android:clickable="true"
|
||||
android:focusable="true" />
|
||||
|
||||
<include
|
||||
layout="@layout/home_mediapicker_sheet"
|
||||
|
||||
@@ -44,22 +44,24 @@
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_width="@dimen/looply_avatar_size"
|
||||
android:layout_height="@dimen/looply_avatar_size">
|
||||
|
||||
<com.android.messaging.ui.ContactIconView
|
||||
android:id="@+id/contact_icon"
|
||||
android:layout_width="@dimen/looply_avatar_size"
|
||||
android:layout_height="@dimen/looply_avatar_size"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:contentDescription="@null"
|
||||
app:contactIconSize="normal" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/contact_checkmark"
|
||||
android:layout_width="@dimen/looply_avatar_size"
|
||||
android:layout_height="@dimen/looply_avatar_size"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/home_bg_contact_selected"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:src="@drawable/home_bg_avatar_selected"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="12dp">
|
||||
android:paddingStart="12dp">
|
||||
|
||||
<include
|
||||
android:id="@+id/home_modal_close"
|
||||
layout="@layout/home_close_button"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="end" />
|
||||
android:layout_gravity="start" />
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="@dimen/home_selection_indicator_size"
|
||||
android:layout_height="@dimen/home_selection_indicator_size">
|
||||
|
||||
<View
|
||||
android:id="@+id/home_selection_ring"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/home_bg_selection_ring" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_selection_check"
|
||||
android:layout_width="@dimen/home_selection_check_size"
|
||||
android:layout_height="@dimen/home_selection_check_size"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/ic_checkmark_light"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
@@ -14,35 +14,27 @@
|
||||
android:paddingBottom="@dimen/looply_space_md">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/home_spam_selection_indicator"
|
||||
android:layout_width="@dimen/home_selection_indicator_size"
|
||||
android:layout_height="@dimen/home_selection_indicator_size"
|
||||
android:layout_marginEnd="@dimen/looply_space_sm"
|
||||
android:visibility="gone">
|
||||
android:layout_width="@dimen/home_list_avatar_size"
|
||||
android:layout_height="@dimen/home_list_avatar_size">
|
||||
|
||||
<View
|
||||
android:id="@+id/home_spam_selection_ring"
|
||||
<com.android.messaging.ui.ContactIconView
|
||||
android:id="@+id/home_spam_avatar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/home_bg_selection_ring" />
|
||||
android:contentDescription="@null"
|
||||
app:contactIconSize="normal" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/home_spam_selection_check"
|
||||
android:layout_width="@dimen/home_selection_check_size"
|
||||
android:layout_height="@dimen/home_selection_check_size"
|
||||
android:layout_gravity="center"
|
||||
android:id="@+id/home_spam_avatar_check"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/ic_checkmark_light"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:src="@drawable/home_bg_avatar_selected"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
|
||||
<com.android.messaging.ui.ContactIconView
|
||||
android:id="@+id/home_spam_avatar"
|
||||
android:layout_width="@dimen/home_list_avatar_size"
|
||||
android:layout_height="@dimen/home_list_avatar_size"
|
||||
android:contentDescription="@null"
|
||||
app:contactIconSize="normal" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
@@ -20,11 +20,6 @@
|
||||
|
||||
<include layout="@layout/home_back_button" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_sub_header_title"
|
||||
style="@style/Home.SubHeaderTitle"
|
||||
android:layout_marginEnd="@dimen/home_header_title_inset" />
|
||||
|
||||
<!-- Shown instead of the back arrow when the screen is presented as a sheet. -->
|
||||
<include
|
||||
android:id="@+id/home_sub_header_close"
|
||||
@@ -34,6 +29,11 @@
|
||||
android:layout_marginStart="4dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/home_sub_header_title"
|
||||
style="@style/Home.SubHeaderTitle"
|
||||
android:layout_marginEnd="@dimen/home_header_title_inset" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/home_sub_header_overflow"
|
||||
android:layout_width="40dp"
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/home_swipe_background"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/home_bg"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="@dimen/looply_space_lg"
|
||||
android:paddingEnd="@dimen/looply_space_lg"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/home_swipe_archive"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:background="@drawable/home_bg_swipe_circle"
|
||||
android:contentDescription="@string/home_swipe_archive"
|
||||
android:padding="9dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/ic_archive_small_dark"
|
||||
android:tint="@android:color/white"
|
||||
android:visibility="gone" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/home_swipe_delete"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:background="@drawable/home_bg_swipe_circle_delete"
|
||||
android:contentDescription="@string/home_swipe_delete"
|
||||
android:padding="9dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/ic_home_menu_trash"
|
||||
android:tint="@android:color/white"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
@@ -186,9 +186,54 @@
|
||||
<string name="home_empty_gallery_permission_title">사진 접근 허용</string>
|
||||
<string name="home_empty_gallery_permission_body">사진과 동영상을 첨부하려면 접근을 허용하세요.</string>
|
||||
<string name="home_automation_create_content_description">새 자동화</string>
|
||||
<string name="home_automation_create_title">새 자동화</string>
|
||||
<string name="home_automation_create_title">자동화 메세지 작성</string>
|
||||
<string name="home_automation_create_name_hint">자동화 이름</string>
|
||||
<string name="home_automation_create_body">언제 실행하고 무엇을 할지 설정하세요.</string>
|
||||
<string name="home_automation_create_banner">자동 발송 메시지는 대화에서 자동화 배지로 구분됩니다.</string>
|
||||
<string name="home_automation_save">저장</string>
|
||||
<string name="home_automation_draft_title">작성 중인 자동화</string>
|
||||
<string name="home_automation_draft_body">이전에 작성하던 규칙이 있습니다. 이어서 작성할까요?</string>
|
||||
<string name="home_automation_draft_resume">이어서 작성</string>
|
||||
<string name="home_automation_draft_start_new">새로 작성</string>
|
||||
<string name="home_automation_preview">미리보기</string>
|
||||
<string name="home_automation_activate">규칙을 켜고 저장</string>
|
||||
<string name="home_automation_next">다음: 템플릿과 메시지 선택</string>
|
||||
<string name="home_automation_recommended">추천</string>
|
||||
<string name="home_automation_step_trigger">1단계</string>
|
||||
<string name="home_automation_step_trigger_meta">실행 조건</string>
|
||||
<string name="home_automation_step_trigger_question">언제 자동으로 보낼까요?</string>
|
||||
<string name="home_automation_trigger_missed_title">부재중 전화</string>
|
||||
<string name="home_automation_trigger_missed_body">전화를 못 받으면 바로 맞춤 답장을 보냅니다</string>
|
||||
<string name="home_automation_trigger_thanks_title">통화 후 감사 인사</string>
|
||||
<string name="home_automation_trigger_thanks_body">통화가 끝나면 명함이나 안내를 보냅니다</string>
|
||||
<string name="home_automation_trigger_schedule_title">예약 발송</string>
|
||||
<string name="home_automation_trigger_schedule_body">날짜와 시간을 지정</string>
|
||||
<string name="home_automation_trigger_keyword_title">키워드 자동응답</string>
|
||||
<string name="home_automation_trigger_keyword_body">특정 단어가 오면 답장</string>
|
||||
<string name="home_automation_step_recipients">2단계</string>
|
||||
<string name="home_automation_step_recipients_meta">수신 필터</string>
|
||||
<string name="home_automation_step_recipients_question">누구에게 보낼까요?</string>
|
||||
<string name="home_automation_recipient_all">모든 발신자</string>
|
||||
<string name="home_automation_recipient_contacts">저장 연락처만</string>
|
||||
<string name="home_automation_recipient_unknown">미등록 번호만</string>
|
||||
<string name="home_automation_exclude_family">가족·개인 연락처 제외</string>
|
||||
<string name="home_automation_business_tag">고객 / 업무 태그 (122)</string>
|
||||
<string name="home_automation_add_target">+ 대상 추가</string>
|
||||
<string name="home_automation_include">포함</string>
|
||||
<string name="home_automation_exclude">제외</string>
|
||||
<string name="home_automation_add_targets">+ 연락처 또는 그룹 추가</string>
|
||||
<string name="home_automation_select_contacts">연락처 선택</string>
|
||||
<string name="home_automation_target_remove">삭제</string>
|
||||
<string name="home_automation_targets_empty">선택한 연락처나 그룹이 없습니다</string>
|
||||
<string name="home_automation_pick_targets">연락처 또는 그룹 선택</string>
|
||||
<string name="home_automation_pick_contacts">연락처</string>
|
||||
<string name="home_automation_pick_groups">그룹</string>
|
||||
<string name="home_automation_pick_done">완료</string>
|
||||
<string name="home_automation_no_groups_title">연락처 그룹 없음</string>
|
||||
<string name="home_automation_no_groups_body">연락처 앱의 그룹이 여기에 나타납니다. 포함하거나 제외할 수 있습니다.</string>
|
||||
<plurals name="home_automation_group_member_count">
|
||||
<item quantity="other">연락처 %d명</item>
|
||||
</plurals>
|
||||
<string name="home_automation_manage">관리</string>
|
||||
<string name="home_automation_banner">자동 발송 메시지는 대화에서 로봇 배지로 구분됩니다.</string>
|
||||
<string name="home_automation_modes_title">주요 자동화 모드</string>
|
||||
@@ -203,6 +248,9 @@
|
||||
<string name="home_automation_rules_title">실행 중인 자동화 규칙</string>
|
||||
<string name="home_automation_rules_count">3</string>
|
||||
<string name="home_automation_rules_sort">정렬: 최신순</string>
|
||||
<string name="home_automation_rule_archived">규칙을 보관했습니다</string>
|
||||
<string name="home_automation_rule_restored">규칙을 복원했습니다</string>
|
||||
<string name="home_automation_rule_deleted">규칙을 삭제했습니다</string>
|
||||
<string name="home_automation_rule_missed_chip1">통화 자동응답</string>
|
||||
<string name="home_automation_rule_missed_chip2">즉시 발송</string>
|
||||
<string name="home_automation_rule_missed_title">부재중 전화 수신 시 답장</string>
|
||||
@@ -302,6 +350,10 @@
|
||||
<string name="home_popover_recently_deleted">휴지통</string>
|
||||
<string name="home_archived_title">보관함</string>
|
||||
<string name="home_archived_subtitle">보관한 대화는 복원하거나 삭제할 때까지 여기에 있습니다.</string>
|
||||
<string name="home_archived_tab_chats">대화</string>
|
||||
<string name="home_archived_tab_rules">규칙</string>
|
||||
<string name="home_archived_rules_empty_title">보관한 규칙 없음</string>
|
||||
<string name="home_archived_rules_empty_body">보관한 자동화 규칙이 여기에 나타납니다.</string>
|
||||
<string name="home_recently_deleted_title">휴지통</string>
|
||||
<string name="home_recently_deleted_subtitle">삭제한 대화는 30일 동안 여기에 있다가 영구 삭제됩니다.</string>
|
||||
<string name="home_recently_deleted_empty">휴지통이 비어 있습니다</string>
|
||||
|
||||
@@ -66,4 +66,6 @@
|
||||
<color name="home_automation_on_bg">#E3F8EA</color>
|
||||
<color name="home_automation_quote_bg">#F6F4FB</color>
|
||||
<color name="home_automation_chip_dot">@color/home_accent</color>
|
||||
<color name="home_avatar_edit_wash">#33FFFFFF</color>
|
||||
<color name="home_avatar_selected_wash">#80000000</color>
|
||||
</resources>
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<dimen name="looply_space_sm">8dp</dimen>
|
||||
<dimen name="looply_space_md">12dp</dimen>
|
||||
<dimen name="looply_space_lg">16dp</dimen>
|
||||
<dimen name="home_swipe_action_size">40dp</dimen>
|
||||
<dimen name="looply_space_xl">20dp</dimen>
|
||||
<dimen name="looply_space_xxl">24dp</dimen>
|
||||
<dimen name="looply_screen_padding">20dp</dimen>
|
||||
@@ -43,6 +44,8 @@
|
||||
<dimen name="home_sheet_top_inset">0dp</dimen>
|
||||
<dimen name="home_compose_chip_height">34dp</dimen>
|
||||
<dimen name="home_compose_chip_avatar_size">28dp</dimen>
|
||||
<dimen name="home_automation_target_chip_height">26dp</dimen>
|
||||
<dimen name="home_automation_target_chip_avatar_size">18dp</dimen>
|
||||
<dimen name="home_group_avatar_size">64dp</dimen>
|
||||
<dimen name="home_group_avatar_stack_height">96dp</dimen>
|
||||
<dimen name="home_profile_avatar_size">96dp</dimen>
|
||||
|
||||
@@ -187,9 +187,55 @@
|
||||
<string name="home_empty_gallery_permission_title" translatable="false">Allow photo access</string>
|
||||
<string name="home_empty_gallery_permission_body" translatable="false">Allow access to photos and videos to attach them here.</string>
|
||||
<string name="home_automation_create_content_description" translatable="false">New automation</string>
|
||||
<string name="home_automation_create_title" translatable="false">New automation</string>
|
||||
<string name="home_automation_create_title" translatable="false">Write automation message</string>
|
||||
<string name="home_automation_create_name_hint" translatable="false">Automation name</string>
|
||||
<string name="home_automation_create_body" translatable="false">Set when this task should run and what it should do.</string>
|
||||
<string name="home_automation_create_banner" translatable="false">Messages sent automatically are marked in chat with an automation badge.</string>
|
||||
<string name="home_automation_save" translatable="false">Save</string>
|
||||
<string name="home_automation_draft_title" translatable="false">Unfinished automation</string>
|
||||
<string name="home_automation_draft_body" translatable="false">You left a rule in progress. Resume where you left off?</string>
|
||||
<string name="home_automation_draft_resume" translatable="false">Resume</string>
|
||||
<string name="home_automation_draft_start_new" translatable="false">Start new</string>
|
||||
<string name="home_automation_preview" translatable="false">Preview</string>
|
||||
<string name="home_automation_activate" translatable="false">Activate and save rule</string>
|
||||
<string name="home_automation_next" translatable="false">Next: Choose template & message</string>
|
||||
<string name="home_automation_recommended" translatable="false">Recommended</string>
|
||||
<string name="home_automation_step_trigger" translatable="false">Step 1</string>
|
||||
<string name="home_automation_step_trigger_meta" translatable="false">Trigger</string>
|
||||
<string name="home_automation_step_trigger_question" translatable="false">When should a message send automatically?</string>
|
||||
<string name="home_automation_trigger_missed_title" translatable="false">On a missed call</string>
|
||||
<string name="home_automation_trigger_missed_body" translatable="false">Send a custom reply as soon as a call is missed</string>
|
||||
<string name="home_automation_trigger_thanks_title" translatable="false">After-call thank-you</string>
|
||||
<string name="home_automation_trigger_thanks_body" translatable="false">Send a card or follow-up when a call ends</string>
|
||||
<string name="home_automation_trigger_schedule_title" translatable="false">Scheduled broadcast</string>
|
||||
<string name="home_automation_trigger_schedule_body" translatable="false">A specific day and time</string>
|
||||
<string name="home_automation_trigger_keyword_title" translatable="false">Keyword auto-reply</string>
|
||||
<string name="home_automation_trigger_keyword_body" translatable="false">Reply when a word matches</string>
|
||||
<string name="home_automation_step_recipients" translatable="false">Step 2</string>
|
||||
<string name="home_automation_step_recipients_meta" translatable="false">Recipient filter</string>
|
||||
<string name="home_automation_step_recipients_question" translatable="false">Who should receive it?</string>
|
||||
<string name="home_automation_recipient_all" translatable="false">All callers</string>
|
||||
<string name="home_automation_recipient_contacts" translatable="false">Saved contacts only</string>
|
||||
<string name="home_automation_recipient_unknown" translatable="false">Unknown numbers only</string>
|
||||
<string name="home_automation_exclude_family" translatable="false">Exclude family and personal contacts</string>
|
||||
<string name="home_automation_business_tag" translatable="false">Client / business tag (122)</string>
|
||||
<string name="home_automation_add_target" translatable="false">+ Add target</string>
|
||||
<string name="home_automation_include" translatable="false">Include</string>
|
||||
<string name="home_automation_exclude" translatable="false">Exclude</string>
|
||||
<string name="home_automation_add_targets" translatable="false">+ Add contacts or groups</string>
|
||||
<string name="home_automation_select_contacts" translatable="false">Select contacts</string>
|
||||
<string name="home_automation_target_remove" translatable="false">Remove</string>
|
||||
<string name="home_automation_targets_empty" translatable="false">No contacts or groups selected</string>
|
||||
<string name="home_automation_pick_targets" translatable="false">Choose contacts or groups</string>
|
||||
<string name="home_automation_pick_contacts" translatable="false">Contacts</string>
|
||||
<string name="home_automation_pick_groups" translatable="false">Groups</string>
|
||||
<string name="home_automation_pick_done" translatable="false">Done</string>
|
||||
<string name="home_automation_no_groups_title" translatable="false">No contact groups</string>
|
||||
<string name="home_automation_no_groups_body" translatable="false">Groups from Contacts will show up here so you can include or exclude them.</string>
|
||||
<plurals name="home_automation_group_member_count" translatable="false">
|
||||
<item quantity="one">%d contact</item>
|
||||
<item quantity="other">%d contacts</item>
|
||||
</plurals>
|
||||
<string name="home_automation_manage" translatable="false">Manage</string>
|
||||
<string name="home_automation_banner" translatable="false">Messages sent automatically are marked in chat with a robot badge.</string>
|
||||
<string name="home_automation_modes_title" translatable="false">Major modes</string>
|
||||
@@ -204,6 +250,9 @@
|
||||
<string name="home_automation_rules_title" translatable="false">Active rules</string>
|
||||
<string name="home_automation_rules_count" translatable="false">3</string>
|
||||
<string name="home_automation_rules_sort" translatable="false">Sort: latest</string>
|
||||
<string name="home_automation_rule_archived" translatable="false">Rule archived</string>
|
||||
<string name="home_automation_rule_restored" translatable="false">Rule restored</string>
|
||||
<string name="home_automation_rule_deleted" translatable="false">Rule deleted</string>
|
||||
<string name="home_automation_rule_missed_chip1" translatable="false">Missed-call reply</string>
|
||||
<string name="home_automation_rule_missed_chip2" translatable="false">Immediate</string>
|
||||
<string name="home_automation_rule_missed_title" translatable="false">Auto-reply to missed calls</string>
|
||||
@@ -304,6 +353,10 @@
|
||||
<string name="home_popover_recently_deleted" translatable="false">Trash</string>
|
||||
<string name="home_archived_title" translatable="false">Archive</string>
|
||||
<string name="home_archived_subtitle" translatable="false">Archived conversations stay here until you restore or delete them.</string>
|
||||
<string name="home_archived_tab_chats" translatable="false">Chats</string>
|
||||
<string name="home_archived_tab_rules" translatable="false">Rules</string>
|
||||
<string name="home_archived_rules_empty_title" translatable="false">No archived rules</string>
|
||||
<string name="home_archived_rules_empty_body" translatable="false">Automation rules you archive will show up here.</string>
|
||||
<string name="home_recently_deleted_title" translatable="false">Trash</string>
|
||||
<string name="home_recently_deleted_subtitle" translatable="false">Deleted conversations stay here for 30 days, then they are permanently deleted.</string>
|
||||
<string name="home_recently_deleted_empty" translatable="false">Trash is empty</string>
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<item name="android:windowBackground">@color/home_bg</item>
|
||||
<item name="android:statusBarColor">@color/home_bg</item>
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
<item name="android:navigationBarColor">@color/home_bg</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowLightNavigationBar">true</item>
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="editTextStyle">@style/Home.EditText</item>
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
<config>
|
||||
<allow-in-power-save package="com.filabcorp.msgq" />
|
||||
<allow-in-power-save package="com.bnkode.notie" />
|
||||
</config>
|
||||
+1
-1
@@ -40,4 +40,4 @@ if [ $# -lt 1 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
adb shell su -c sqlite3 $opts data/data/com.filabcorp.msgq/databases/bugle_db "$1"
|
||||
adb shell su -c sqlite3 $opts data/data/com.bnkode.notie/databases/bugle_db "$1"
|
||||
|
||||
@@ -11,14 +11,14 @@ function Invoke-Adb {
|
||||
}
|
||||
|
||||
Write-Host "== Default SMS + permissions =="
|
||||
Invoke-Adb shell cmd role add-role-holder android.app.role.SMS com.filabcorp.msgq | Out-Null
|
||||
Invoke-Adb shell settings put secure sms_default_application com.filabcorp.msgq | Out-Null
|
||||
Invoke-Adb shell cmd role add-role-holder android.app.role.SMS com.bnkode.notie | Out-Null
|
||||
Invoke-Adb shell settings put secure sms_default_application com.bnkode.notie | Out-Null
|
||||
foreach ($p in @(
|
||||
"READ_SMS","RECEIVE_SMS","SEND_SMS","RECEIVE_MMS",
|
||||
"READ_CONTACTS","WRITE_CONTACTS","READ_PHONE_STATE",
|
||||
"READ_PHONE_NUMBERS","POST_NOTIFICATIONS"
|
||||
)) {
|
||||
Invoke-Adb shell pm grant com.filabcorp.msgq "android.permission.$p" 2>$null | Out-Null
|
||||
Invoke-Adb shell pm grant com.bnkode.notie "android.permission.$p" 2>$null | Out-Null
|
||||
}
|
||||
|
||||
$demo = @(
|
||||
@@ -79,7 +79,7 @@ for ($i = 0; $i -lt $demo.Count; $i += 2) {
|
||||
}
|
||||
|
||||
Write-Host "== Relaunch =="
|
||||
Invoke-Adb shell am force-stop com.filabcorp.msgq | Out-Null
|
||||
Invoke-Adb shell am force-stop com.bnkode.notie | Out-Null
|
||||
Start-Sleep -Seconds 1
|
||||
Invoke-Adb shell am start -n com.filabcorp.msgq/com.android.messaging.ui.conversationlist.ConversationListActivity | Out-Null
|
||||
Invoke-Adb shell am start -n com.bnkode.notie/com.android.messaging.ui.conversationlist.ConversationListActivity | Out-Null
|
||||
Write-Host "Done."
|
||||
|
||||
Reference in New Issue
Block a user