/* * This is the source code of Telegram for Android v. 5.x.x. * It is licensed under GNU GPL v. 2 or later. * You should have received a copy of the license in this archive (see LICENSE). * * Copyright Nikolai Kudashov, 2013-2018. */ package org.telegram.ui; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.StateListAnimator; import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; import android.util.TypedValue; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.ViewOutlineProvider; import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.Keep; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BuildConfig; import org.telegram.messenger.BuildVars; import org.telegram.messenger.ContactsController; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLoader; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaDataController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.NotificationsController; import org.telegram.messenger.R; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.SerializedData; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; import org.telegram.ui.Cells.EmptyCell; import org.telegram.ui.Cells.GraySectionCell; import org.telegram.ui.Cells.HeaderCell; import org.telegram.ui.Cells.SettingsSearchCell; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.TextDetailCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.EmptyTextProgressView; import org.telegram.ui.Components.ImageUpdater; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RadialProgressView; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.voip.VoIPHelper; import java.io.File; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.Locale; import java.util.Set; import cn.hutool.core.util.RuntimeUtil; import kotlin.Unit; import tw.nekomimi.nekogram.BottomBuilder; import tw.nekomimi.nekogram.NekoConfig; import tw.nekomimi.nekogram.NekoXConfig; import tw.nekomimi.nekogram.NekoXSettingActivity; import tw.nekomimi.nekogram.parts.UpdateChecksKt; import tw.nekomimi.nekogram.settings.NekoSettingsActivity; import tw.nekomimi.nekogram.utils.AlertUtil; import tw.nekomimi.nekogram.utils.EnvUtil; import tw.nekomimi.nekogram.utils.FileUtil; import tw.nekomimi.nekogram.utils.IoUtil; import tw.nekomimi.nekogram.utils.LangsKt; import tw.nekomimi.nekogram.utils.ShareUtil; import tw.nekomimi.nekogram.utils.ThreadUtil; import tw.nekomimi.nekogram.utils.UIUtil; public class SettingsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, ImageUpdater.ImageUpdaterDelegate { private RecyclerListView listView; private RecyclerListView searchListView; private ListAdapter listAdapter; private SearchAdapter searchAdapter; private LinearLayoutManager layoutManager; private FrameLayout avatarContainer; private BackupImageView avatarImage; private View avatarOverlay; private AnimatorSet avatarAnimation; private RadialProgressView avatarProgressView; private SimpleTextView titleTextView; private TextView nameTextView; private TextView onlineTextView; private TextView idTextView; private ImageView writeButton; private AnimatorSet writeButtonAnimation; private ImageUpdater imageUpdater; private AvatarDrawable avatarDrawable; private TopView topView; private ActionBarMenuItem otherItem; private EmptyTextProgressView emptyView; private ActionBarMenuItem searchItem; private TLRPC.FileLocation avatar; private TLRPC.FileLocation avatarBig; private TLRPC.UserFull userInfo; private boolean playProfileAnimation; private boolean allowProfileAnimation = true; private float animationProgress; private int initialAnimationExtraHeight; private boolean openAnimationInProgress; private int extraHeight; private int searchTransitionOffset; private float searchTransitionProgress; private Animator searchViewTransition; private boolean searchMode; private int emptyRow; private int numberSectionRow; private int numberRow; private int usernameRow; private int bioRow; private int settingsSectionRow; private int settingsSectionRow2; private int notificationRow; private int languageRow; private int privacyRow; private int dataRow; private int chatRow; private int stickersRow; private int filtersRow; private int devicesRow; private int nekoRow; private int devicesSectionRow; private int helpHeaderRow; private int questionRow; private int faqRow; private int policyRow; private int helpSectionCell; private int debugHeaderRow; private int sendLogsRow; private int clearLogsRow; private int switchBackendRow; private int versionRow; private int rowCount; private String currentBio; private int transitionIndex; private final static int edit_name = 1; private final static int logout = 2; private final static int search_button = 3; private final Interpolator transitionInterpolator = new DecelerateInterpolator(); private class TopView extends View { private int currentColor; private Paint paint = new Paint(); public TopView(Context context) { super(context); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), ActionBar.getCurrentActionBarHeight() + (actionBar.getOccupyStatusBar() ? AndroidUtilities.statusBarHeight : 0) + AndroidUtilities.dp(91)); } @Override public void setBackgroundColor(int color) { if (color != currentColor) { paint.setColor(color); invalidate(); } } @Override protected void onDraw(Canvas canvas) { int height = getMeasuredHeight() - AndroidUtilities.dp(91); canvas.drawRect(0, 0, getMeasuredWidth(), height + extraHeight + searchTransitionOffset, paint); if (parentLayout != null) { parentLayout.drawHeaderShadow(canvas, height + extraHeight + searchTransitionOffset); } } } private PhotoViewer.PhotoViewerProvider provider = new PhotoViewer.EmptyPhotoViewerProvider() { @Override public PhotoViewer.PlaceProviderObject getPlaceForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index, boolean needPreview) { if (fileLocation == null) { return null; } TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); if (user != null && user.photo != null && user.photo.photo_big != null) { TLRPC.FileLocation photoBig = user.photo.photo_big; if (photoBig.local_id == fileLocation.local_id && photoBig.volume_id == fileLocation.volume_id && photoBig.dc_id == fileLocation.dc_id) { int[] coords = new int[2]; avatarImage.getLocationInWindow(coords); PhotoViewer.PlaceProviderObject object = new PhotoViewer.PlaceProviderObject(); object.viewX = coords[0]; object.viewY = coords[1] - (Build.VERSION.SDK_INT >= 21 ? 0 : AndroidUtilities.statusBarHeight); object.parentView = avatarImage; object.imageReceiver = avatarImage.getImageReceiver(); object.dialogId = UserConfig.getInstance(currentAccount).getClientUserId(); object.thumb = object.imageReceiver.getBitmapSafe(); object.size = -1; object.radius = avatarImage.getImageReceiver().getRoundRadius(); object.scale = avatarContainer.getScaleX(); return object; } } return null; } @Override public void willHidePhotoViewer() { avatarImage.getImageReceiver().setVisible(true, true); } }; @Override public boolean onFragmentCreate() { super.onFragmentCreate(); hasOwnBackground = true; imageUpdater = new ImageUpdater(); imageUpdater.parentFragment = this; imageUpdater.delegate = this; NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.updateInterfaces); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.userInfoDidLoad); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiDidLoad); updateRows(); getMediaDataController().checkFeaturedStickers(); getMessagesController().loadSuggestedFilters(); userInfo = getMessagesController().getUserFull(UserConfig.getInstance(currentAccount).getClientUserId()); getMessagesController().loadUserInfo(UserConfig.getInstance(currentAccount).getCurrentUser(), true, classGuid); return true; } @Override public void onFragmentDestroy() { super.onFragmentDestroy(); if (avatarImage != null) { avatarImage.setImageDrawable(null); } NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.updateInterfaces); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.userInfoDidLoad); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiDidLoad); imageUpdater.clear(); } @Override protected ActionBar createActionBar(Context context) { ActionBar actionBar = new ActionBar(context); actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_avatar_actionBarSelectorBlue), false); actionBar.setItemsColor(Theme.getColor(Theme.key_avatar_actionBarIconBlue), false); actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setCastShadows(false); actionBar.setAddToContainer(false); actionBar.setOccupyStatusBar(Build.VERSION.SDK_INT >= 21 && !AndroidUtilities.isTablet()); return actionBar; } @Override public View createView(Context context) { extraHeight = AndroidUtilities.dp(88); searchTransitionOffset = 0; searchTransitionProgress = 1f; searchMode = false; actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { if (id == -1) { finishFragment(); } else if (id == edit_name) { presentFragment(new ChangeNameActivity()); } else if (id == logout) { presentFragment(new LogoutActivity()); } } }); ActionBarMenu menu = actionBar.createMenu(); searchItem = menu.addItem(search_button, R.drawable.ic_ab_search).setIsSearchField(true).setActionBarMenuItemSearchListener(new ActionBarMenuItem.ActionBarMenuItemSearchListener() { @Override public Animator getCustomToggleTransition() { searchMode = !searchMode; if (searchMode) { searchAdapter.loadFaqWebPage(); } else { searchItem.clearFocusOnSearchView(); } return searchExpandTransition(searchMode); } @Override public void onTextChanged(EditText editText) { searchAdapter.search(editText.getText().toString().toLowerCase()); } }); searchItem.setContentDescription(LocaleController.getString("SearchInSettings", R.string.SearchInSettings)); searchItem.setSearchFieldHint(LocaleController.getString("SearchInSettings", R.string.SearchInSettings)); otherItem = menu.addItem(0, R.drawable.ic_ab_other); otherItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); otherItem.addSubItem(edit_name, R.drawable.baseline_edit_24, LocaleController.getString("EditName", R.string.EditName)); otherItem.addSubItem(logout, R.drawable.baseline_exit_to_app_24, LocaleController.getString("LogOut", R.string.LogOut)); int scrollTo; int scrollToPosition = 0; Object writeButtonTag = null; if (listView != null) { scrollTo = layoutManager.findFirstVisibleItemPosition(); View topView = layoutManager.findViewByPosition(scrollTo); if (topView != null) { scrollToPosition = topView.getTop(); } else { scrollTo = -1; } writeButtonTag = writeButton.getTag(); } else { scrollTo = -1; } listAdapter = new ListAdapter(context); searchAdapter = new SearchAdapter(context); fragmentView = new FrameLayout(context) { private Paint paint = new Paint(); @Override public boolean hasOverlappingRendering() { return false; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { titleTextView.setTextSize(!AndroidUtilities.isTablet() && getContext().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 18 : 20); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (titleTextView != null) { int textLeft = AndroidUtilities.dp(AndroidUtilities.isTablet() ? 80 : 72); int textTop = (ActionBar.getCurrentActionBarHeight() - titleTextView.getTextHeight()) / 2 + (Build.VERSION.SDK_INT >= 21 && !AndroidUtilities.isTablet() ? AndroidUtilities.statusBarHeight : 0); titleTextView.layout(textLeft, textTop, textLeft + titleTextView.getMeasuredWidth(), textTop + titleTextView.getTextHeight()); } checkListViewScroll(); } @Override public void onDraw(Canvas c) { paint.setColor(Theme.getColor(Theme.key_windowBackgroundWhite)); View contentView = listView.getVisibility() == View.VISIBLE ? listView : searchListView; c.drawRect(contentView.getLeft(), contentView.getTop() + extraHeight + searchTransitionOffset, contentView.getRight(), contentView.getBottom(), paint); } }; fragmentView.setWillNotDraw(false); FrameLayout frameLayout = (FrameLayout) fragmentView; listView = new RecyclerListView(context) { @Override public boolean hasOverlappingRendering() { return false; } }; listView.setHideIfEmpty(false); listView.setVerticalScrollBarEnabled(false); listView.setLayoutManager(layoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) { @Override public boolean supportsPredictiveItemAnimations() { return false; } }); listView.setGlowColor(Theme.getColor(Theme.key_avatar_backgroundActionBarBlue)); listView.setPadding(0, AndroidUtilities.dp(88), 0, 0); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); listView.setAdapter(listAdapter); listView.setItemAnimator(null); listView.setLayoutAnimation(null); listView.setClipToPadding(false); listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { private int pressCount = 0; @Override public void onItemClick(View view, int position) { if (position == notificationRow) { presentFragment(new NotificationsSettingsActivity()); } else if (position == privacyRow) { presentFragment(new PrivacySettingsActivity()); } else if (position == dataRow) { presentFragment(new DataSettingsActivity()); } else if (position == chatRow) { presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC)); } else if (position == stickersRow) { presentFragment(new StickersActivity(MediaDataController.TYPE_IMAGE)); } else if (position == filtersRow) { presentFragment(new FiltersSetupActivity()); } else if (position == devicesRow) { presentFragment(new SessionsActivity(0)); } else if (position == nekoRow) { presentFragment(new NekoSettingsActivity()); } else if (position == questionRow) { Browser.openUrl(getParentActivity(), "https://t.me/NekogramX"); } else if (position == faqRow) { Browser.openUrl(getParentActivity(), NekoXConfig.FAQ_URL); } else if (position == policyRow) { Browser.openUrl(getParentActivity(), LocaleController.getString("PrivacyPolicyUrl", R.string.PrivacyPolicyUrl)); } else if (position == sendLogsRow) { sendLogs(); } else if (position == clearLogsRow) { AlertDialog pro = AlertUtil.showProgress(getParentActivity()); pro.show(); UIUtil.runOnIoDispatcher(() -> { FileUtil.delete(new File(EnvUtil.getTelegramPath(), "logs")); ThreadUtil.sleep(100L); LangsKt.uDismiss(pro); }); } else if (position == switchBackendRow) { if (getParentActivity() == null) { return; } AlertDialog.Builder builder1 = new AlertDialog.Builder(getParentActivity()); builder1.setMessage(LocaleController.getString("AreYouSure", R.string.AreYouSure)); builder1.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder1.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> { SharedConfig.pushAuthKey = null; SharedConfig.pushAuthKeyId = null; SharedConfig.saveConfig(); ConnectionsManager.getInstance(currentAccount).switchBackend(); }); builder1.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder1.create()); } else if (position == languageRow) { presentFragment(new LanguageSelectActivity()); } else if (position == usernameRow) { presentFragment(new ChangeUsernameActivity()); } else if (position == bioRow) { if (userInfo != null) { presentFragment(new ChangeBioActivity()); } } else if (position == numberRow) { presentFragment(new ActionIntroActivity(ActionIntroActivity.ACTION_TYPE_CHANGE_PHONE_NUMBER)); } else if (position == versionRow) { TextInfoPrivacyCell cell = (TextInfoPrivacyCell) view; pressCount++; if (pressCount == 8) { NekoXConfig.developerModeEntrance = true; } BottomBuilder builder = new BottomBuilder(getParentActivity()); builder.addTitle(cell.getTextView().getText().toString(), false); builder.addItem(LocaleController.getString("Copy", R.string.Copy), R.drawable.baseline_content_copy_24, (it) -> { builder.dismiss(); AndroidUtilities.addToClipboard(cell.getTextView().getText().toString()); AlertUtil.showToast(LocaleController.getString("TextCopied", R.string.TextCopied)); return Unit.INSTANCE; }); builder.addItem(BuildVars.LOGS_ENABLED ? LocaleController.getString("DebugMenuDisableLogs", R.string.DebugMenuDisableLogs) : LocaleController.getString("DebugMenuEnableLogs", R.string.DebugMenuEnableLogs), R.drawable.baseline_bug_report_24, (it) -> { builder.dismiss(); BuildVars.LOGS_ENABLED = !BuildVars.LOGS_ENABLED; SharedPreferences sharedPreferences = ApplicationLoader.applicationContext.getSharedPreferences("systemConfig", Context.MODE_PRIVATE); sharedPreferences.edit().putBoolean("logsEnabled", BuildVars.LOGS_ENABLED).apply(); updateRows(); return Unit.INSTANCE; }); if (!BuildVars.isUnknown) { builder.addItem(LocaleController.getString("CheckUpdate", R.string.CheckUpdate), R.drawable.baseline_system_update_24, (it) -> { builder.dismiss(); UpdateChecksKt.checkUpdate(getParentActivity()); return Unit.INSTANCE; }); } builder.addItem(LocaleController.getString("SwitchVersion", R.string.SwitchVersion), R.drawable.baseline_replay_24, (it) -> { builder.dismiss(); UpdateChecksKt.switchVersion(getParentActivity()); return Unit.INSTANCE; }); if (NekoXConfig.developerModeEntrance || NekoXConfig.developerMode) { builder.addItem(LocaleController.getString("DeveloperSettings", R.string.DeveloperSettings), R.drawable.baseline_developer_mode_24, (it) -> { builder.dismiss(); BottomBuilder devBuilder = new BottomBuilder(getParentActivity()); devBuilder.addTitle(LocaleController.getString("DevModeTitle", R.string.DevModeTitle), LocaleController.getString("DevModeNotice", R.string.DevModeNotice)); devBuilder.addItem(LocaleController.getString("Continue", R.string.Continue), R.drawable.baseline_warning_24, true, (__) -> { devBuilder.dismiss(); presentFragment(new NekoXSettingActivity()); return Unit.INSTANCE; }); devBuilder.addCancelItem(); devBuilder.show(); return Unit.INSTANCE; }); } builder.show(); } } }); listView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { private int pressCount = 0; @Override public boolean onItemClick(View view, int position) { if (!NekoXConfig.developerMode) return false; if (position == versionRow) { pressCount++; if (pressCount >= 2 || BuildVars.DEBUG_PRIVATE_VERSION) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("DebugMenu", R.string.DebugMenu)); CharSequence[] items; items = new CharSequence[]{ LocaleController.getString("DebugMenuImportContacts", R.string.DebugMenuImportContacts), LocaleController.getString("DebugMenuReloadContacts", R.string.DebugMenuReloadContacts), LocaleController.getString("DebugMenuResetContacts", R.string.DebugMenuResetContacts), LocaleController.getString("DebugMenuResetDialogs", R.string.DebugMenuResetDialogs), BuildVars.DEBUG_VERSION ? LocaleController.getString("DebugMenuDisableLogs", R.string.DebugMenuDisableLogs) : LocaleController.getString("DebugMenuEnableLogs", R.string.DebugMenuEnableLogs), null, LocaleController.getString("DebugMenuClearMediaCache", R.string.DebugMenuClearMediaCache), LocaleController.getString("DebugMenuCallSettings", R.string.DebugMenuCallSettings), LocaleController.getString("DebugMenuReadAllDialogs", R.string.DebugMenuReadAllDialogs), SharedConfig.pauseMusicOnRecord ? LocaleController.getString("DebugMenuDisablePauseMusic", R.string.DebugMenuDisablePauseMusic) : LocaleController.getString("DebugMenuEnablePauseMusic", R.string.DebugMenuEnablePauseMusic) }; builder.setItems(items, (dialog, which) -> { if (which == 0) { UserConfig.getInstance(currentAccount).syncContacts = true; UserConfig.getInstance(currentAccount).saveConfig(false); ContactsController.getInstance(currentAccount).forceImportContacts(); } else if (which == 1) { ContactsController.getInstance(currentAccount).loadContacts(false, 0); } else if (which == 2) { ContactsController.getInstance(currentAccount).resetImportedContacts(); } else if (which == 3) { MessagesController.getInstance(currentAccount).forceResetDialogs(); } else if (which == 4) { NekoConfig.toggleResidentNotification(); } else if (which == 5) { MessagesStorage.getInstance(currentAccount).clearSentMedia(); SharedConfig.setNoSoundHintShowed(false); SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); editor.remove("archivehint").remove("archivehint_l").remove("gifhint").remove("soundHint").remove("themehint").remove("filterhint").apply(); SharedConfig.textSelectionHintShows = 0; SharedConfig.lockRecordAudioVideoHint = 0; SharedConfig.stickersReorderingHintUsed = false; } else if (which == 6) { VoIPHelper.showCallDebugSettings(getParentActivity()); } else if (which == 7) { MessagesStorage.getInstance(currentAccount).readAllDialogs(-1); } else if (which == 8) { SharedConfig.togglePauseMusicOnRecord(); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); } else { try { Toast.makeText(getParentActivity(), "¯\\_(ツ)_/¯", Toast.LENGTH_SHORT).show(); } catch (Exception e) { FileLog.e(e); } } return true; } return false; } }); searchListView = new RecyclerListView(context) { @Override public boolean hasOverlappingRendering() { return false; } }; searchListView.setVerticalScrollBarEnabled(false); searchListView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); searchListView.setGlowColor(Theme.getColor(Theme.key_avatar_backgroundActionBarBlue)); frameLayout.addView(searchListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); searchListView.setAdapter(searchAdapter); searchListView.setItemAnimator(null); searchListView.setLayoutAnimation(null); searchListView.setOnItemClickListener((view, position) -> { if (position < 0) { return; } Object object = numberRow; if (searchAdapter.searchWas) { if (position < searchAdapter.searchResults.size()) { object = searchAdapter.searchResults.get(position); } else { position -= searchAdapter.searchResults.size() + 1; if (position >= 0 && position < searchAdapter.faqSearchResults.size()) { object = searchAdapter.faqSearchResults.get(position); } } } else { position--; if (position < 0) { return; } if (position < searchAdapter.recentSearches.size()) { object = searchAdapter.recentSearches.get(position); } } if (object instanceof SearchAdapter.SearchResult) { SearchAdapter.SearchResult result = (SearchAdapter.SearchResult) object; result.open(); } else if (object instanceof SearchAdapter.FaqSearchResult) { SearchAdapter.FaqSearchResult result = (SearchAdapter.FaqSearchResult) object; NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.openArticle, searchAdapter.faqWebPage, result.url); } if (object != null) { searchAdapter.addRecent(object); } }); searchListView.setOnItemLongClickListener((view, position) -> { if (searchAdapter.isSearchWas()) { return false; } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("NekoX", R.string.NekoX)); builder.setMessage(LocaleController.getString("ClearSearch", R.string.ClearSearch)); builder.setPositiveButton(LocaleController.getString("ClearButton", R.string.ClearButton).toUpperCase(), (dialogInterface, i) -> searchAdapter.clearRecent()); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); return true; }); searchListView.setVisibility(View.GONE); emptyView = new EmptyTextProgressView(context); emptyView.showTextView(); emptyView.setTextSize(18); emptyView.setVisibility(View.GONE); emptyView.setShowAtCenter(true); emptyView.setPadding(0, AndroidUtilities.dp(50), 0, 0); frameLayout.addView(emptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); topView = new TopView(context); topView.setBackgroundColor(Theme.getColor(Theme.key_avatar_backgroundActionBarBlue)); frameLayout.addView(topView); frameLayout.addView(actionBar); avatarContainer = new FrameLayout(context); avatarContainer.setPivotX(0); avatarContainer.setPivotY(0); frameLayout.addView(avatarContainer, LayoutHelper.createFrame(42, 42, Gravity.TOP | Gravity.LEFT, 64, 0, 0, 0)); avatarContainer.setOnClickListener(v -> { if (avatar != null) { return; } TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); if (user != null && user.photo != null && user.photo.photo_big != null) { PhotoViewer.getInstance().setParentActivity(getParentActivity()); if (user.photo.dc_id != 0) { user.photo.photo_big.dc_id = user.photo.dc_id; } PhotoViewer.getInstance().openPhoto(user.photo.photo_big, provider); } }); avatarImage = new BackupImageView(context); avatarImage.setRoundRadius(AndroidUtilities.dp(21)); avatarImage.setContentDescription(LocaleController.getString("AccDescrProfilePicture", R.string.AccDescrProfilePicture)); avatarContainer.addView(avatarImage, LayoutHelper.createFrame(42, 42)); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(0x55000000); avatarProgressView = new RadialProgressView(context) { @Override protected void onDraw(Canvas canvas) { if (avatarImage != null && avatarImage.getImageReceiver().hasNotThumb()) { paint.setAlpha((int) (0x55 * avatarImage.getImageReceiver().getCurrentAlpha())); canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, AndroidUtilities.dp(21), paint); } super.onDraw(canvas); } }; avatarProgressView.setSize(AndroidUtilities.dp(26)); avatarProgressView.setProgressColor(0xffffffff); avatarContainer.addView(avatarProgressView, LayoutHelper.createFrame(42, 42)); showAvatarProgress(false, false); titleTextView = new SimpleTextView(context); titleTextView.setGravity(Gravity.LEFT); titleTextView.setTextColor(Theme.getColor(Theme.key_actionBarDefaultTitle)); titleTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); titleTextView.setText(LocaleController.getString("NekoX", R.string.NekoX)); titleTextView.setAlpha(0.0f); frameLayout.addView(titleTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP)); nameTextView = new TextView(context); nameTextView.setTextColor(Theme.getColor(Theme.key_profile_title)); nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); nameTextView.setLines(1); nameTextView.setMaxLines(1); nameTextView.setSingleLine(true); nameTextView.setEllipsize(TextUtils.TruncateAt.END); nameTextView.setGravity(Gravity.LEFT); nameTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); nameTextView.setPivotX(0); nameTextView.setPivotY(0); frameLayout.addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 118, 0, 96, 0)); onlineTextView = new TextView(context); onlineTextView.setTextColor(Theme.getColor(Theme.key_profile_status)); onlineTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); onlineTextView.setLines(1); onlineTextView.setMaxLines(1); onlineTextView.setSingleLine(true); onlineTextView.setEllipsize(TextUtils.TruncateAt.END); onlineTextView.setGravity(Gravity.LEFT); frameLayout.addView(onlineTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 118, 0, 96, 0)); idTextView = new TextView(context); idTextView.setTextColor(AvatarDrawable.getProfileTextColorForId(5)); idTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); idTextView.setLines(1); idTextView.setMaxLines(1); idTextView.setSingleLine(true); idTextView.setEllipsize(TextUtils.TruncateAt.END); idTextView.setGravity(Gravity.LEFT); idTextView.setAlpha(1.0f); frameLayout.addView(idTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 118, 0, 48, 0)); writeButton = new ImageView(context); Drawable drawable = Theme.createSimpleSelectorCircleDrawable(AndroidUtilities.dp(56), Theme.getColor(Theme.key_profile_actionBackground), Theme.getColor(Theme.key_profile_actionPressedBackground)); if (Build.VERSION.SDK_INT < 21) { Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.floating_shadow_profile).mutate(); shadowDrawable.setColorFilter(new PorterDuffColorFilter(0xff000000, PorterDuff.Mode.SRC_IN)); CombinedDrawable combinedDrawable = new CombinedDrawable(shadowDrawable, drawable, 0, 0); combinedDrawable.setIconSize(AndroidUtilities.dp(56), AndroidUtilities.dp(56)); drawable = combinedDrawable; } writeButton.setBackgroundDrawable(drawable); writeButton.setImageResource(R.drawable.baseline_edit_24); writeButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_actionBarDefaultSubmenuItemIcon), PorterDuff.Mode.SRC_IN)); writeButton.setScaleType(ImageView.ScaleType.CENTER); if (Build.VERSION.SDK_INT >= 21) { StateListAnimator animator = new StateListAnimator(); animator.addState(new int[]{android.R.attr.state_pressed}, ObjectAnimator.ofFloat(writeButton, "translationZ", AndroidUtilities.dp(2), AndroidUtilities.dp(4)).setDuration(200)); animator.addState(new int[]{}, ObjectAnimator.ofFloat(writeButton, "translationZ", AndroidUtilities.dp(4), AndroidUtilities.dp(2)).setDuration(200)); writeButton.setStateListAnimator(animator); writeButton.setOutlineProvider(new ViewOutlineProvider() { @SuppressLint("NewApi") @Override public void getOutline(View view, Outline outline) { outline.setOval(0, 0, AndroidUtilities.dp(56), AndroidUtilities.dp(56)); } }); } frameLayout.addView(writeButton, LayoutHelper.createFrame(Build.VERSION.SDK_INT >= 21 ? 56 : 60, Build.VERSION.SDK_INT >= 21 ? 56 : 60, Gravity.RIGHT | Gravity.TOP, 0, 0, 16, 0)); writeButton.setOnClickListener(v -> { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); if (user == null) { user = UserConfig.getInstance(currentAccount).getCurrentUser(); } if (user == null) { return; } imageUpdater.openMenu(user.photo != null && user.photo.photo_big != null && !(user.photo instanceof TLRPC.TL_userProfilePhotoEmpty), () -> MessagesController.getInstance(currentAccount).deleteUserPhoto(null)); }); writeButton.setContentDescription(LocaleController.getString("AccDescrChangeProfilePicture", R.string.AccDescrChangeProfilePicture)); if (scrollTo != -1) { layoutManager.scrollToPositionWithOffset(scrollTo, scrollToPosition); if (writeButtonTag != null) { writeButton.setTag(0); writeButton.setScaleX(0.2f); writeButton.setScaleY(0.2f); writeButton.setAlpha(0.0f); } } needLayout(); searchListView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { if (newState == RecyclerView.SCROLL_STATE_DRAGGING) { AndroidUtilities.hideKeyboard(getParentActivity().getCurrentFocus()); } } }); listView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { checkListViewScroll(); } }); return fragmentView; } private void updateRows() { rowCount = 0; emptyRow = rowCount++; numberSectionRow = rowCount++; numberRow = rowCount++; usernameRow = rowCount++; bioRow = rowCount++; settingsSectionRow = rowCount++; settingsSectionRow2 = rowCount++; notificationRow = rowCount++; dataRow = rowCount++; privacyRow = rowCount++; chatRow = rowCount++; stickersRow = rowCount++; filtersRow = rowCount++; devicesRow = -1; nekoRow = rowCount++; languageRow = rowCount++; devicesSectionRow = -1; helpHeaderRow = rowCount++; questionRow = -1; faqRow = rowCount++; policyRow = -1; if (BuildVars.DEBUG_VERSION) { helpSectionCell = rowCount++; debugHeaderRow = rowCount++; } else { helpSectionCell = -1; debugHeaderRow = -1; } if (BuildVars.DEBUG_VERSION) { sendLogsRow = rowCount++; clearLogsRow = rowCount++; } else { sendLogsRow = -1; clearLogsRow = -1; } switchBackendRow = -1; versionRow = rowCount++; if (listAdapter != null) { listAdapter.notifyDataSetChanged(); } } private Animator searchExpandTransition(boolean enter) { if (enter) { getParentActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); } if (searchViewTransition != null) { searchViewTransition.removeAllListeners(); searchViewTransition.cancel(); } ValueAnimator valueAnimator = ValueAnimator.ofFloat(searchTransitionProgress, enter ? 0f : 1f); int offset = extraHeight; searchListView.setTranslationY(offset); searchListView.setVisibility(View.VISIBLE); searchItem.setVisibility(View.VISIBLE); listView.setVisibility(View.VISIBLE); needLayout(); avatarContainer.setVisibility(View.VISIBLE); nameTextView.setVisibility(View.VISIBLE); onlineTextView.setVisibility(View.VISIBLE); idTextView.setVisibility(View.VISIBLE); actionBar.onSearchFieldVisibilityChanged(searchTransitionProgress > 0.5f); if (otherItem != null) { otherItem.setVisibility(searchTransitionProgress > 0.5f ? View.VISIBLE : View.GONE); } searchItem.setVisibility(searchTransitionProgress > 0.5f ? View.VISIBLE : View.GONE); searchItem.getSearchContainer().setVisibility(searchTransitionProgress > 0.5f ? View.GONE : View.VISIBLE); searchListView.setEmptyView(emptyView); avatarContainer.setClickable(false); valueAnimator.addUpdateListener(animation -> { searchTransitionProgress = (float) valueAnimator.getAnimatedValue(); float progressHalf = (searchTransitionProgress - 0.5f) / 0.5f; float progressHalfEnd = (0.5f - searchTransitionProgress) / 0.5f; if (progressHalf < 0) { progressHalf = 0f; } if (progressHalfEnd < 0) { progressHalfEnd = 0f; } searchTransitionOffset = (int) (-offset * (1f - searchTransitionProgress)); searchListView.setTranslationY(offset * searchTransitionProgress); emptyView.setTranslationY(offset * searchTransitionProgress); listView.setTranslationY(-offset * (1f - searchTransitionProgress)); needLayout(); listView.setAlpha(progressHalf); searchListView.setAlpha(1f - progressHalf); emptyView.setAlpha(1f - progressHalf); avatarContainer.setAlpha(progressHalf); nameTextView.setAlpha(progressHalf); onlineTextView.setAlpha(progressHalf); idTextView.setAlpha(progressHalf); searchItem.getSearchField().setAlpha(progressHalfEnd); if (enter && searchTransitionProgress < 0.7f) { searchItem.requestFocusOnSearchView(); } searchItem.getSearchContainer().setVisibility(searchTransitionProgress < 0.5f ? View.VISIBLE : View.GONE); if (otherItem != null) { otherItem.setVisibility(searchTransitionProgress > 0.5f ? View.VISIBLE : View.GONE); } searchItem.setVisibility(searchTransitionProgress > 0.5f ? View.VISIBLE : View.GONE); actionBar.onSearchFieldVisibilityChanged(searchTransitionProgress < 0.5f); if (otherItem != null) { otherItem.setAlpha(progressHalf); } searchItem.setAlpha(progressHalf); topView.invalidate(); }); valueAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { updateSearchViewState(enter); avatarContainer.setClickable(true); if (enter) searchItem.requestFocusOnSearchView(); needLayout(); } }); valueAnimator.setDuration(180); valueAnimator.setInterpolator(transitionInterpolator); searchViewTransition = valueAnimator; return valueAnimator; } private void updateSearchViewState(boolean enter) { int hide = enter ? View.GONE : View.VISIBLE; listView.setVisibility(hide); searchListView.setVisibility(enter ? View.VISIBLE : View.GONE); searchItem.getSearchContainer().setVisibility(enter ? View.VISIBLE : View.GONE); actionBar.onSearchFieldVisibilityChanged(enter); avatarContainer.setVisibility(hide); nameTextView.setVisibility(hide); onlineTextView.setVisibility(hide); idTextView.setVisibility(hide); if (otherItem != null) { otherItem.setAlpha(1f); otherItem.setVisibility(hide); } searchItem.setVisibility(hide); avatarContainer.setAlpha(1f); nameTextView.setAlpha(1f); onlineTextView.setAlpha(1f); idTextView.setAlpha(1f); searchItem.setAlpha(1f); listView.setAlpha(1f); searchListView.setAlpha(1f); emptyView.setAlpha(1f); if (enter) { searchListView.setEmptyView(emptyView); } else { emptyView.setVisibility(View.GONE); } } @Override public void didUploadPhoto(final TLRPC.InputFile file, final TLRPC.PhotoSize bigSize, final TLRPC.PhotoSize smallSize) { AndroidUtilities.runOnUIThread(() -> { if (file != null) { TLRPC.TL_photos_uploadProfilePhoto req = new TLRPC.TL_photos_uploadProfilePhoto(); req.file = file; ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { if (error == null) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); if (user == null) { user = UserConfig.getInstance(currentAccount).getCurrentUser(); if (user == null) { return; } MessagesController.getInstance(currentAccount).putUser(user, false); } else { UserConfig.getInstance(currentAccount).setCurrentUser(user); } TLRPC.TL_photos_photo photo = (TLRPC.TL_photos_photo) response; ArrayList sizes = photo.photo.sizes; TLRPC.PhotoSize small = FileLoader.getClosestPhotoSizeWithSize(sizes, 150); TLRPC.PhotoSize big = FileLoader.getClosestPhotoSizeWithSize(sizes, 800); user.photo = new TLRPC.TL_userProfilePhoto(); user.photo.photo_id = photo.photo.id; if (small != null) { user.photo.photo_small = small.location; } if (big != null) { user.photo.photo_big = big.location; } else if (small != null) { user.photo.photo_small = small.location; } if (photo != null) { if (small != null && avatar != null) { File destFile = FileLoader.getPathToAttach(small, true); File src = FileLoader.getPathToAttach(avatar, true); src.renameTo(destFile); String oldKey = avatar.volume_id + "_" + avatar.local_id + "@50_50"; String newKey = small.location.volume_id + "_" + small.location.local_id + "@50_50"; ImageLoader.getInstance().replaceImageInCache(oldKey, newKey, ImageLocation.getForUser(user, false), true); } if (big != null && avatarBig != null) { File destFile = FileLoader.getPathToAttach(big, true); File src = FileLoader.getPathToAttach(avatarBig, true); src.renameTo(destFile); } } MessagesStorage.getInstance(currentAccount).clearUserPhotos(user.id); ArrayList users = new ArrayList<>(); users.add(user); MessagesStorage.getInstance(currentAccount).putUsersAndChats(users, null, false, true); } AndroidUtilities.runOnUIThread(() -> { avatar = null; avatarBig = null; updateUserData(); showAvatarProgress(false, true); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_ALL); NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.mainUserInfoChanged); UserConfig.getInstance(currentAccount).saveConfig(true); }); }); } else { avatar = smallSize.location; avatarBig = bigSize.location; avatarImage.setImage(ImageLocation.getForLocal(avatar), "50_50", avatarDrawable, null); showAvatarProgress(true, false); } }); } private void showAvatarProgress(boolean show, boolean animated) { if (avatarProgressView == null) { return; } if (avatarAnimation != null) { avatarAnimation.cancel(); avatarAnimation = null; } if (animated) { avatarAnimation = new AnimatorSet(); if (show) { avatarProgressView.setVisibility(View.VISIBLE); avatarAnimation.playTogether(ObjectAnimator.ofFloat(avatarProgressView, View.ALPHA, 1.0f)); } else { avatarAnimation.playTogether(ObjectAnimator.ofFloat(avatarProgressView, View.ALPHA, 0.0f)); } avatarAnimation.setDuration(180); avatarAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (avatarAnimation == null || avatarProgressView == null) { return; } if (!show) { avatarProgressView.setVisibility(View.INVISIBLE); } avatarAnimation = null; } @Override public void onAnimationCancel(Animator animation) { avatarAnimation = null; } }); avatarAnimation.start(); } else { if (show) { avatarProgressView.setAlpha(1.0f); avatarProgressView.setVisibility(View.VISIBLE); } else { avatarProgressView.setAlpha(0.0f); avatarProgressView.setVisibility(View.INVISIBLE); } } } @Override public void onActivityResultFragment(int requestCode, int resultCode, Intent data) { imageUpdater.onActivityResult(requestCode, resultCode, data); } @Override public void saveSelfArgs(Bundle args) { if (imageUpdater != null && imageUpdater.currentPicturePath != null) { args.putString("path", imageUpdater.currentPicturePath); } } @Override public void restoreSelfArgs(Bundle args) { if (imageUpdater != null) { imageUpdater.currentPicturePath = args.getString("path"); } } @Override public void didReceivedNotification(int id, int account, Object... args) { if (id == NotificationCenter.updateInterfaces) { int mask = (Integer) args[0]; if ((mask & MessagesController.UPDATE_MASK_AVATAR) != 0 || (mask & MessagesController.UPDATE_MASK_NAME) != 0) { updateUserData(); } } else if (id == NotificationCenter.userInfoDidLoad) { Integer uid = (Integer) args[0]; if (uid == UserConfig.getInstance(currentAccount).getClientUserId() && listAdapter != null) { userInfo = (TLRPC.UserFull) args[1]; if (!TextUtils.equals(userInfo.about, currentBio)) { listAdapter.notifyItemChanged(bioRow); } } } else if (id == NotificationCenter.emojiDidLoad) { if (listView != null) { listView.invalidateViews(); } } } @Override public void onResume() { super.onResume(); if (listAdapter != null) { listAdapter.notifyDataSetChanged(); } updateUserData(); fixLayout(); setParentActivityTitle(LocaleController.getString("Settings", R.string.Settings)); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); fixLayout(); } @Override protected void onTransitionAnimationStart(boolean isOpen, boolean backward) { if ((!isOpen && backward || isOpen && !backward) && playProfileAnimation && allowProfileAnimation) { openAnimationInProgress = true; } if (isOpen) { transitionIndex = NotificationCenter.getInstance(currentAccount).setAnimationInProgress(transitionIndex, new int[]{NotificationCenter.dialogsNeedReload, NotificationCenter.closeChats, NotificationCenter.mediaCountDidLoad, NotificationCenter.mediaCountsDidLoad, NotificationCenter.userInfoDidLoad}); } } @Override protected void onTransitionAnimationEnd(boolean isOpen, boolean backward) { if (isOpen) { if (!backward && playProfileAnimation && allowProfileAnimation) { openAnimationInProgress = false; } NotificationCenter.getInstance(currentAccount).onAnimationFinish(transitionIndex); } } @Keep public float getAnimationProgress() { return animationProgress; } @Keep public void setAnimationProgress(float progress) { animationProgress = progress; listView.setAlpha(progress); listView.setTranslationX(AndroidUtilities.dp(48) - AndroidUtilities.dp(48) * progress); int color = Theme.getColor(Theme.key_avatar_backgroundActionBarBlue); int actionBarColor = Theme.getColor(Theme.key_actionBarDefault); int r = Color.red(actionBarColor); int g = Color.green(actionBarColor); int b = Color.blue(actionBarColor); int rD = (int) ((Color.red(color) - r) * progress); int gD = (int) ((Color.green(color) - g) * progress); int bD = (int) ((Color.blue(color) - b) * progress); topView.setBackgroundColor(Color.rgb(r + rD, g + gD, b + bD)); color = Theme.getColor(Theme.key_avatar_actionBarIconBlue); int iconColor = Theme.getColor(Theme.key_actionBarDefaultIcon); r = Color.red(iconColor); g = Color.green(iconColor); b = Color.blue(iconColor); rD = (int) ((Color.red(color) - r) * progress); gD = (int) ((Color.green(color) - g) * progress); bD = (int) ((Color.blue(color) - b) * progress); actionBar.setItemsColor(Color.rgb(r + rD, g + gD, b + bD), false); titleTextView.setAlpha(1.0f - progress); nameTextView.setAlpha(progress); onlineTextView.setAlpha(progress); idTextView.setAlpha(progress); extraHeight = (int) (initialAnimationExtraHeight * progress); avatarContainer.setAlpha(progress); needLayout(); } @Override protected AnimatorSet onCustomTransitionAnimation(final boolean isOpen, final Runnable callback) { if (playProfileAnimation && allowProfileAnimation) { final AnimatorSet animatorSet = new AnimatorSet(); animatorSet.setDuration(180); listView.setLayerType(View.LAYER_TYPE_HARDWARE, null); ActionBarMenu menu = actionBar.createMenu(); if (isOpen) { FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) onlineTextView.getLayoutParams(); layoutParams.rightMargin = (int) (-21 * AndroidUtilities.density + AndroidUtilities.dp(8)); onlineTextView.setLayoutParams(layoutParams); idTextView.setLayoutParams(layoutParams); int width = (int) Math.ceil(AndroidUtilities.displaySize.x - AndroidUtilities.dp(118 + 8) + 21 * AndroidUtilities.density); float width2 = nameTextView.getPaint().measureText(nameTextView.getText().toString()) * 1.12f; layoutParams = (FrameLayout.LayoutParams) nameTextView.getLayoutParams(); if (width < width2) { layoutParams.width = (int) Math.ceil(width / 1.12f); } else { layoutParams.width = LayoutHelper.WRAP_CONTENT; } nameTextView.setLayoutParams(layoutParams); initialAnimationExtraHeight = AndroidUtilities.dp(88); setAnimationProgress(0); ArrayList animators = new ArrayList<>(); animators.add(ObjectAnimator.ofFloat(this, "animationProgress", 0.0f, 1.0f)); if (writeButton != null) { writeButton.setScaleX(0.2f); writeButton.setScaleY(0.2f); writeButton.setAlpha(0.0f); animators.add(ObjectAnimator.ofFloat(writeButton, View.SCALE_X, 1.0f)); animators.add(ObjectAnimator.ofFloat(writeButton, View.SCALE_Y, 1.0f)); animators.add(ObjectAnimator.ofFloat(writeButton, View.ALPHA, 1.0f)); } animators.add(ObjectAnimator.ofFloat(onlineTextView, View.ALPHA, 0.0f, 1.0f)); animators.add(ObjectAnimator.ofFloat(idTextView, View.ALPHA, 0.0f, 1.0f)); animators.add(ObjectAnimator.ofFloat(nameTextView, View.ALPHA, 0.0f, 1.0f)); searchItem.setTranslationX(AndroidUtilities.dp(48)); otherItem.setTranslationX(AndroidUtilities.dp(48)); animators.add(ObjectAnimator.ofFloat(searchItem, View.TRANSLATION_X, 0)); animators.add(ObjectAnimator.ofFloat(otherItem, View.TRANSLATION_X, 0)); animatorSet.playTogether(animators); } else { initialAnimationExtraHeight = extraHeight; ArrayList animators = new ArrayList<>(); animators.add(ObjectAnimator.ofFloat(this, "animationProgress", 1.0f, 0.0f)); if (writeButton != null) { animators.add(ObjectAnimator.ofFloat(writeButton, View.SCALE_X, 0.2f)); animators.add(ObjectAnimator.ofFloat(writeButton, View.SCALE_Y, 0.2f)); animators.add(ObjectAnimator.ofFloat(writeButton, View.ALPHA, 0.0f)); } animators.add(ObjectAnimator.ofFloat(onlineTextView, View.ALPHA, 0.0f)); animators.add(ObjectAnimator.ofFloat(idTextView, View.ALPHA, 0.0f)); animators.add(ObjectAnimator.ofFloat(nameTextView, View.ALPHA, 0.0f)); animators.add(ObjectAnimator.ofFloat(searchItem, View.TRANSLATION_X, AndroidUtilities.dp(48))); animators.add(ObjectAnimator.ofFloat(otherItem, View.TRANSLATION_X, AndroidUtilities.dp(48))); animatorSet.playTogether(animators); } animatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { listView.setLayerType(View.LAYER_TYPE_NONE, null); callback.run(); } }); animatorSet.setInterpolator(CubicBezierInterpolator.EASE_OUT); AndroidUtilities.runOnUIThread(animatorSet::start, 50); return animatorSet; } return null; } public void setPlayProfileAnimation(boolean value) { SharedPreferences preferences = MessagesController.getGlobalMainSettings(); if (!AndroidUtilities.isTablet() && preferences.getBoolean("view_animations", true)) { playProfileAnimation = value; } } private void checkListViewScroll() { if (listView.getVisibility() != View.VISIBLE || listView.getChildCount() <= 0 || openAnimationInProgress || writeButton.getVisibility() != View.VISIBLE) { return; } View child = listView.getChildAt(0); RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findContainingViewHolder(child); int top = child.getTop(); int newOffset = 0; if (top >= 0 && holder != null && holder.getAdapterPosition() == 0) { newOffset = top; } if (extraHeight != newOffset) { extraHeight = newOffset; topView.invalidate(); needLayout(); } } private void needLayout() { FrameLayout.LayoutParams layoutParams; int newTop = (actionBar.getOccupyStatusBar() ? AndroidUtilities.statusBarHeight : 0) + ActionBar.getCurrentActionBarHeight(); if (listView != null && !openAnimationInProgress) { layoutParams = (FrameLayout.LayoutParams) listView.getLayoutParams(); if (layoutParams.topMargin != newTop) { layoutParams.topMargin = newTop; listView.setLayoutParams(layoutParams); searchListView.setLayoutParams(layoutParams); } } if (avatarContainer != null) { float diff = extraHeight / (float) AndroidUtilities.dp(88); listView.setTopGlowOffset(extraHeight); if (writeButton != null) { writeButton.setTranslationY((actionBar.getOccupyStatusBar() ? AndroidUtilities.statusBarHeight : 0) + ActionBar.getCurrentActionBarHeight() + extraHeight + searchTransitionOffset - AndroidUtilities.dp(29.5f)); if (!openAnimationInProgress) { final boolean setVisible = diff > 0.2f && !searchMode; boolean currentVisible = writeButton.getTag() == null; if (setVisible != currentVisible) { if (setVisible) { writeButton.setTag(null); } else { writeButton.setTag(0); } if (writeButtonAnimation != null) { AnimatorSet old = writeButtonAnimation; writeButtonAnimation = null; old.cancel(); } writeButtonAnimation = new AnimatorSet(); if (setVisible) { writeButtonAnimation.setInterpolator(new DecelerateInterpolator()); writeButtonAnimation.playTogether( ObjectAnimator.ofFloat(writeButton, View.SCALE_X, 1.0f), ObjectAnimator.ofFloat(writeButton, View.SCALE_Y, 1.0f), ObjectAnimator.ofFloat(writeButton, View.ALPHA, 1.0f) ); } else { writeButtonAnimation.setInterpolator(new AccelerateInterpolator()); writeButtonAnimation.playTogether( ObjectAnimator.ofFloat(writeButton, View.SCALE_X, 0.2f), ObjectAnimator.ofFloat(writeButton, View.SCALE_Y, 0.2f), ObjectAnimator.ofFloat(writeButton, View.ALPHA, 0.0f) ); } writeButtonAnimation.setDuration(150); writeButtonAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (writeButtonAnimation != null && writeButtonAnimation.equals(animation)) { writeButtonAnimation = null; } } }); writeButtonAnimation.start(); } } } float avatarY = (actionBar.getOccupyStatusBar() ? AndroidUtilities.statusBarHeight : 0) + ActionBar.getCurrentActionBarHeight() / 2.0f * (1.0f + diff) - 21 * AndroidUtilities.density + 27 * AndroidUtilities.density * diff; avatarContainer.setScaleX((42 + 18 * diff) / 42.0f); avatarContainer.setScaleY((42 + 18 * diff) / 42.0f); avatarContainer.setTranslationX(-AndroidUtilities.dp(47) * diff); avatarContainer.setTranslationY((float) Math.ceil(avatarY)); if (nameTextView != null) { nameTextView.setTranslationX(-21 * AndroidUtilities.density * diff); onlineTextView.setTranslationX(-21 * AndroidUtilities.density * diff); nameTextView.setTranslationY((float) Math.floor(avatarY) - (float) Math.ceil(AndroidUtilities.density) + (float) Math.floor(7 * AndroidUtilities.density * diff)); onlineTextView.setTranslationY((float) Math.floor(avatarY) + AndroidUtilities.dp(22) + (float) Math.floor(11 * AndroidUtilities.density) * diff); float scale = 1.0f + 0.12f * diff; nameTextView.setScaleX(scale); nameTextView.setScaleY(scale); idTextView.setTranslationX(-21 * AndroidUtilities.density * diff); idTextView.setTranslationY((float) Math.floor(avatarY) + AndroidUtilities.dp(32) + (float) Math.floor(22 * AndroidUtilities.density) * diff); if (diff > 0.85 && !searchMode && NekoConfig.showIdAndDc) { idTextView.setVisibility(View.VISIBLE); } else { idTextView.setVisibility(View.GONE); } if (!openAnimationInProgress) { int viewWidth; if (AndroidUtilities.isTablet()) { viewWidth = AndroidUtilities.dp(490); } else { viewWidth = AndroidUtilities.displaySize.x; } int buttonsWidth = AndroidUtilities.dp(118 + 8 + 40 + 48); int minWidth = viewWidth - buttonsWidth; int width = (int) (viewWidth - buttonsWidth * Math.max(0.0f, 1.0f - (diff != 1.0f ? diff * 0.15f / (1.0f - diff) : 1.0f)) - nameTextView.getTranslationX()); float width2 = nameTextView.getPaint().measureText(nameTextView.getText().toString()) * scale; layoutParams = (FrameLayout.LayoutParams) nameTextView.getLayoutParams(); if (width < width2) { layoutParams.width = Math.max(minWidth, (int) Math.ceil((width - AndroidUtilities.dp(24)) / (scale + (1.12f - scale) * 7.0f))); } else { layoutParams.width = (int) Math.ceil(width2); } layoutParams.width = (int) Math.min((viewWidth - nameTextView.getX()) / scale - AndroidUtilities.dp(8), layoutParams.width); nameTextView.setLayoutParams(layoutParams); width2 = onlineTextView.getPaint().measureText(onlineTextView.getText().toString()); layoutParams = (FrameLayout.LayoutParams) onlineTextView.getLayoutParams(); layoutParams.rightMargin = (int) Math.ceil(onlineTextView.getTranslationX() + AndroidUtilities.dp(8) + AndroidUtilities.dp(40) * (1.0f - diff)); if (width < width2) { layoutParams.width = (int) Math.ceil(width); } else { layoutParams.width = LayoutHelper.WRAP_CONTENT; } onlineTextView.setLayoutParams(layoutParams); width2 = idTextView.getPaint().measureText(idTextView.getText().toString()); layoutParams = (FrameLayout.LayoutParams) idTextView.getLayoutParams(); layoutParams.rightMargin = (int) Math.ceil(idTextView.getTranslationX() + AndroidUtilities.dp(8) + AndroidUtilities.dp(40) * (1.0f - diff)); if (width < width2) { layoutParams.width = (int) Math.ceil(width); } else { layoutParams.width = LayoutHelper.WRAP_CONTENT; } idTextView.setLayoutParams(layoutParams); } } } } private void fixLayout() { if (fragmentView == null) { return; } fragmentView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { if (fragmentView != null) { checkListViewScroll(); needLayout(); fragmentView.getViewTreeObserver().removeOnPreDrawListener(this); } return true; } }); } private void updateUserData() { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(UserConfig.getInstance(currentAccount).getClientUserId()); if (user == null) { return; } TLRPC.FileLocation photoBig = null; if (user.photo != null) { photoBig = user.photo.photo_big; } avatarDrawable = new AvatarDrawable(user, true); avatarDrawable.setColor(Theme.getColor(Theme.key_avatar_backgroundInProfileBlue)); if (avatarImage != null) { avatarImage.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); avatarImage.getImageReceiver().setVisible(!PhotoViewer.isShowingImage(photoBig), false); nameTextView.setText(UserObject.getUserName(user)); onlineTextView.setText(LocaleController.getString("Online", R.string.Online)); avatarImage.getImageReceiver().setVisible(!PhotoViewer.isShowingImage(photoBig), false); } if (user.photo != null && user.photo.dc_id != 0) { idTextView.setText("ID: " + user.id + ", DC: " + user.photo.dc_id); } else { idTextView.setText("ID: " + user.id + ", DC: " + getMessagesController().thisDc); } int finalId = user.id; idTextView.setOnLongClickListener(v -> { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setItems(new CharSequence[]{LocaleController.getString("Copy", R.string.Copy)}, (dialogInterface, i) -> { if (i == 0) { try { AndroidUtilities.addToClipboard(String.valueOf(finalId)); Toast.makeText(getParentActivity(), LocaleController.getString("TextCopied", R.string.TextCopied), Toast.LENGTH_SHORT).show(); } catch (Exception e) { FileLog.e(e); } } }); showDialog(builder.create()); return false; }); } private void sendLogs() { File path = new File(EnvUtil.getTelegramPath(), "logs"); File logcatFile = new File(path, "NekoX-" + System.currentTimeMillis() + ".log"); FileUtil.delete(logcatFile); try { Process process = RuntimeUtil.exec("logcat", "-d"); IoUtil.copy(process, logcatFile); RuntimeUtil.exec("logcat", "-c"); ShareUtil.shareFile(getParentActivity(), logcatFile); } catch (Exception e) { AlertUtil.showToast(e); } } private class SearchAdapter extends RecyclerListView.SelectionAdapter { private class SearchResult { private String searchTitle; private Runnable openRunnable; private String rowName; private String[] path; private int iconResId; private int guid; private int num; public SearchResult(int g, String search, int icon, Runnable open) { this(g, search, null, null, null, icon, open); } public SearchResult(int g, String search, String pathArg1, int icon, Runnable open) { this(g, search, null, pathArg1, null, icon, open); } public SearchResult(int g, String search, String row, String pathArg1, int icon, Runnable open) { this(g, search, row, pathArg1, null, icon, open); } public SearchResult(int g, String search, String row, String pathArg1, String pathArg2, int icon, Runnable open) { guid = g; searchTitle = search; rowName = row; openRunnable = open; iconResId = icon; if (pathArg1 != null && pathArg2 != null) { path = new String[]{pathArg1, pathArg2}; } else if (pathArg1 != null) { path = new String[]{pathArg1}; } } @Override public boolean equals(Object obj) { if (!(obj instanceof SearchResult)) { return false; } SearchResult result = (SearchResult) obj; return guid == result.guid; } @Override public String toString() { SerializedData data = new SerializedData(); data.writeInt32(num); data.writeInt32(1); data.writeInt32(guid); return Utilities.bytesToHex(data.toByteArray()); } private void open() { openRunnable.run(); if (rowName != null) { BaseFragment openingFragment = parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 1); try { Field listViewField = openingFragment.getClass().getDeclaredField("listView"); listViewField.setAccessible(true); RecyclerListView.IntReturnCallback callback = () -> { int position = -1; try { Field rowField = openingFragment.getClass().getDeclaredField(rowName); Field linearLayoutField = openingFragment.getClass().getDeclaredField("layoutManager"); rowField.setAccessible(true); linearLayoutField.setAccessible(true); LinearLayoutManager layoutManager = (LinearLayoutManager) linearLayoutField.get(openingFragment); position = rowField.getInt(openingFragment); layoutManager.scrollToPositionWithOffset(position, 0); rowField.setAccessible(false); linearLayoutField.setAccessible(false); return position; } catch (Throwable ignore) { } return position; }; RecyclerListView listView = (RecyclerListView) listViewField.get(openingFragment); listView.highlightRow(callback); listViewField.setAccessible(false); } catch (Throwable ignore) { } } } } private class FaqSearchResult { private String title; private String[] path; private String url; private int num; public FaqSearchResult(String t, String[] p, String u) { title = t; path = p; url = u; } @Override public boolean equals(Object obj) { if (!(obj instanceof FaqSearchResult)) { return false; } FaqSearchResult result = (FaqSearchResult) obj; return title.equals(result.title); } @Override public String toString() { SerializedData data = new SerializedData(); data.writeInt32(num); data.writeInt32(0); data.writeString(title); data.writeInt32(path != null ? path.length : 0); if (path != null) { for (int a = 0; a < path.length; a++) { data.writeString(path[a]); } } data.writeString(url); return Utilities.bytesToHex(data.toByteArray()); } } private SearchResult[] searchArray = new SearchResult[]{ new SearchResult(500, LocaleController.getString("EditName", R.string.EditName), 0, () -> presentFragment(new ChangeNameActivity())), new SearchResult(501, LocaleController.getString("ChangePhoneNumber", R.string.ChangePhoneNumber), 0, () -> presentFragment(new ActionIntroActivity(ActionIntroActivity.ACTION_TYPE_CHANGE_PHONE_NUMBER))), new SearchResult(502, LocaleController.getString("AddAnotherAccount", R.string.AddAnotherAccount), 0, () -> { int freeAccount = -1; for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { if (!UserConfig.getInstance(a).isClientActivated()) { freeAccount = a; break; } } if (freeAccount >= 0) { presentFragment(new LoginActivity(freeAccount)); } }), new SearchResult(503, LocaleController.getString("UserBio", R.string.UserBio), 0, () -> { if (userInfo != null) { presentFragment(new ChangeBioActivity()); } }), new SearchResult(1, LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.baseline_notifications_24, () -> presentFragment(new NotificationsSettingsActivity())), new SearchResult(2, LocaleController.getString("NotificationsPrivateChats", R.string.NotificationsPrivateChats), LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.baseline_notifications_24, () -> presentFragment(new NotificationsCustomSettingsActivity(NotificationsController.TYPE_PRIVATE, new ArrayList<>(), true))), new SearchResult(3, LocaleController.getString("NotificationsGroups", R.string.NotificationsGroups), LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.baseline_notifications_24, () -> presentFragment(new NotificationsCustomSettingsActivity(NotificationsController.TYPE_GROUP, new ArrayList<>(), true))), new SearchResult(4, LocaleController.getString("NotificationsChannels", R.string.NotificationsChannels), LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.baseline_notifications_24, () -> presentFragment(new NotificationsCustomSettingsActivity(NotificationsController.TYPE_CHANNEL, new ArrayList<>(), true))), new SearchResult(5, LocaleController.getString("VoipNotificationSettings", R.string.VoipNotificationSettings), "callsSectionRow", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.baseline_notifications_24, () -> presentFragment(new NotificationsSettingsActivity())), new SearchResult(6, LocaleController.getString("BadgeNumber", R.string.BadgeNumber), "badgeNumberSection", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.baseline_notifications_24, () -> presentFragment(new NotificationsSettingsActivity())), new SearchResult(7, LocaleController.getString("InAppNotifications", R.string.InAppNotifications), "inappSectionRow", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.baseline_notifications_24, () -> presentFragment(new NotificationsSettingsActivity())), new SearchResult(8, LocaleController.getString("ContactJoined", R.string.ContactJoined), "contactJoinedRow", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.baseline_notifications_24, () -> presentFragment(new NotificationsSettingsActivity())), new SearchResult(9, LocaleController.getString("PinnedMessages", R.string.PinnedMessages), "pinnedMessageRow", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.baseline_notifications_24, () -> presentFragment(new NotificationsSettingsActivity())), new SearchResult(10, LocaleController.getString("ResetAllNotifications", R.string.ResetAllNotifications), "resetNotificationsRow", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.baseline_notifications_24, () -> presentFragment(new NotificationsSettingsActivity())), new SearchResult(100, LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new PrivacySettingsActivity())), new SearchResult(101, LocaleController.getString("BlockedUsers", R.string.BlockedUsers), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new PrivacyUsersActivity())), new SearchResult(105, LocaleController.getString("PrivacyPhone", R.string.PrivacyPhone), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_PHONE, true))), new SearchResult(102, LocaleController.getString("PrivacyLastSeen", R.string.PrivacyLastSeen), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_LASTSEEN, true))), new SearchResult(103, LocaleController.getString("PrivacyProfilePhoto", R.string.PrivacyProfilePhoto), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_PHOTO, true))), new SearchResult(104, LocaleController.getString("PrivacyForwards", R.string.PrivacyForwards), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_FORWARDS, true))), new SearchResult(105, LocaleController.getString("PrivacyP2P", R.string.PrivacyP2P), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_P2P, true))), new SearchResult(106, LocaleController.getString("Calls", R.string.Calls), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_CALLS, true))), new SearchResult(107, LocaleController.getString("GroupsAndChannels", R.string.GroupsAndChannels), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_INVITE, true))), new SearchResult(108, LocaleController.getString("Passcode", R.string.Passcode), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new PasscodeActivity(SharedConfig.passcodeHash.length() > 0 ? 2 : 0))), new SearchResult(109, LocaleController.getString("TwoStepVerification", R.string.TwoStepVerification), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new TwoStepVerificationActivity())), new SearchResult(110, LocaleController.getString("SessionsTitle", R.string.SessionsTitle), R.drawable.baseline_security_24, () -> presentFragment(new SessionsActivity(0))), new SearchResult(111, LocaleController.getString("PrivacyDeleteCloudDrafts", R.string.PrivacyDeleteCloudDrafts), "clearDraftsRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new PrivacySettingsActivity())), new SearchResult(112, LocaleController.getString("DeleteAccountIfAwayFor2", R.string.DeleteAccountIfAwayFor2), "deleteAccountRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new PrivacySettingsActivity())), new SearchResult(113, LocaleController.getString("PrivacyPaymentsClear", R.string.PrivacyPaymentsClear), "paymentsClearRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new PrivacySettingsActivity())), new SearchResult(114, LocaleController.getString("WebSessionsTitle", R.string.WebSessionsTitle), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new SessionsActivity(1))), new SearchResult(115, LocaleController.getString("SyncContactsDelete", R.string.SyncContactsDelete), "contactsDeleteRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new PrivacySettingsActivity())), new SearchResult(116, LocaleController.getString("SyncContacts", R.string.SyncContacts), "contactsSyncRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new PrivacySettingsActivity())), new SearchResult(117, LocaleController.getString("SuggestContacts", R.string.SuggestContacts), "contactsSuggestRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new PrivacySettingsActivity())), new SearchResult(118, LocaleController.getString("MapPreviewProvider", R.string.MapPreviewProvider), "secretMapRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new PrivacySettingsActivity())), new SearchResult(119, LocaleController.getString("SecretWebPage", R.string.SecretWebPage), "secretWebpageRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_security_24, () -> presentFragment(new PrivacySettingsActivity())), new SearchResult(120, LocaleController.getString("Devices", R.string.Devices), R.drawable.baseline_security_24, () -> presentFragment(new SessionsActivity(0))), new SearchResult(200, LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new DataSettingsActivity())), new SearchResult(201, LocaleController.getString("DataUsage", R.string.DataUsage), "usageSectionRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new DataSettingsActivity())), new SearchResult(202, LocaleController.getString("StorageUsage", R.string.StorageUsage), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new CacheControlActivity())), new SearchResult(203, LocaleController.getString("KeepMedia", R.string.KeepMedia), "keepMediaRow", LocaleController.getString("DataSettings", R.string.DataSettings), LocaleController.getString("StorageUsage", R.string.StorageUsage), R.drawable.baseline_data_usage_24, () -> presentFragment(new CacheControlActivity())), new SearchResult(204, LocaleController.getString("ClearMediaCache", R.string.ClearMediaCache), "cacheRow", LocaleController.getString("DataSettings", R.string.DataSettings), LocaleController.getString("StorageUsage", R.string.StorageUsage), R.drawable.baseline_data_usage_24, () -> presentFragment(new CacheControlActivity())), new SearchResult(205, LocaleController.getString("LocalDatabase", R.string.LocalDatabase), "databaseRow", LocaleController.getString("DataSettings", R.string.DataSettings), LocaleController.getString("StorageUsage", R.string.StorageUsage), R.drawable.baseline_data_usage_24, () -> presentFragment(new CacheControlActivity())), new SearchResult(206, LocaleController.getString("NetworkUsage", R.string.NetworkUsage), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new DataUsageActivity())), new SearchResult(207, LocaleController.getString("AutomaticMediaDownload", R.string.AutomaticMediaDownload), "mediaDownloadSectionRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new DataSettingsActivity())), new SearchResult(208, LocaleController.getString("WhenUsingMobileData", R.string.WhenUsingMobileData), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new DataAutoDownloadActivity(0))), new SearchResult(209, LocaleController.getString("WhenConnectedOnWiFi", R.string.WhenConnectedOnWiFi), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new DataAutoDownloadActivity(1))), new SearchResult(210, LocaleController.getString("WhenRoaming", R.string.WhenRoaming), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new DataAutoDownloadActivity(2))), new SearchResult(211, LocaleController.getString("ResetAutomaticMediaDownload", R.string.ResetAutomaticMediaDownload), "resetDownloadRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new DataSettingsActivity())), new SearchResult(212, LocaleController.getString("AutoplayMedia", R.string.AutoplayMedia), "autoplayHeaderRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new DataSettingsActivity())), new SearchResult(213, LocaleController.getString("AutoplayGIF", R.string.AutoplayGIF), "autoplayGifsRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new DataSettingsActivity())), new SearchResult(214, LocaleController.getString("AutoplayVideo", R.string.AutoplayVideo), "autoplayVideoRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new DataSettingsActivity())), new SearchResult(215, LocaleController.getString("Streaming", R.string.Streaming), "streamSectionRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new DataSettingsActivity())), new SearchResult(216, LocaleController.getString("EnableStreaming", R.string.EnableStreaming), "enableStreamRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new DataSettingsActivity())), new SearchResult(217, LocaleController.getString("Calls", R.string.Calls), "callsSectionRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new DataSettingsActivity())), new SearchResult(218, LocaleController.getString("VoipUseLessData", R.string.VoipUseLessData), "useLessDataForCallsRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new DataSettingsActivity())), new SearchResult(219, LocaleController.getString("VoipQuickReplies", R.string.VoipQuickReplies), "quickRepliesRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new DataSettingsActivity())), new SearchResult(220, LocaleController.getString("ProxySettings", R.string.ProxySettings), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new ProxyListActivity())), new SearchResult(221, LocaleController.getString("UseProxyForCalls", R.string.UseProxyForCalls), "callsRow", LocaleController.getString("DataSettings", R.string.DataSettings), LocaleController.getString("ProxySettings", R.string.ProxySettings), R.drawable.baseline_data_usage_24, () -> presentFragment(new ProxyListActivity())), new SearchResult(300, LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), new SearchResult(301, LocaleController.getString("TextSizeHeader", R.string.TextSizeHeader), "textSizeHeaderRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), new SearchResult(302, LocaleController.getString("ChatBackground", R.string.ChatBackground), LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new WallpapersListActivity(WallpapersListActivity.TYPE_ALL))), new SearchResult(303, LocaleController.getString("SetColor", R.string.SetColor), null, LocaleController.getString("ChatSettings", R.string.ChatSettings), LocaleController.getString("ChatBackground", R.string.ChatBackground), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new WallpapersListActivity(WallpapersListActivity.TYPE_COLOR))), new SearchResult(304, LocaleController.getString("ResetChatBackgrounds", R.string.ResetChatBackgrounds), "resetRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), LocaleController.getString("ChatBackground", R.string.ChatBackground), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new WallpapersListActivity(WallpapersListActivity.TYPE_ALL))), new SearchResult(305, LocaleController.getString("AutoNightTheme", R.string.AutoNightTheme), LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_NIGHT))), new SearchResult(306, LocaleController.getString("ColorTheme", R.string.ColorTheme), "themeHeaderRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), new SearchResult(307, LocaleController.getString("ChromeCustomTabs", R.string.ChromeCustomTabs), "customTabsRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), new SearchResult(308, LocaleController.getString("DirectShare", R.string.DirectShare), "directShareRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), new SearchResult(309, LocaleController.getString("EnableAnimations", R.string.EnableAnimations), "enableAnimationsRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), new SearchResult(310, LocaleController.getString("RaiseToSpeak", R.string.RaiseToSpeak), "raiseToSpeakRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), new SearchResult(311, LocaleController.getString("SendByEnter", R.string.SendByEnter), "sendByEnterRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), new SearchResult(312, LocaleController.getString("SaveToGallerySettings", R.string.SaveToGallerySettings), "saveToGalleryRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), new SearchResult(312, LocaleController.getString("DistanceUnits", R.string.DistanceUnits), "distanceRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), new SearchResult(313, LocaleController.getString("StickersAndMasks", R.string.StickersAndMasks), LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new StickersActivity(MediaDataController.TYPE_IMAGE))), new SearchResult(314, LocaleController.getString("SuggestStickers", R.string.SuggestStickers), "suggestRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), LocaleController.getString("StickersAndMasks", R.string.StickersAndMasks), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new StickersActivity(MediaDataController.TYPE_IMAGE))), new SearchResult(315, LocaleController.getString("FeaturedStickers", R.string.FeaturedStickers), null, LocaleController.getString("ChatSettings", R.string.ChatSettings), LocaleController.getString("StickersAndMasks", R.string.StickersAndMasks), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new FeaturedStickersActivity())), new SearchResult(316, LocaleController.getString("Masks", R.string.Masks), null, LocaleController.getString("ChatSettings", R.string.ChatSettings), LocaleController.getString("StickersAndMasks", R.string.StickersAndMasks), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new StickersActivity(MediaDataController.TYPE_MASK))), new SearchResult(317, LocaleController.getString("ArchivedStickers", R.string.ArchivedStickers), null, LocaleController.getString("ChatSettings", R.string.ChatSettings), LocaleController.getString("StickersAndMasks", R.string.StickersAndMasks), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new ArchivedStickersActivity(MediaDataController.TYPE_IMAGE))), new SearchResult(317, LocaleController.getString("ArchivedMasks", R.string.ArchivedMasks), null, LocaleController.getString("ChatSettings", R.string.ChatSettings), LocaleController.getString("StickersAndMasks", R.string.StickersAndMasks), R.drawable.baseline_chat_bubble_24, () -> presentFragment(new ArchivedStickersActivity(MediaDataController.TYPE_MASK))), new SearchResult(400, LocaleController.getString("Language", R.string.Language), R.drawable.baseline_language_24, () -> presentFragment(new LanguageSelectActivity())), new SearchResult(402, LocaleController.getString("AskAQuestion", R.string.AskAQuestion), LocaleController.getString("SettingsHelp", R.string.SettingsHelp), R.drawable.baseline_help_24, () -> showDialog(AlertsCreator.createSupportAlert(SettingsActivity.this))), new SearchResult(403, LocaleController.getString("TelegramFAQ", R.string.TelegramFAQ), LocaleController.getString("SettingsHelp", R.string.SettingsHelp), R.drawable.baseline_help_24, () -> Browser.openUrl(getParentActivity(), LocaleController.getString("TelegramFaqUrl", R.string.TelegramFaqUrl))), new SearchResult(404, LocaleController.getString("PrivacyPolicy", R.string.PrivacyPolicy), LocaleController.getString("SettingsHelp", R.string.SettingsHelp), R.drawable.baseline_help_24, () -> Browser.openUrl(getParentActivity(), LocaleController.getString("PrivacyPolicyUrl", R.string.PrivacyPolicyUrl))), }; private ArrayList faqSearchArray = new ArrayList<>(); private Context mContext; private ArrayList resultNames = new ArrayList<>(); private ArrayList searchResults = new ArrayList<>(); private ArrayList faqSearchResults = new ArrayList<>(); private ArrayList recentSearches = new ArrayList<>(); private boolean searchWas; private Runnable searchRunnable; private String lastSearchString; private TLRPC.WebPage faqWebPage; private boolean loadingFaqPage; public SearchAdapter(Context context) { mContext = context; HashMap resultHashMap = new HashMap<>(); for (int a = 0; a < searchArray.length; a++) { resultHashMap.put(searchArray[a].guid, searchArray[a]); } Set set = MessagesController.getGlobalMainSettings().getStringSet("settingsSearchRecent2", null); if (set != null) { for (String value : set) { try { SerializedData data = new SerializedData(Utilities.hexToBytes(value)); int num = data.readInt32(false); int type = data.readInt32(false); if (type == 0) { String title = data.readString(false); int count = data.readInt32(false); String[] path = null; if (count > 0) { path = new String[count]; for (int a = 0; a < count; a++) { path[a] = data.readString(false); } } String url = data.readString(false); FaqSearchResult result = new FaqSearchResult(title, path, url); result.num = num; recentSearches.add(result); } else if (type == 1) { SearchResult result = resultHashMap.get(data.readInt32(false)); if (result != null) { result.num = num; recentSearches.add(result); } } } catch (Exception ignore) { } } } Collections.sort(recentSearches, (o1, o2) -> { int n1 = getNum(o1); int n2 = getNum(o2); if (n1 < n2) { return -1; } else if (n1 > n2) { return 1; } return 0; }); } private void loadFaqWebPage() { if (faqWebPage != null || loadingFaqPage) { return; } loadingFaqPage = true; final TLRPC.TL_messages_getWebPage req2 = new TLRPC.TL_messages_getWebPage(); req2.url = NekoXConfig.FAQ_URL; req2.hash = 0; ConnectionsManager.getInstance(currentAccount).sendRequest(req2, (response2, error2) -> { if (response2 instanceof TLRPC.WebPage) { TLRPC.WebPage page = (TLRPC.WebPage) response2; if (page.cached_page != null) { for (int a = 0, N = page.cached_page.blocks.size(); a < N; a++) { TLRPC.PageBlock block = page.cached_page.blocks.get(a); if (block instanceof TLRPC.TL_pageBlockList) { String paragraph = null; if (a != 0) { TLRPC.PageBlock prevBlock = page.cached_page.blocks.get(a - 1); if (prevBlock instanceof TLRPC.TL_pageBlockParagraph) { TLRPC.TL_pageBlockParagraph pageBlockParagraph = (TLRPC.TL_pageBlockParagraph) prevBlock; paragraph = ArticleViewer.getPlainText(pageBlockParagraph.text).toString(); } } TLRPC.TL_pageBlockList list = (TLRPC.TL_pageBlockList) block; for (int b = 0, N2 = list.items.size(); b < N2; b++) { TLRPC.PageListItem item = list.items.get(b); if (item instanceof TLRPC.TL_pageListItemText) { TLRPC.TL_pageListItemText itemText = (TLRPC.TL_pageListItemText) item; String url = ArticleViewer.getUrl(itemText.text); String text = ArticleViewer.getPlainText(itemText.text).toString(); if (TextUtils.isEmpty(url) || TextUtils.isEmpty(text)) { continue; } String[] path; if (paragraph != null) { path = new String[]{LocaleController.getString("SettingsSearchFaq", R.string.SettingsSearchFaq), paragraph}; } else { path = new String[]{LocaleController.getString("SettingsSearchFaq", R.string.SettingsSearchFaq)}; } faqSearchArray.add(new FaqSearchResult(text, path, url)); } } } else if (block instanceof TLRPC.TL_pageBlockAnchor) { break; } } faqWebPage = page; } } loadingFaqPage = false; }); } @Override public int getItemCount() { if (searchWas) { return searchResults.size() + (faqSearchResults.isEmpty() ? 0 : 1 + faqSearchResults.size()); } return (recentSearches.isEmpty() ? 0 : recentSearches.size() + 1); } @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { return holder.getItemViewType() == 0; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { case 0: { SettingsSearchCell searchCell = (SettingsSearchCell) holder.itemView; if (searchWas) { if (position < searchResults.size()) { SearchResult result = searchResults.get(position); SearchResult prevResult = position > 0 ? searchResults.get(position - 1) : null; int icon; if (prevResult != null && prevResult.iconResId == result.iconResId) { icon = 0; } else { icon = result.iconResId; } searchCell.setTextAndValueAndIcon(resultNames.get(position), result.path, icon, position < searchResults.size() - 1); } else { position -= searchResults.size() + 1; FaqSearchResult result = faqSearchResults.get(position); searchCell.setTextAndValue(resultNames.get(position + searchResults.size()), result.path, true, position < searchResults.size() - 1); } } else { position--; Object object = recentSearches.get(position); if (object instanceof SearchResult) { SearchResult result = (SearchResult) object; searchCell.setTextAndValue(result.searchTitle, result.path, false, position < recentSearches.size() - 1); } else if (object instanceof FaqSearchResult) { FaqSearchResult result = (FaqSearchResult) object; searchCell.setTextAndValue(result.title, result.path, true, position < recentSearches.size() - 1); } } break; } case 1: { GraySectionCell sectionCell = (GraySectionCell) holder.itemView; sectionCell.setText(LocaleController.getString("SettingsFaqSearchTitle", R.string.SettingsFaqSearchTitle)); break; } case 2: { HeaderCell headerCell = (HeaderCell) holder.itemView; headerCell.setText(LocaleController.getString("SettingsRecent", R.string.SettingsRecent)); break; } } } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view; switch (viewType) { case 0: view = new SettingsSearchCell(mContext); break; case 1: view = new GraySectionCell(mContext); break; case 2: default: view = new HeaderCell(mContext, 16); break; } view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT)); return new RecyclerListView.Holder(view); } @Override public int getItemViewType(int position) { if (searchWas) { if (position < searchResults.size()) { return 0; } else if (position == searchResults.size()) { return 1; } return 0; } else { if (position == 0) { return 2; } return 0; } } public void addRecent(Object object) { int index = recentSearches.indexOf(object); if (index >= 0) { recentSearches.remove(index); } recentSearches.add(0, object); if (!searchWas) { notifyDataSetChanged(); } if (recentSearches.size() > 20) { recentSearches.remove(recentSearches.size() - 1); } LinkedHashSet toSave = new LinkedHashSet<>(); for (int a = 0, N = recentSearches.size(); a < N; a++) { Object o = recentSearches.get(a); if (o instanceof SearchResult) { ((SearchResult) o).num = a; } else if (o instanceof FaqSearchResult) { ((FaqSearchResult) o).num = a; } toSave.add(o.toString()); } MessagesController.getGlobalMainSettings().edit().putStringSet("settingsSearchRecent2", toSave).commit(); } public void clearRecent() { recentSearches.clear(); MessagesController.getGlobalMainSettings().edit().remove("settingsSearchRecent2").commit(); notifyDataSetChanged(); } private int getNum(Object o) { if (o instanceof SearchResult) { return ((SearchResult) o).num; } else if (o instanceof FaqSearchResult) { return ((FaqSearchResult) o).num; } return 0; } public void search(String text) { lastSearchString = text; if (searchRunnable != null) { Utilities.searchQueue.cancelRunnable(searchRunnable); searchRunnable = null; } if (TextUtils.isEmpty(text)) { searchWas = false; searchResults.clear(); faqSearchResults.clear(); resultNames.clear(); emptyView.setTopImage(0); emptyView.setText(LocaleController.getString("SettingsNoRecent", R.string.SettingsNoRecent)); notifyDataSetChanged(); return; } Utilities.searchQueue.postRunnable(searchRunnable = () -> { ArrayList results = new ArrayList<>(); ArrayList faqResults = new ArrayList<>(); ArrayList names = new ArrayList<>(); String[] searchArgs = text.split(" "); String[] translitArgs = new String[searchArgs.length]; for (int a = 0; a < searchArgs.length; a++) { translitArgs[a] = LocaleController.getInstance().getTranslitString(searchArgs[a]); if (translitArgs[a].equals(searchArgs[a])) { translitArgs[a] = null; } } for (int a = 0; a < searchArray.length; a++) { SearchResult result = searchArray[a]; String title = " " + result.searchTitle.toLowerCase(); SpannableStringBuilder stringBuilder = null; for (int i = 0; i < searchArgs.length; i++) { if (searchArgs[i].length() != 0) { String searchString = searchArgs[i]; int index = title.indexOf(" " + searchString); if (index < 0 && translitArgs[i] != null) { searchString = translitArgs[i]; index = title.indexOf(" " + searchString); } if (index >= 0) { if (stringBuilder == null) { stringBuilder = new SpannableStringBuilder(result.searchTitle); } stringBuilder.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4)), index, index + searchString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else { break; } } if (stringBuilder != null && i == searchArgs.length - 1) { if (result.guid == 502) { int freeAccount = -1; for (int b = 0; b < UserConfig.MAX_ACCOUNT_COUNT; b++) { if (!UserConfig.getInstance(a).isClientActivated()) { freeAccount = b; break; } } if (freeAccount < 0) { continue; } } results.add(result); names.add(stringBuilder); } } } if (faqWebPage != null) { for (int a = 0, N = faqSearchArray.size(); a < N; a++) { FaqSearchResult result = faqSearchArray.get(a); String title = " " + result.title.toLowerCase(); SpannableStringBuilder stringBuilder = null; for (int i = 0; i < searchArgs.length; i++) { if (searchArgs[i].length() != 0) { String searchString = searchArgs[i]; int index = title.indexOf(" " + searchString); if (index < 0 && translitArgs[i] != null) { searchString = translitArgs[i]; index = title.indexOf(" " + searchString); } if (index >= 0) { if (stringBuilder == null) { stringBuilder = new SpannableStringBuilder(result.title); } stringBuilder.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4)), index, index + searchString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else { break; } } if (stringBuilder != null && i == searchArgs.length - 1) { faqResults.add(result); names.add(stringBuilder); } } } } AndroidUtilities.runOnUIThread(() -> { if (!text.equals(lastSearchString)) { return; } if (!searchWas) { emptyView.setTopImage(R.drawable.settings_noresults); emptyView.setText(LocaleController.getString("SettingsNoResults", R.string.SettingsNoResults)); } searchWas = true; searchResults = results; faqSearchResults = faqResults; resultNames = names; notifyDataSetChanged(); }); }, 300); } public boolean isSearchWas() { return searchWas; } } private class ListAdapter extends RecyclerListView.SelectionAdapter { private Context mContext; public ListAdapter(Context context) { mContext = context; } @Override public int getItemCount() { return rowCount; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { case 2: { TextCell textCell = (TextCell) holder.itemView; if (position == languageRow) { textCell.setTextAndIcon(LocaleController.getString("Language", R.string.Language), R.drawable.baseline_language_24, false); } else if (position == notificationRow) { textCell.setTextAndIcon(LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.baseline_notifications_24, true); } else if (position == privacyRow) { textCell.setTextAndIcon(LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.baseline_lock_24, true); } else if (position == dataRow) { textCell.setTextAndIcon(LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.baseline_data_usage_24, true); } else if (position == chatRow) { textCell.setTextAndIcon(LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.baseline_palette_24, true); } else if (position == stickersRow) { textCell.setTextAndIcon(LocaleController.getString("StickersAndMasks", R.string.StickersAndMasks), R.drawable.deproko_baseline_stickers_24, true); } else if (position == nekoRow) { textCell.setTextAndIcon(LocaleController.getString("NekoSettings", R.string.NekoSettings), R.drawable.baseline_extension_24, true); } else if (position == filtersRow) { textCell.setTextAndIcon(LocaleController.getString("Filters", R.string.Filters), R.drawable.baseline_folder_24, true); } else if (position == questionRow) { textCell.setTextAndIcon(LocaleController.getString("NekoXUpdatesChannel", R.string.NekoXUpdatesChannel), R.drawable.baseline_bullhorn_24, true); } else if (position == faqRow) { textCell.setTextAndIcon(LocaleController.getString("NekoXFaq", R.string.NekoXFaq), R.drawable.baseline_help_24, true); } else if (position == sendLogsRow) { textCell.setTextAndIcon(LocaleController.getString("DebugSendLogs", R.string.DebugSendLogs), R.drawable.baseline_bug_report_24, true); } else if (position == clearLogsRow) { textCell.setTextAndIcon(LocaleController.getString("DebugClearLogs", R.string.DebugClearLogs), R.drawable.baseline_delete_sweep_24, switchBackendRow != -1); } else if (position == switchBackendRow) { textCell.setText("Switch Backend", false); } break; } case 4: { HeaderCell headerCell = (HeaderCell) holder.itemView; if (position == settingsSectionRow2) { headerCell.setText(LocaleController.getString("SETTINGS", R.string.SETTINGS)); } else if (position == numberSectionRow) { headerCell.setText(LocaleController.getString("Account", R.string.Account)); } else if (position == helpHeaderRow) { headerCell.setText(LocaleController.getString("SettingsHelp", R.string.SettingsHelp)); } else if (position == debugHeaderRow) { headerCell.setText(LocaleController.getString("SettingsDebug", R.string.SettingsDebug)); } break; } case 6: { TextDetailCell textCell = (TextDetailCell) holder.itemView; if (position == numberRow) { TLRPC.User user = UserConfig.getInstance(currentAccount).getCurrentUser(); String value; if (user != null && user.phone != null && user.phone.length() != 0) { value = PhoneFormat.getInstance().format("+" + user.phone); } else { value = LocaleController.getString("NumberUnknown", R.string.NumberUnknown); } textCell.setTextAndValue(value, LocaleController.getString("TapToChangePhone", R.string.TapToChangePhone), true); } else if (position == usernameRow) { TLRPC.User user = UserConfig.getInstance(currentAccount).getCurrentUser(); String value; if (user != null && !TextUtils.isEmpty(user.username)) { value = "@" + user.username; } else { value = LocaleController.getString("UsernameEmpty", R.string.UsernameEmpty); } textCell.setTextAndValue(value, LocaleController.getString("Username", R.string.Username), true); } else if (position == bioRow) { String value; if (userInfo == null || !TextUtils.isEmpty(userInfo.about)) { value = userInfo == null ? LocaleController.getString("Loading", R.string.Loading) : userInfo.about; textCell.setTextWithEmojiAndValue(value, LocaleController.getString("UserBio", R.string.UserBio), false); currentBio = userInfo != null ? userInfo.about : null; } else { textCell.setTextAndValue(LocaleController.getString("UserBio", R.string.UserBio), LocaleController.getString("UserBioDetail", R.string.UserBioDetail), false); currentBio = null; } } break; } } } @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { int position = holder.getAdapterPosition(); return position == notificationRow || position == numberRow || position == privacyRow || position == languageRow || position == usernameRow || position == bioRow || position == versionRow || position == dataRow || position == chatRow || position == stickersRow || position == questionRow || position == devicesRow || position == filtersRow || position == faqRow || position == policyRow || position == sendLogsRow || position == clearLogsRow || position == switchBackendRow || position == nekoRow; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = null; switch (viewType) { case 0: view = new EmptyCell(mContext, LocaleController.isRTL ? 46 : 36); break; case 1: { view = new ShadowSectionCell(mContext); Drawable drawable = Theme.getThemedDrawable(mContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow); CombinedDrawable combinedDrawable = new CombinedDrawable(new ColorDrawable(Theme.getColor(Theme.key_windowBackgroundGray)), drawable); combinedDrawable.setFullsize(true); view.setBackgroundDrawable(combinedDrawable); break; } case 2: view = new TextCell(mContext); break; case 4: view = new HeaderCell(mContext, 23); break; case 5: { TextInfoPrivacyCell cell = new TextInfoPrivacyCell(mContext, 10); cell.getTextView().setGravity(Gravity.CENTER_HORIZONTAL); cell.getTextView().setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText3)); cell.getTextView().setMovementMethod(null); cell.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); String abi = FileUtil.getAbi(); cell.setText(String.format("%1$s %2$s", LocaleController.getString("NekoX", R.string.NekoX), String.format(Locale.US, "v%s %s %s", BuildConfig.VERSION_NAME, abi, BuildConfig.BUILD_TYPE))); cell.getTextView().setPadding(0, AndroidUtilities.dp(14), 0, AndroidUtilities.dp(14)); view = cell; Drawable drawable = Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow); CombinedDrawable combinedDrawable = new CombinedDrawable(new ColorDrawable(Theme.getColor(Theme.key_windowBackgroundGray)), drawable); combinedDrawable.setFullsize(true); view.setBackgroundDrawable(combinedDrawable); break; } case 6: view = new TextDetailCell(mContext); break; } view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT)); return new RecyclerListView.Holder(view); } @Override public int getItemViewType(int position) { if (position == emptyRow) { return 0; } else if (position == settingsSectionRow || position == devicesSectionRow || position == helpSectionCell) { return 1; } else if (position == notificationRow || position == privacyRow || position == languageRow || position == dataRow || position == chatRow || position == questionRow || position == devicesRow || position == filtersRow || position == faqRow || position == policyRow || position == sendLogsRow || position == clearLogsRow || position == switchBackendRow || position == nekoRow || position == stickersRow) { return 2; } else if (position == versionRow) { return 5; } else if (position == numberRow || position == usernameRow || position == bioRow) { return 6; } else if (position == settingsSectionRow2 || position == numberSectionRow || position == helpHeaderRow || position == debugHeaderRow) { return 4; } else { return 2; } } } @Override public ArrayList getThemeDescriptions() { ArrayList themeDescriptions = new ArrayList<>(); themeDescriptions.add(new ThemeDescription(fragmentView, 0, null, null, null, null, Theme.key_windowBackgroundWhite)); themeDescriptions.add(new ThemeDescription(fragmentView, 0, null, null, null, null, Theme.key_windowBackgroundGray)); themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_avatar_backgroundActionBarBlue)); themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_LISTGLOWCOLOR, null, null, null, null, Theme.key_avatar_backgroundActionBarBlue)); themeDescriptions.add(new ThemeDescription(topView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_avatar_backgroundActionBarBlue)); themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_ITEMSCOLOR, null, null, null, null, Theme.key_avatar_actionBarIconBlue)); themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_TITLECOLOR, null, null, null, null, Theme.key_actionBarDefaultTitle)); themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SELECTORCOLOR, null, null, null, null, Theme.key_avatar_actionBarSelectorBlue)); themeDescriptions.add(new ThemeDescription(nameTextView, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_profile_title)); themeDescriptions.add(new ThemeDescription(onlineTextView, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_profile_status)); themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SUBMENUBACKGROUND, null, null, null, null, Theme.key_actionBarDefaultSubmenuBackground)); themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SUBMENUITEM, null, null, null, null, Theme.key_actionBarDefaultSubmenuItem)); themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SUBMENUITEM | ThemeDescription.FLAG_IMAGECOLOR, null, null, null, null, Theme.key_actionBarDefaultSubmenuItemIcon)); themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_SELECTOR, null, null, null, null, Theme.key_listSelector)); themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{View.class}, Theme.dividerPaint, null, null, Theme.key_divider)); themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{ShadowSectionCell.class}, null, null, null, Theme.key_windowBackgroundGrayShadow)); themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_BACKGROUNDFILTER | ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{ShadowSectionCell.class}, null, null, null, Theme.key_windowBackgroundGray)); themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCell.class}, new String[]{"valueTextView"}, null, null, null, Theme.key_windowBackgroundWhiteValueText)); themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayIcon)); themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{HeaderCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader)); themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextDetailCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextDetailCell.class}, new String[]{"valueTextView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText2)); themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{TextInfoPrivacyCell.class}, null, null, null, Theme.key_windowBackgroundGrayShadow)); themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_BACKGROUNDFILTER | ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{TextInfoPrivacyCell.class}, null, null, null, Theme.key_windowBackgroundGray)); themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{TextInfoPrivacyCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText4)); themeDescriptions.add(new ThemeDescription(avatarImage, 0, null, null, Theme.avatarDrawables, null, Theme.key_avatar_text)); themeDescriptions.add(new ThemeDescription(avatarImage, 0, null, null, new Drawable[]{avatarDrawable}, null, Theme.key_avatar_backgroundInProfileBlue)); themeDescriptions.add(new ThemeDescription(writeButton, ThemeDescription.FLAG_IMAGECOLOR, null, null, null, null, Theme.key_profile_actionIcon)); themeDescriptions.add(new ThemeDescription(writeButton, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, null, null, Theme.key_profile_actionBackground)); themeDescriptions.add(new ThemeDescription(writeButton, ThemeDescription.FLAG_BACKGROUNDFILTER | ThemeDescription.FLAG_DRAWABLESELECTEDSTATE, null, null, null, null, Theme.key_profile_actionPressedBackground)); themeDescriptions.add(new ThemeDescription(searchListView, 0, new Class[]{HeaderCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader)); themeDescriptions.add(new ThemeDescription(searchListView, 0, new Class[]{GraySectionCell.class}, new String[]{"textView"}, null, null, null, Theme.key_graySectionText)); themeDescriptions.add(new ThemeDescription(searchListView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{GraySectionCell.class}, null, null, null, Theme.key_graySection)); themeDescriptions.add(new ThemeDescription(searchListView, 0, new Class[]{SettingsSearchCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); themeDescriptions.add(new ThemeDescription(searchListView, 0, new Class[]{SettingsSearchCell.class}, new String[]{"valueTextView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayText2)); themeDescriptions.add(new ThemeDescription(searchListView, 0, new Class[]{SettingsSearchCell.class}, new String[]{"imageView"}, null, null, null, Theme.key_windowBackgroundWhiteGrayIcon)); return themeDescriptions; } }