/* * Twidere - Twitter client for Android * * Copyright (C) 2012-2014 Mariotaku Lee * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.mariotaku.twidere.fragment import android.app.Dialog import android.content.ContentValues import android.os.Bundle import androidx.fragment.app.FragmentManager import androidx.appcompat.app.AlertDialog import com.twitter.Extractor import org.mariotaku.kpreferences.get import org.mariotaku.twidere.R import org.mariotaku.twidere.constant.IntentConstants.EXTRA_STATUS import org.mariotaku.twidere.constant.nameFirstKey import org.mariotaku.twidere.extension.applyTheme import org.mariotaku.twidere.extension.onShow import org.mariotaku.twidere.model.ParcelableStatus import org.mariotaku.twidere.model.ParcelableUserMention import org.mariotaku.twidere.model.UserKey import org.mariotaku.twidere.provider.TwidereDataStore.Filters import org.mariotaku.twidere.util.ContentValuesCreator import org.mariotaku.twidere.util.HtmlEscapeHelper import org.mariotaku.twidere.util.ParseUtils import org.mariotaku.twidere.util.UserColorNameManager import org.mariotaku.twidere.util.content.ContentResolverUtils import java.util.* class AddStatusFilterDialogFragment : BaseDialogFragment() { private val extractor = Extractor() private var filterItems: Array? = null override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val builder = AlertDialog.Builder(requireContext()) filterItems = filterItemsInfo val entries = arrayOfNulls(filterItems!!.size) val nameFirst = preferences[nameFirstKey] for (i in entries.indices) { val info = filterItems!![i] when (info.type) { FilterItemInfo.FILTER_TYPE_USER -> { entries[i] = getString(R.string.user_filter_name, getName(userColorNameManager, info.value, nameFirst)) } FilterItemInfo.FILTER_TYPE_KEYWORD -> { entries[i] = getString(R.string.keyword_filter_name, getName(userColorNameManager, info.value, nameFirst)) } FilterItemInfo.FILTER_TYPE_SOURCE -> { entries[i] = getString(R.string.source_filter_name, getName(userColorNameManager, info.value, nameFirst)) } } } builder.setTitle(R.string.action_add_to_filter) builder.setMultiChoiceItems(entries, null, null) builder.setPositiveButton(android.R.string.ok) { dialog, _ -> val alertDialog = dialog as AlertDialog val checkPositions = alertDialog.listView.checkedItemPositions val userKeys = HashSet() val keywords = HashSet() val sources = HashSet() val userValues = ArrayList() val keywordValues = ArrayList() val sourceValues = ArrayList() loop@ for (i in 0 until checkPositions.size()) { if (!checkPositions.valueAt(i)) { continue@loop } val info = filterItems!![checkPositions.keyAt(i)] val value = info.value when { value is ParcelableUserMention -> { userKeys.add(value.key) userValues.add(ContentValuesCreator.createFilteredUser(value)) } value is UserItem -> { userKeys.add(value.key) userValues.add(createFilteredUser(value)) } info.type == FilterItemInfo.FILTER_TYPE_KEYWORD -> { val keyword = ParseUtils.parseString(value) keywords.add(keyword) val values = ContentValues() values.put(Filters.Keywords.VALUE, "#$keyword") keywordValues.add(values) } info.type == FilterItemInfo.FILTER_TYPE_SOURCE -> { val source = ParseUtils.parseString(value) sources.add(source) val values = ContentValues() values.put(Filters.Sources.VALUE, source) sourceValues.add(values) } } } context?.contentResolver?.let { resolver -> ContentResolverUtils.bulkDelete(resolver, Filters.Users.CONTENT_URI, Filters.Users.USER_KEY, false, userKeys, null, null) ContentResolverUtils.bulkDelete(resolver, Filters.Keywords.CONTENT_URI, Filters.Keywords.VALUE, false, keywords, null, null) ContentResolverUtils.bulkDelete(resolver, Filters.Sources.CONTENT_URI, Filters.Sources.VALUE, false, sources, null, null) ContentResolverUtils.bulkInsert(resolver, Filters.Users.CONTENT_URI, userValues) ContentResolverUtils.bulkInsert(resolver, Filters.Keywords.CONTENT_URI, keywordValues) ContentResolverUtils.bulkInsert(resolver, Filters.Sources.CONTENT_URI, sourceValues) } } builder.setNegativeButton(android.R.string.cancel, null) val dialog = builder.create() dialog.onShow { it.applyTheme() } return dialog } private val filterItemsInfo: Array get() { val args = arguments if (args == null || !args.containsKey(EXTRA_STATUS)) return emptyArray() val status = args.getParcelable(EXTRA_STATUS) ?: return emptyArray() val list = ArrayList() if (status.is_retweet && status.retweeted_by_user_key != null) { list.add(FilterItemInfo(FilterItemInfo.FILTER_TYPE_USER, UserItem(status.retweeted_by_user_key!!, status.retweeted_by_user_name, status.retweeted_by_user_screen_name))) } if (status.is_quote && status.quoted_user_key != null) { list.add(FilterItemInfo(FilterItemInfo.FILTER_TYPE_USER, UserItem(status.quoted_user_key!!, status.quoted_user_name, status.quoted_user_screen_name))) } list.add(FilterItemInfo(FilterItemInfo.FILTER_TYPE_USER, UserItem(status.user_key, status.user_name, status.user_screen_name))) val mentions = status.mentions if (mentions != null) { for (mention in mentions) { if (mention.key != status.user_key) { list.add(FilterItemInfo(FilterItemInfo.FILTER_TYPE_USER, mention)) } } } val hashtags = HashSet() hashtags.addAll(extractor.extractHashtags(status.text_plain)) for (hashtag in hashtags) { list.add(FilterItemInfo(FilterItemInfo.FILTER_TYPE_KEYWORD, hashtag)) } val source = status.source?.let(HtmlEscapeHelper::toPlainText) if (source != null) { list.add(FilterItemInfo(FilterItemInfo.FILTER_TYPE_SOURCE, source)) } return list.toTypedArray() } private fun getName(manager: UserColorNameManager, value: Any, nameFirst: Boolean): String { return when (value) { is ParcelableUserMention -> { manager.getDisplayName(value.key, value.name, value.screen_name, nameFirst) } is UserItem -> { manager.getDisplayName(value.key, value.name, value.screen_name, nameFirst) } else -> ParseUtils.parseString(value) } } internal data class FilterItemInfo( val type: Int, val value: Any ) { companion object { internal const val FILTER_TYPE_USER = 1 internal const val FILTER_TYPE_KEYWORD = 2 internal const val FILTER_TYPE_SOURCE = 3 } } internal data class UserItem( val key: UserKey, val name: String, val screen_name: String ) companion object { const val FRAGMENT_TAG = "add_status_filter" private fun createFilteredUser(item: UserItem): ContentValues { val values = ContentValues() values.put(Filters.Users.USER_KEY, item.key.toString()) values.put(Filters.Users.NAME, item.name) values.put(Filters.Users.SCREEN_NAME, item.screen_name) return values } fun show(fm: FragmentManager, status: ParcelableStatus): AddStatusFilterDialogFragment { val args = Bundle() args.putParcelable(EXTRA_STATUS, status) val f = AddStatusFilterDialogFragment() f.arguments = args f.show(fm, FRAGMENT_TAG) return f } } }