commit
4c884673ee
|
@ -226,6 +226,7 @@ dependencies {
|
||||||
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.15'
|
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.15'
|
||||||
implementation 'com.sprylab.android.texturevideoview:texturevideoview:1.2.1'
|
implementation 'com.sprylab.android.texturevideoview:texturevideoview:1.2.1'
|
||||||
implementation 'com.squareup:pollexor:2.0.4'
|
implementation 'com.squareup:pollexor:2.0.4'
|
||||||
|
implementation 'org.apache.commons:commons-text:1.8'
|
||||||
implementation "org.apache.james:apache-mime4j-core:${libVersions['Mime4J']}"
|
implementation "org.apache.james:apache-mime4j-core:${libVersions['Mime4J']}"
|
||||||
implementation "org.apache.james:apache-mime4j-storage:${libVersions['Mime4J']}"
|
implementation "org.apache.james:apache-mime4j-storage:${libVersions['Mime4J']}"
|
||||||
implementation "com.bluelinelabs:logansquare:${sharedVersions['LoganSquare']}"
|
implementation "com.bluelinelabs:logansquare:${sharedVersions['LoganSquare']}"
|
||||||
|
|
|
@ -316,9 +316,9 @@ class AccountsDumperPlugin(val context: Context) : DumperPlugin {
|
||||||
return JsonPath.parse(JsonSerializer.serialize(details), configuration)
|
return JsonPath.parse(JsonSerializer.serialize(details), configuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Any.prettyPrint() = when {
|
private fun Any.prettyPrint() = when (this) {
|
||||||
this is JSONObject -> toString(4)
|
is JSONObject -> toString(4)
|
||||||
this is JSONArray -> toString(4)
|
is JSONArray -> toString(4)
|
||||||
else -> toString()
|
else -> toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.commons.text.translate;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes a sequence of translators one after the other. Execution ends whenever
|
|
||||||
* the first translator consumes codepoints from the input.
|
|
||||||
*
|
|
||||||
* @since 1.0
|
|
||||||
*/
|
|
||||||
public class AggregateTranslator extends CharSequenceTranslator {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translator list.
|
|
||||||
*/
|
|
||||||
private final List<CharSequenceTranslator> translators = new ArrayList<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the translators to be used at creation time.
|
|
||||||
*
|
|
||||||
* @param translators CharSequenceTranslator array to aggregate
|
|
||||||
*/
|
|
||||||
public AggregateTranslator(final CharSequenceTranslator... translators) {
|
|
||||||
if (translators != null) {
|
|
||||||
for (CharSequenceTranslator translator : translators) {
|
|
||||||
if (translator != null) {
|
|
||||||
this.translators.add(translator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The first translator to consume codepoints from the input is the 'winner'.
|
|
||||||
* Execution stops with the number of consumed codepoints being returned.
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
|
|
||||||
for (final CharSequenceTranslator translator : translators) {
|
|
||||||
final int consumed = translator.translate(input, index, out);
|
|
||||||
if (consumed != 0) {
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,140 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.commons.text.translate;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An API for translating text.
|
|
||||||
* Its core use is to escape and unescape text. Because escaping and unescaping
|
|
||||||
* is completely contextual, the API does not present two separate signatures.
|
|
||||||
*
|
|
||||||
* @since 1.0
|
|
||||||
*/
|
|
||||||
public abstract class CharSequenceTranslator {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Array containing the hexadecimal alphabet.
|
|
||||||
*/
|
|
||||||
static final char[] HEX_DIGITS = new char[]{'0', '1', '2', '3',
|
|
||||||
'4', '5', '6', '7',
|
|
||||||
'8', '9', 'A', 'B',
|
|
||||||
'C', 'D', 'E', 'F'};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate a set of codepoints, represented by an int index into a CharSequence,
|
|
||||||
* into another set of codepoints. The number of codepoints consumed must be returned,
|
|
||||||
* and the only IOExceptions thrown must be from interacting with the Writer so that
|
|
||||||
* the top level API may reliably ignore StringWriter IOExceptions.
|
|
||||||
*
|
|
||||||
* @param input CharSequence that is being translated
|
|
||||||
* @param index int representing the current point of translation
|
|
||||||
* @param out Writer to translate the text to
|
|
||||||
* @return int count of codepoints consumed
|
|
||||||
* @throws IOException if and only if the Writer produces an IOException
|
|
||||||
*/
|
|
||||||
public abstract int translate(CharSequence input, int index, Writer out) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper for non-Writer usage.
|
|
||||||
*
|
|
||||||
* @param input CharSequence to be translated
|
|
||||||
* @return String output of translation
|
|
||||||
*/
|
|
||||||
public final String translate(final CharSequence input) {
|
|
||||||
if (input == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
final StringWriter writer = new StringWriter(input.length() * 2);
|
|
||||||
translate(input, writer);
|
|
||||||
return writer.toString();
|
|
||||||
} catch (final IOException ioe) {
|
|
||||||
// this should never ever happen while writing to a StringWriter
|
|
||||||
throw new RuntimeException(ioe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate an input onto a Writer. This is intentionally final as its algorithm is
|
|
||||||
* tightly coupled with the abstract method of this class.
|
|
||||||
*
|
|
||||||
* @param input CharSequence that is being translated
|
|
||||||
* @param out Writer to translate the text to
|
|
||||||
* @throws IOException if and only if the Writer produces an IOException
|
|
||||||
*/
|
|
||||||
public final void translate(final CharSequence input, final Writer out) throws IOException {
|
|
||||||
if (out == null) throw new IllegalArgumentException("The Writer must not be null");
|
|
||||||
if (input == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int pos = 0;
|
|
||||||
final int len = input.length();
|
|
||||||
while (pos < len) {
|
|
||||||
final int consumed = translate(input, pos, out);
|
|
||||||
if (consumed == 0) {
|
|
||||||
// inlined implementation of Character.toChars(Character.codePointAt(input, pos))
|
|
||||||
// avoids allocating temp char arrays and duplicate checks
|
|
||||||
final char c1 = input.charAt(pos);
|
|
||||||
out.write(c1);
|
|
||||||
pos++;
|
|
||||||
if (Character.isHighSurrogate(c1) && pos < len) {
|
|
||||||
final char c2 = input.charAt(pos);
|
|
||||||
if (Character.isLowSurrogate(c2)) {
|
|
||||||
out.write(c2);
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// contract with translators is that they have to understand codepoints
|
|
||||||
// and they just took care of a surrogate pair
|
|
||||||
for (int pt = 0; pt < consumed; pt++) {
|
|
||||||
pos += Character.charCount(Character.codePointAt(input, pos));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method to create a merger of this translator with another set of
|
|
||||||
* translators. Useful in customizing the standard functionality.
|
|
||||||
*
|
|
||||||
* @param translators CharSequenceTranslator array of translators to merge with this one
|
|
||||||
* @return CharSequenceTranslator merging this translator with the others
|
|
||||||
*/
|
|
||||||
public final CharSequenceTranslator with(final CharSequenceTranslator... translators) {
|
|
||||||
final CharSequenceTranslator[] newArray = new CharSequenceTranslator[translators.length + 1];
|
|
||||||
newArray[0] = this;
|
|
||||||
System.arraycopy(translators, 0, newArray, 1, translators.length);
|
|
||||||
return new AggregateTranslator(newArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Returns an upper case hexadecimal <code>String</code> for the given
|
|
||||||
* character.</p>
|
|
||||||
*
|
|
||||||
* @param codepoint The codepoint to convert.
|
|
||||||
* @return An upper case hexadecimal <code>String</code>
|
|
||||||
*/
|
|
||||||
public static String hex(final int codepoint) {
|
|
||||||
return Integer.toHexString(codepoint).toUpperCase(Locale.ENGLISH);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.commons.text.translate;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Writer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper subclass to CharSequenceTranslator to allow for translations that
|
|
||||||
* will replace up to one character at a time.
|
|
||||||
*
|
|
||||||
* @since 1.0
|
|
||||||
*/
|
|
||||||
public abstract class CodePointTranslator extends CharSequenceTranslator {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of translate that maps onto the abstract translate(int, Writer) method.
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final int translate(final CharSequence input, final int index, final Writer out) throws IOException {
|
|
||||||
final int codepoint = Character.codePointAt(input, index);
|
|
||||||
final boolean consumed = translate(codepoint, out);
|
|
||||||
return consumed ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate the specified codepoint into another.
|
|
||||||
*
|
|
||||||
* @param codepoint int character input to translate
|
|
||||||
* @param out Writer to optionally push the translated output to
|
|
||||||
* @return boolean as to whether translation occurred or not
|
|
||||||
* @throws IOException if and only if the Writer produces an IOException
|
|
||||||
*/
|
|
||||||
public abstract boolean translate(int codepoint, Writer out) throws IOException;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.commons.text.translate;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.security.InvalidParameterException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translates a value using a lookup table.
|
|
||||||
*
|
|
||||||
* @since 1.0
|
|
||||||
*/
|
|
||||||
public class LookupTranslator extends CharSequenceTranslator {
|
|
||||||
|
|
||||||
/** The mapping to be used in translation. */
|
|
||||||
private final Map<String, String> lookupMap;
|
|
||||||
/** The first character of each key in the lookupMap. */
|
|
||||||
private final HashSet<Character> prefixSet;
|
|
||||||
/** The length of the shortest key in the lookupMap. */
|
|
||||||
private final int shortest;
|
|
||||||
/** The length of the longest key in the lookupMap. */
|
|
||||||
private final int longest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define the lookup table to be used in translation
|
|
||||||
*
|
|
||||||
* Note that, as of Lang 3.1 (the orgin of this code), the key to the lookup
|
|
||||||
* table is converted to a java.lang.String. This is because we need the key
|
|
||||||
* to support hashCode and equals(Object), allowing it to be the key for a
|
|
||||||
* HashMap. See LANG-882.
|
|
||||||
*
|
|
||||||
* @param lookupMap Map<CharSequence, CharSequence> table of translator
|
|
||||||
* mappings
|
|
||||||
*/
|
|
||||||
public LookupTranslator(final Map<CharSequence, CharSequence> lookupMap) {
|
|
||||||
if (lookupMap == null) {
|
|
||||||
throw new InvalidParameterException("lookupMap cannot be null");
|
|
||||||
}
|
|
||||||
this.lookupMap = new HashMap<>();
|
|
||||||
this.prefixSet = new HashSet<>();
|
|
||||||
int currentShortest = Integer.MAX_VALUE;
|
|
||||||
int currentLongest = 0;
|
|
||||||
|
|
||||||
for (Map.Entry<CharSequence, CharSequence> pair : lookupMap.entrySet()) {
|
|
||||||
this.lookupMap.put(pair.getKey().toString(), pair.getValue().toString());
|
|
||||||
this.prefixSet.add(pair.getKey().charAt(0));
|
|
||||||
final int sz = pair.getKey().length();
|
|
||||||
if (sz < currentShortest) {
|
|
||||||
currentShortest = sz;
|
|
||||||
}
|
|
||||||
if (sz > currentLongest) {
|
|
||||||
currentLongest = sz;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.shortest = currentShortest;
|
|
||||||
this.longest = currentLongest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
|
|
||||||
// check if translation exists for the input at position index
|
|
||||||
if (prefixSet.contains(input.charAt(index))) {
|
|
||||||
int max = longest;
|
|
||||||
if (index + longest > input.length()) {
|
|
||||||
max = input.length() - index;
|
|
||||||
}
|
|
||||||
// implement greedy algorithm by trying maximum match first
|
|
||||||
for (int i = max; i >= shortest; i--) {
|
|
||||||
final CharSequence subSeq = input.subSequence(index, index + i);
|
|
||||||
final String result = lookupMap.get(subSeq.toString());
|
|
||||||
|
|
||||||
if (result != null) {
|
|
||||||
out.write(result);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,139 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.commons.text.translate;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.EnumSet;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translate XML numeric entities of the form &#[xX]?\d+;? to
|
|
||||||
* the specific codepoint.
|
|
||||||
*
|
|
||||||
* Note that the semi-colon is optional.
|
|
||||||
*
|
|
||||||
* @since 1.0
|
|
||||||
*/
|
|
||||||
public class NumericEntityUnescaper extends CharSequenceTranslator {
|
|
||||||
|
|
||||||
/** NumericEntityUnescaper option enum. */
|
|
||||||
public enum OPTION { semiColonRequired, semiColonOptional, errorIfNoSemiColon }
|
|
||||||
|
|
||||||
/** EnumSet of OPTIONS, given from the constructor. */
|
|
||||||
private final EnumSet<OPTION> options;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a UnicodeUnescaper.
|
|
||||||
*
|
|
||||||
* The constructor takes a list of options, only one type of which is currently
|
|
||||||
* available (whether to allow, error or ignore the semi-colon on the end of a
|
|
||||||
* numeric entity to being missing).
|
|
||||||
*
|
|
||||||
* For example, to support numeric entities without a ';':
|
|
||||||
* new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.semiColonOptional)
|
|
||||||
* and to throw an IllegalArgumentException when they're missing:
|
|
||||||
* new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.errorIfNoSemiColon)
|
|
||||||
*
|
|
||||||
* Note that the default behaviour is to ignore them.
|
|
||||||
*
|
|
||||||
* @param options to apply to this unescaper
|
|
||||||
*/
|
|
||||||
public NumericEntityUnescaper(final OPTION... options) {
|
|
||||||
if (options.length > 0) {
|
|
||||||
this.options = EnumSet.copyOf(Arrays.asList(options));
|
|
||||||
} else {
|
|
||||||
this.options = EnumSet.of(OPTION.semiColonRequired);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the passed in option is currently set.
|
|
||||||
*
|
|
||||||
* @param option to check state of
|
|
||||||
* @return whether the option is set
|
|
||||||
*/
|
|
||||||
public boolean isSet(final OPTION option) {
|
|
||||||
return options != null && options.contains(option);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
|
|
||||||
final int seqEnd = input.length();
|
|
||||||
// Uses -2 to ensure there is something after the &#
|
|
||||||
if (input.charAt(index) == '&' && index < seqEnd - 2 && input.charAt(index + 1) == '#') {
|
|
||||||
int start = index + 2;
|
|
||||||
boolean isHex = false;
|
|
||||||
|
|
||||||
final char firstChar = input.charAt(start);
|
|
||||||
if (firstChar == 'x' || firstChar == 'X') {
|
|
||||||
start++;
|
|
||||||
isHex = true;
|
|
||||||
|
|
||||||
// Check there's more than just an x after the &#
|
|
||||||
if (start == seqEnd) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int end = start;
|
|
||||||
// Note that this supports character codes without a ; on the end
|
|
||||||
while (end < seqEnd && (input.charAt(end) >= '0' && input.charAt(end) <= '9'
|
|
||||||
|| input.charAt(end) >= 'a' && input.charAt(end) <= 'f'
|
|
||||||
|| input.charAt(end) >= 'A' && input.charAt(end) <= 'F')) {
|
|
||||||
end++;
|
|
||||||
}
|
|
||||||
|
|
||||||
final boolean semiNext = end != seqEnd && input.charAt(end) == ';';
|
|
||||||
|
|
||||||
if (!semiNext) {
|
|
||||||
if (isSet(OPTION.semiColonRequired)) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
if (isSet(OPTION.errorIfNoSemiColon)) {
|
|
||||||
throw new IllegalArgumentException("Semi-colon required at end of numeric entity");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int entityValue;
|
|
||||||
try {
|
|
||||||
if (isHex) {
|
|
||||||
entityValue = Integer.parseInt(input.subSequence(start, end).toString(), 16);
|
|
||||||
} else {
|
|
||||||
entityValue = Integer.parseInt(input.subSequence(start, end).toString(), 10);
|
|
||||||
}
|
|
||||||
} catch (final NumberFormatException nfe) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entityValue > 0xFFFF) {
|
|
||||||
final char[] chrs = Character.toChars(entityValue);
|
|
||||||
out.write(chrs[0]);
|
|
||||||
out.write(chrs[1]);
|
|
||||||
} else {
|
|
||||||
out.write(entityValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 2 + end - start + (isHex ? 1 : 0) + (semiNext ? 1 : 0);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -95,8 +95,8 @@ public class KeyboardShortcutsFragment extends BasePreferenceFragment implements
|
||||||
protected void onClick() {
|
protected void onClick() {
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
final Intent intent = new Intent(context, KeyboardShortcutPreferenceCompatActivity.class);
|
final Intent intent = new Intent(context, KeyboardShortcutPreferenceCompatActivity.class);
|
||||||
intent.putExtra(KeyboardShortcutPreferenceCompatActivity.Companion.getEXTRA_CONTEXT_TAG(), mContextTag);
|
intent.putExtra(KeyboardShortcutPreferenceCompatActivity.EXTRA_CONTEXT_TAG, mContextTag);
|
||||||
intent.putExtra(KeyboardShortcutPreferenceCompatActivity.Companion.getEXTRA_KEY_ACTION(), mAction);
|
intent.putExtra(KeyboardShortcutPreferenceCompatActivity.EXTRA_KEY_ACTION, mAction);
|
||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Uses https://github.com/george-steel/android-utils/commit/289aff11e53593a55d780f9f5986e49343a79e55
|
||||||
|
|
||||||
package org.oshkimaadziig.george.androidutils;
|
package org.oshkimaadziig.george.androidutils;
|
||||||
|
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
|
@ -87,7 +89,7 @@ public class SpanFormatter {
|
||||||
|
|
||||||
if (typeTerm.equals("%")) {
|
if (typeTerm.equals("%")) {
|
||||||
cookedArg = "%";
|
cookedArg = "%";
|
||||||
} else if (typeTerm.equals("%")) {
|
} else if (typeTerm.equals("n")) {
|
||||||
cookedArg = "\n";
|
cookedArg = "\n";
|
||||||
} else {
|
} else {
|
||||||
int argIdx;
|
int argIdx;
|
||||||
|
|
|
@ -25,27 +25,39 @@ import java.util.*
|
||||||
@SuppressLint("RestrictedApi")
|
@SuppressLint("RestrictedApi")
|
||||||
object LocaleHelperAccessor {
|
object LocaleHelperAccessor {
|
||||||
fun forLanguageTag(str: String): Locale {
|
fun forLanguageTag(str: String): Locale {
|
||||||
if (str.contains("-")) {
|
when {
|
||||||
|
str.contains("-") -> {
|
||||||
val args = str.split("-").dropLastWhile { it.isEmpty() }.toTypedArray()
|
val args = str.split("-").dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||||
if (args.size > 2) {
|
when {
|
||||||
|
args.size > 2 -> {
|
||||||
return Locale(args[0], args[1], args[2])
|
return Locale(args[0], args[1], args[2])
|
||||||
} else if (args.size > 1) {
|
}
|
||||||
|
args.size > 1 -> {
|
||||||
return Locale(args[0], args[1])
|
return Locale(args[0], args[1])
|
||||||
} else if (args.size == 1) {
|
}
|
||||||
|
args.size == 1 -> {
|
||||||
return Locale(args[0])
|
return Locale(args[0])
|
||||||
}
|
}
|
||||||
} else if (str.contains("_")) {
|
}
|
||||||
|
}
|
||||||
|
str.contains("_") -> {
|
||||||
val args = str.split("_").dropLastWhile { it.isEmpty() }.toTypedArray()
|
val args = str.split("_").dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||||
if (args.size > 2) {
|
when {
|
||||||
|
args.size > 2 -> {
|
||||||
return Locale(args[0], args[1], args[2])
|
return Locale(args[0], args[1], args[2])
|
||||||
} else if (args.size > 1) {
|
}
|
||||||
|
args.size > 1 -> {
|
||||||
return Locale(args[0], args[1])
|
return Locale(args[0], args[1])
|
||||||
} else if (args.size == 1) {
|
}
|
||||||
|
args.size == 1 -> {
|
||||||
return Locale(args[0])
|
return Locale(args[0])
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
return Locale(str)
|
return Locale(str)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
throw IllegalArgumentException("Can not parse language tag: [$str]")
|
throw IllegalArgumentException("Can not parse language tag: [$str]")
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,23 +10,23 @@ import android.os.Handler
|
||||||
|
|
||||||
fun AccountManager.addOnAccountsUpdatedListenerSafe(listener: OnAccountsUpdateListener,
|
fun AccountManager.addOnAccountsUpdatedListenerSafe(listener: OnAccountsUpdateListener,
|
||||||
handler: Handler? = null, updateImmediately: Boolean = false): Boolean {
|
handler: Handler? = null, updateImmediately: Boolean = false): Boolean {
|
||||||
try {
|
return try {
|
||||||
this.addOnAccountsUpdatedListener(listener, handler, updateImmediately)
|
this.addOnAccountsUpdatedListener(listener, handler, updateImmediately)
|
||||||
return true
|
true
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
return false
|
false
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (e: IllegalArgumentException) {
|
||||||
return false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun AccountManager.removeOnAccountsUpdatedListenerSafe(listener: OnAccountsUpdateListener): Boolean {
|
fun AccountManager.removeOnAccountsUpdatedListenerSafe(listener: OnAccountsUpdateListener): Boolean {
|
||||||
try {
|
return try {
|
||||||
this.removeOnAccountsUpdatedListener(listener)
|
this.removeOnAccountsUpdatedListener(listener)
|
||||||
return true
|
true
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
return false
|
false
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (e: IllegalArgumentException) {
|
||||||
return false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,10 @@ fun Collection<*>?.isNullOrEmpty(): Boolean {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> MutableCollection<T>.addAllEnhanced(collection: Collection<T>, ignoreDuplicates: Boolean): Boolean {
|
fun <T> MutableCollection<T>.addAllEnhanced(collection: Collection<T>, ignoreDuplicates: Boolean): Boolean {
|
||||||
if (ignoreDuplicates) {
|
return if (ignoreDuplicates) {
|
||||||
return addAll(collection.filter { it !in this })
|
addAll(collection.filter { it !in this })
|
||||||
} else {
|
} else {
|
||||||
return addAll(collection)
|
addAll(collection)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ fun <E> Collection<E>.contentEquals(other: Collection<E>): Boolean {
|
||||||
|
|
||||||
inline fun <reified T> List<T>.subArray(range: IntRange): Array<T> {
|
inline fun <reified T> List<T>.subArray(range: IntRange): Array<T> {
|
||||||
return Array(range.count()) {
|
return Array(range.count()) {
|
||||||
this[range.start + it]
|
this[range.first + it]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,11 +20,11 @@ fun Context.checkAnySelfPermissionsGranted(vararg permissions: String): Boolean
|
||||||
|
|
||||||
fun Context.unregisterReceiverSafe(receiver: BroadcastReceiver?): Boolean {
|
fun Context.unregisterReceiverSafe(receiver: BroadcastReceiver?): Boolean {
|
||||||
if (receiver == null) return false
|
if (receiver == null) return false
|
||||||
try {
|
return try {
|
||||||
unregisterReceiver(receiver)
|
unregisterReceiver(receiver)
|
||||||
return true
|
true
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (e: IllegalArgumentException) {
|
||||||
return false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ fun Cursor.safeGetInt(columnIndex: Int, def: Int = -1) = try {
|
||||||
def
|
def
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Cursor.safeGetString(columnIndex: Int, def: String = "") = try {
|
fun Cursor.safeGetString(columnIndex: Int, def: String = ""): String = try {
|
||||||
getString(columnIndex)
|
getString(columnIndex)
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
def
|
def
|
||||||
|
|
|
@ -58,10 +58,10 @@ val Locale.bcp47Tag: String
|
||||||
}
|
}
|
||||||
|
|
||||||
val bcp47Tag = StringBuilder(language)
|
val bcp47Tag = StringBuilder(language)
|
||||||
if (!country.isEmpty()) {
|
if (country.isNotEmpty()) {
|
||||||
bcp47Tag.append(SEP).append(country)
|
bcp47Tag.append(SEP).append(country)
|
||||||
}
|
}
|
||||||
if (!variant.isEmpty()) {
|
if (variant.isNotEmpty()) {
|
||||||
bcp47Tag.append(SEP).append(variant)
|
bcp47Tag.append(SEP).append(variant)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ fun Number.toLocalizedString(locale: Locale = Locale.getDefault()): String {
|
||||||
val Int.nextPowerOf2: Int
|
val Int.nextPowerOf2: Int
|
||||||
get() {
|
get() {
|
||||||
var n = this
|
var n = this
|
||||||
if (n <= 0 || n > 1 shl 30) throw IllegalArgumentException("n is invalid: " + n)
|
if (n <= 0 || n > 1 shl 30) throw IllegalArgumentException("n is invalid: $n")
|
||||||
n -= 1
|
n -= 1
|
||||||
n = n or (n shr 16)
|
n = n or (n shr 16)
|
||||||
n = n or (n shr 8)
|
n = n or (n shr 8)
|
||||||
|
|
|
@ -6,5 +6,5 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
* Created by mariotaku on 16/8/21.
|
* Created by mariotaku on 16/8/21.
|
||||||
*/
|
*/
|
||||||
fun RecyclerView.Adapter<*>.findPositionByItemId(itemId: Long): Int {
|
fun RecyclerView.Adapter<*>.findPositionByItemId(itemId: Long): Int {
|
||||||
return (0 until itemCount).firstOrNull { getItemId(it) == itemId } ?: androidx.recyclerview.widget.RecyclerView.NO_POSITION
|
return (0 until itemCount).firstOrNull { getItemId(it) == itemId } ?: RecyclerView.NO_POSITION
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,5 +40,5 @@ fun InputStream.expectLine(string: String = "", charset: Charset = Charset.defau
|
||||||
fun InputStream.expectBytes(bytes: ByteArray): Boolean {
|
fun InputStream.expectBytes(bytes: ByteArray): Boolean {
|
||||||
val readBytes = ByteArray(bytes.size)
|
val readBytes = ByteArray(bytes.size)
|
||||||
read(readBytes)
|
read(readBytes)
|
||||||
return Arrays.equals(readBytes, bytes)
|
return readBytes.contentEquals(bytes)
|
||||||
}
|
}
|
|
@ -35,21 +35,25 @@ object InternalActivityCreator {
|
||||||
activity.maxSortPosition = activity.minSortPosition
|
activity.maxSortPosition = activity.minSortPosition
|
||||||
activity.createdAt = status.getCreatedAt()
|
activity.createdAt = status.getCreatedAt()
|
||||||
|
|
||||||
if (status.getInReplyToUserId() == accountId) {
|
when {
|
||||||
|
status.getInReplyToUserId() == accountId -> {
|
||||||
activity.action = Activity.Action.REPLY
|
activity.action = Activity.Action.REPLY
|
||||||
activity.targetStatuses = arrayOf(status)
|
activity.targetStatuses = arrayOf(status)
|
||||||
|
|
||||||
//TODO set target statuses (in reply to status)
|
//TODO set target statuses (in reply to status)
|
||||||
activity.targetObjectStatuses = arrayOfNulls<Status>(0)
|
activity.targetObjectStatuses = arrayOfNulls<Status>(0)
|
||||||
} else if (status.quotedStatus?.user?.id == accountId) {
|
}
|
||||||
|
status.quotedStatus?.user?.id == accountId -> {
|
||||||
activity.action = Activity.Action.QUOTE
|
activity.action = Activity.Action.QUOTE
|
||||||
activity.targetStatuses = arrayOf(status)
|
activity.targetStatuses = arrayOf(status)
|
||||||
activity.targetObjectStatuses = arrayOfNulls<Status>(0)
|
activity.targetObjectStatuses = arrayOfNulls<Status>(0)
|
||||||
} else {
|
}
|
||||||
|
else -> {
|
||||||
activity.action = Activity.Action.MENTION
|
activity.action = Activity.Action.MENTION
|
||||||
activity.targetUsers = arrayOfNulls<User>(0)
|
activity.targetUsers = arrayOfNulls<User>(0)
|
||||||
activity.targetObjectStatuses = arrayOf(status)
|
activity.targetObjectStatuses = arrayOf(status)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
activity.sourcesSize = 1
|
activity.sourcesSize = 1
|
||||||
activity.sources = arrayOf(status.getUser())
|
activity.sources = arrayOf(status.getUser())
|
||||||
return activity
|
return activity
|
||||||
|
|
|
@ -13,8 +13,7 @@ class AssistLauncherActivity : Activity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
val prefs = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
|
val prefs = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
|
||||||
val composeNowAction = prefs.getString(KEY_COMPOSE_NOW_ACTION, VALUE_COMPOSE_NOW_ACTION_COMPOSE)
|
val action = when (prefs.getString(KEY_COMPOSE_NOW_ACTION, VALUE_COMPOSE_NOW_ACTION_COMPOSE)) {
|
||||||
val action = when (composeNowAction) {
|
|
||||||
VALUE_COMPOSE_NOW_ACTION_TAKE_PHOTO -> INTENT_ACTION_COMPOSE_TAKE_PHOTO
|
VALUE_COMPOSE_NOW_ACTION_TAKE_PHOTO -> INTENT_ACTION_COMPOSE_TAKE_PHOTO
|
||||||
VALUE_COMPOSE_NOW_ACTION_PICK_IMAGE -> INTENT_ACTION_COMPOSE_PICK_IMAGE
|
VALUE_COMPOSE_NOW_ACTION_PICK_IMAGE -> INTENT_ACTION_COMPOSE_PICK_IMAGE
|
||||||
else -> INTENT_ACTION_COMPOSE
|
else -> INTENT_ACTION_COMPOSE
|
||||||
|
|
|
@ -300,7 +300,7 @@ open class BaseActivity : ChameleonActivity(), IBaseActivity<BaseActivity>, IThe
|
||||||
for (i in 0 until handlerFilter.countDataAuthorities()) {
|
for (i in 0 until handlerFilter.countDataAuthorities()) {
|
||||||
val authorityEntry = handlerFilter.getDataAuthority(i)
|
val authorityEntry = handlerFilter.getDataAuthority(i)
|
||||||
val port = authorityEntry.port
|
val port = authorityEntry.port
|
||||||
intentFilter.addDataAuthority(authorityEntry.host, if (port < 0) null else Integer.toString(port))
|
intentFilter.addDataAuthority(authorityEntry.host, if (port < 0) null else port.toString())
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
adapter.enableForegroundDispatch(this, intent, arrayOf(intentFilter), null)
|
adapter.enableForegroundDispatch(this, intent, arrayOf(intentFilter), null)
|
||||||
|
@ -469,20 +469,20 @@ open class BaseActivity : ChameleonActivity(), IBaseActivity<BaseActivity>, IThe
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun newInstance(name: String, context: Context, attrs: AttributeSet): View? {
|
private fun newInstance(name: String, context: Context, attrs: AttributeSet): View? {
|
||||||
try {
|
return try {
|
||||||
val cls = findClass(name) ?: throw ClassNotFoundException(name)
|
val cls = findClass(name) ?: throw ClassNotFoundException(name)
|
||||||
val constructor = cls.getConstructor(Context::class.java, AttributeSet::class.java)
|
val constructor = cls.getConstructor(Context::class.java, AttributeSet::class.java)
|
||||||
return constructor.newInstance(context, attrs) as View
|
constructor.newInstance(context, attrs) as View
|
||||||
} catch (e: InstantiationException) {
|
} catch (e: InstantiationException) {
|
||||||
return null
|
null
|
||||||
} catch (e: IllegalAccessException) {
|
} catch (e: IllegalAccessException) {
|
||||||
return null
|
null
|
||||||
} catch (e: InvocationTargetException) {
|
} catch (e: InvocationTargetException) {
|
||||||
return null
|
null
|
||||||
} catch (e: NoSuchMethodException) {
|
} catch (e: NoSuchMethodException) {
|
||||||
return null
|
null
|
||||||
} catch (e: ClassNotFoundException) {
|
} catch (e: ClassNotFoundException) {
|
||||||
return null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ class ColorPickerDialogActivity : BaseActivity(), Callback {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val RESULT_CLEARED = -2
|
const val RESULT_CLEARED = -2
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,7 @@ import java.text.Normalizer
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
import kotlin.math.abs
|
||||||
import android.Manifest.permission as AndroidPermission
|
import android.Manifest.permission as AndroidPermission
|
||||||
|
|
||||||
@SuppressLint("RestrictedApi")
|
@SuppressLint("RestrictedApi")
|
||||||
|
@ -394,7 +395,10 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
REQUEST_TAKE_PHOTO, REQUEST_PICK_MEDIA -> {
|
REQUEST_TAKE_PHOTO, REQUEST_PICK_MEDIA -> {
|
||||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||||
val src = MediaPickerActivity.getMediaUris(data)
|
val src = MediaPickerActivity.getMediaUris(data)
|
||||||
TaskStarter.execute(AddMediaTask(this, src, null, false, false))
|
TaskStarter.execute(AddMediaTask(this, src, null,
|
||||||
|
copySrc = false,
|
||||||
|
deleteSrc = false
|
||||||
|
))
|
||||||
val extras = data.getBundleExtra(MediaPickerActivity.EXTRA_EXTRAS)
|
val extras = data.getBundleExtra(MediaPickerActivity.EXTRA_EXTRAS)
|
||||||
if (extras?.getBoolean(EXTRA_IS_POSSIBLY_SENSITIVE) == true) {
|
if (extras?.getBoolean(EXTRA_IS_POSSIBLY_SENSITIVE) == true) {
|
||||||
possiblySensitive = true
|
possiblySensitive = true
|
||||||
|
@ -431,7 +435,10 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
val src = MediaPickerActivity.getMediaUris(data)?.takeIf(Array<Uri>::isNotEmpty) ?:
|
val src = MediaPickerActivity.getMediaUris(data)?.takeIf(Array<Uri>::isNotEmpty) ?:
|
||||||
data.getParcelableExtra<Uri>(EXTRA_IMAGE_URI)?.let { arrayOf(it) }
|
data.getParcelableExtra<Uri>(EXTRA_IMAGE_URI)?.let { arrayOf(it) }
|
||||||
if (src != null) {
|
if (src != null) {
|
||||||
TaskStarter.execute(AddMediaTask(this, src, null, false, false))
|
TaskStarter.execute(AddMediaTask(this, src, null,
|
||||||
|
copySrc = false,
|
||||||
|
deleteSrc = false
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -509,7 +516,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
}
|
}
|
||||||
replyLabel -> {
|
replyLabel -> {
|
||||||
if (replyLabel.visibility != View.VISIBLE) return
|
if (replyLabel.visibility != View.VISIBLE) return
|
||||||
replyLabel.setSingleLine(replyLabel.lineCount > 1)
|
replyLabel.isSingleLine = replyLabel.lineCount > 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -807,8 +814,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
private fun extensionIntentItemSelected(item: MenuItem) {
|
private fun extensionIntentItemSelected(item: MenuItem) {
|
||||||
val intent = item.intent ?: return
|
val intent = item.intent ?: return
|
||||||
try {
|
try {
|
||||||
val action = intent.action
|
when (intent.action) {
|
||||||
when (action) {
|
|
||||||
INTENT_ACTION_EXTENSION_COMPOSE -> {
|
INTENT_ACTION_EXTENSION_COMPOSE -> {
|
||||||
val accountKeys = accountsAdapter.selectedAccountKeys
|
val accountKeys = accountsAdapter.selectedAccountKeys
|
||||||
intent.putExtra(EXTRA_TEXT, ParseUtils.parseString(editText.text))
|
intent.putExtra(EXTRA_TEXT, ParseUtils.parseString(editText.text))
|
||||||
|
@ -1084,17 +1090,21 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
val action = intent.action
|
val action = intent.action
|
||||||
val hasVisibility = intent.hasExtra(EXTRA_VISIBILITY)
|
val hasVisibility = intent.hasExtra(EXTRA_VISIBILITY)
|
||||||
val hasAccountKeys: Boolean
|
val hasAccountKeys: Boolean
|
||||||
if (intent.hasExtra(EXTRA_ACCOUNT_KEYS)) {
|
when {
|
||||||
|
intent.hasExtra(EXTRA_ACCOUNT_KEYS) -> {
|
||||||
val accountKeys = intent.getTypedArrayExtra<UserKey>(EXTRA_ACCOUNT_KEYS)
|
val accountKeys = intent.getTypedArrayExtra<UserKey>(EXTRA_ACCOUNT_KEYS)
|
||||||
accountsAdapter.selectedAccountKeys = accountKeys
|
accountsAdapter.selectedAccountKeys = accountKeys
|
||||||
hasAccountKeys = true
|
hasAccountKeys = true
|
||||||
} else if (intent.hasExtra(EXTRA_ACCOUNT_KEY)) {
|
}
|
||||||
|
intent.hasExtra(EXTRA_ACCOUNT_KEY) -> {
|
||||||
val accountKey = intent.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY)
|
val accountKey = intent.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY)
|
||||||
accountsAdapter.selectedAccountKeys = arrayOf(accountKey)
|
accountsAdapter.selectedAccountKeys = arrayOf(accountKey)
|
||||||
hasAccountKeys = true
|
hasAccountKeys = true
|
||||||
} else {
|
}
|
||||||
|
else -> {
|
||||||
hasAccountKeys = false
|
hasAccountKeys = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
when (action) {
|
when (action) {
|
||||||
Intent.ACTION_SEND, Intent.ACTION_SEND_MULTIPLE -> {
|
Intent.ACTION_SEND, Intent.ACTION_SEND_MULTIPLE -> {
|
||||||
shouldSaveAccounts = false
|
shouldSaveAccounts = false
|
||||||
|
@ -1102,7 +1112,10 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
val stream = intent.getStreamExtra()
|
val stream = intent.getStreamExtra()
|
||||||
if (stream != null) {
|
if (stream != null) {
|
||||||
val src = stream.toTypedArray()
|
val src = stream.toTypedArray()
|
||||||
TaskStarter.execute(AddMediaTask(this, src, null, true, false))
|
TaskStarter.execute(AddMediaTask(this, src, null,
|
||||||
|
copySrc = true,
|
||||||
|
deleteSrc = false
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
@ -1111,7 +1124,10 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
val data = intent.data
|
val data = intent.data
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
val src = arrayOf(data)
|
val src = arrayOf(data)
|
||||||
TaskStarter.execute(AddMediaTask(this, src, null, true, false))
|
TaskStarter.execute(AddMediaTask(this, src, null,
|
||||||
|
copySrc = true,
|
||||||
|
deleteSrc = false
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1147,16 +1163,16 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
}
|
}
|
||||||
INTENT_ACTION_EDIT_DRAFT -> {
|
INTENT_ACTION_EDIT_DRAFT -> {
|
||||||
val draft: Draft? = intent.getParcelableExtra(EXTRA_DRAFT)
|
val draft: Draft? = intent.getParcelableExtra(EXTRA_DRAFT)
|
||||||
when (draft?.action_type) {
|
return when (draft?.action_type) {
|
||||||
Draft.Action.REPLY -> {
|
Draft.Action.REPLY -> {
|
||||||
return showReplyLabelAndHint((draft.action_extras as? UpdateStatusActionExtras)?.inReplyToStatus)
|
showReplyLabelAndHint((draft.action_extras as? UpdateStatusActionExtras)?.inReplyToStatus)
|
||||||
}
|
}
|
||||||
Draft.Action.QUOTE -> {
|
Draft.Action.QUOTE -> {
|
||||||
return showQuoteLabelAndHint((draft.action_extras as? UpdateStatusActionExtras)?.inReplyToStatus)
|
showQuoteLabelAndHint((draft.action_extras as? UpdateStatusActionExtras)?.inReplyToStatus)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
showDefaultLabelAndHint()
|
showDefaultLabelAndHint()
|
||||||
return false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1786,7 +1802,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
s.setSpan(MarkForDeleteSpan(), start, start + count,
|
s.setSpan(MarkForDeleteSpan(), start, start + count,
|
||||||
Spanned.SPAN_INCLUSIVE_INCLUSIVE)
|
Spanned.SPAN_INCLUSIVE_INCLUSIVE)
|
||||||
}
|
}
|
||||||
if (!imageSources.isEmpty()) {
|
if (imageSources.isNotEmpty()) {
|
||||||
val intent = ThemedMediaPickerActivity.withThemed(this@ComposeActivity)
|
val intent = ThemedMediaPickerActivity.withThemed(this@ComposeActivity)
|
||||||
.getMedia(Uri.parse(imageSources[0]))
|
.getMedia(Uri.parse(imageSources[0]))
|
||||||
.build()
|
.build()
|
||||||
|
@ -1817,7 +1833,10 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
})
|
})
|
||||||
editText.customSelectionActionModeCallback = this
|
editText.customSelectionActionModeCallback = this
|
||||||
editText.imageInputListener = { contentInfo ->
|
editText.imageInputListener = { contentInfo ->
|
||||||
val task = AddMediaTask(this, arrayOf(contentInfo.contentUri), null, true, false)
|
val task = AddMediaTask(this, arrayOf(contentInfo.contentUri), null,
|
||||||
|
copySrc = true,
|
||||||
|
deleteSrc = false
|
||||||
|
)
|
||||||
task.callback = {
|
task.callback = {
|
||||||
contentInfo.releasePermission()
|
contentInfo.releasePermission()
|
||||||
}
|
}
|
||||||
|
@ -1887,7 +1906,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AttachedMediaItemTouchHelperCallback(adapter: SimpleItemTouchHelperCallback.ItemTouchHelperAdapter) : SimpleItemTouchHelperCallback(adapter) {
|
class AttachedMediaItemTouchHelperCallback(adapter: ItemTouchHelperAdapter) : SimpleItemTouchHelperCallback(adapter) {
|
||||||
|
|
||||||
override fun isLongPressDragEnabled(): Boolean {
|
override fun isLongPressDragEnabled(): Boolean {
|
||||||
return true
|
return true
|
||||||
|
@ -1907,7 +1926,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {
|
override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {
|
||||||
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
|
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
|
||||||
// Fade out the view as it is swiped out of the parent's bounds
|
// Fade out the view as it is swiped out of the parent's bounds
|
||||||
val alpha = ALPHA_FULL - Math.abs(dY) / viewHolder.itemView.height.toFloat()
|
val alpha = ALPHA_FULL - abs(dY) / viewHolder.itemView.height.toFloat()
|
||||||
viewHolder.itemView.alpha = alpha
|
viewHolder.itemView.alpha = alpha
|
||||||
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
|
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1925,7 +1944,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val ALPHA_FULL = 1.0f
|
const val ALPHA_FULL = 1.0f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1997,7 +2016,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
set(value) {
|
set(value) {
|
||||||
selection.clear()
|
selection.clear()
|
||||||
for (accountKey in value) {
|
for (accountKey in value) {
|
||||||
selection.put(accountKey, true)
|
selection[accountKey] = true
|
||||||
}
|
}
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
@ -2035,7 +2054,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
fun toggleSelection(position: Int) {
|
fun toggleSelection(position: Int) {
|
||||||
if (accounts == null || position < 0) return
|
if (accounts == null || position < 0) return
|
||||||
val account = accounts!![position]
|
val account = accounts!![position]
|
||||||
selection.put(account.key, true != selection[account.key])
|
selection[account.key] = true != selection[account.key]
|
||||||
activity.updateAccountSelectionState()
|
activity.updateAccountSelectionState()
|
||||||
activity.updateVisibilityState()
|
activity.updateVisibilityState()
|
||||||
activity.updateSummaryTextState()
|
activity.updateSummaryTextState()
|
||||||
|
@ -2047,7 +2066,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
if (accounts == null || position < 0) return
|
if (accounts == null || position < 0) return
|
||||||
val account = accounts!![position]
|
val account = accounts!![position]
|
||||||
selection.clear()
|
selection.clear()
|
||||||
selection.put(account.key, true != selection[account.key])
|
selection[account.key] = true != selection[account.key]
|
||||||
activity.updateAccountSelectionState()
|
activity.updateAccountSelectionState()
|
||||||
activity.updateVisibilityState()
|
activity.updateVisibilityState()
|
||||||
activity.updateSummaryTextState()
|
activity.updateSummaryTextState()
|
||||||
|
@ -2097,12 +2116,12 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
private class DisplayPlaceNameTask : AbstractTask<ParcelableLocation, List<Address>, ComposeActivity>() {
|
private class DisplayPlaceNameTask : AbstractTask<ParcelableLocation, List<Address>, ComposeActivity>() {
|
||||||
|
|
||||||
override fun doLongOperation(location: ParcelableLocation): List<Address>? {
|
override fun doLongOperation(location: ParcelableLocation): List<Address>? {
|
||||||
try {
|
return try {
|
||||||
val activity = callback ?: throw IOException("Interrupted")
|
val activity = callback ?: throw IOException("Interrupted")
|
||||||
val gcd = Geocoder(activity, Locale.getDefault())
|
val gcd = Geocoder(activity, Locale.getDefault())
|
||||||
return gcd.getFromLocation(location.latitude, location.longitude, 1)
|
gcd.getFromLocation(location.latitude, location.longitude, 1)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
return null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2120,15 +2139,18 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
|
||||||
textView.spannable = ParcelableLocationUtils.getHumanReadableString(location, 3)
|
textView.spannable = ParcelableLocationUtils.getHumanReadableString(location, 3)
|
||||||
textView.tag = location
|
textView.tag = location
|
||||||
} else {
|
} else {
|
||||||
val tag = textView.tag
|
when (val tag = textView.tag) {
|
||||||
if (tag is Address) {
|
is Address -> {
|
||||||
textView.spannable = tag.locality
|
textView.spannable = tag.locality
|
||||||
} else if (tag is NoAddress) {
|
}
|
||||||
|
is NoAddress -> {
|
||||||
textView.setText(R.string.label_location_your_coarse_location)
|
textView.setText(R.string.label_location_your_coarse_location)
|
||||||
} else {
|
}
|
||||||
|
else -> {
|
||||||
textView.setText(R.string.getting_location)
|
textView.setText(R.string.getting_location)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
textView.setText(R.string.no_location)
|
textView.setText(R.string.no_location)
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,12 +105,12 @@ class DataExportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
|
||||||
?: return false
|
?: return false
|
||||||
// val file = File(folder, fileName)
|
// val file = File(folder, fileName)
|
||||||
// file.delete()
|
// file.delete()
|
||||||
try {
|
return try {
|
||||||
DataImportExportUtils.exportData(activity, file, flags)
|
DataImportExportUtils.exportData(activity, file, flags)
|
||||||
return true
|
true
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
Log.w(LOGTAG, e)
|
Log.w(LOGTAG, e)
|
||||||
return false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,7 @@ class DataExportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val FRAGMENT_TAG = "import_settings_dialog"
|
private const val FRAGMENT_TAG = "import_settings_dialog"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,12 +111,12 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (!file.isFile) return false
|
if (!file.isFile) return false
|
||||||
try {
|
return try {
|
||||||
DataImportExportUtils.importData(activity, file, flags)
|
DataImportExportUtils.importData(activity, file, flags)
|
||||||
return true
|
true
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
Log.w(LOGTAG, e)
|
Log.w(LOGTAG, e)
|
||||||
return false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,7 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val FRAGMENT_TAG = "import_settings_dialog"
|
private const val FRAGMENT_TAG = "import_settings_dialog"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -152,10 +152,10 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
if (!file.isFile) return 0
|
if (!file.isFile) return 0
|
||||||
try {
|
return try {
|
||||||
return DataImportExportUtils.getImportedSettingsFlags(activity, file)
|
DataImportExportUtils.getImportedSettingsFlags(activity, file)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
return 0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private val FRAGMENT_TAG = "read_settings_data_dialog"
|
private const val FRAGMENT_TAG = "read_settings_data_dialog"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,15 +87,19 @@ class FileSelectorActivity : BaseActivity(), FileSelectorDialogFragment.Callback
|
||||||
finish()
|
finish()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (checkAllSelfPermissionsGranted(AndroidPermissions.READ_EXTERNAL_STORAGE, AndroidPermissions.WRITE_EXTERNAL_STORAGE)) {
|
when {
|
||||||
|
checkAllSelfPermissionsGranted(AndroidPermissions.READ_EXTERNAL_STORAGE, AndroidPermissions.WRITE_EXTERNAL_STORAGE) -> {
|
||||||
showPickFileDialog()
|
showPickFileDialog()
|
||||||
} else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
|
}
|
||||||
|
Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN -> {
|
||||||
val permissions = arrayOf(AndroidPermissions.READ_EXTERNAL_STORAGE, AndroidPermissions.WRITE_EXTERNAL_STORAGE)
|
val permissions = arrayOf(AndroidPermissions.READ_EXTERNAL_STORAGE, AndroidPermissions.WRITE_EXTERNAL_STORAGE)
|
||||||
ActivityCompat.requestPermissions(this, permissions, REQUEST_REQUEST_PERMISSIONS)
|
ActivityCompat.requestPermissions(this, permissions, REQUEST_REQUEST_PERMISSIONS)
|
||||||
} else {
|
}
|
||||||
|
else -> {
|
||||||
finishWithDeniedMessage()
|
finishWithDeniedMessage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun finishWithDeniedMessage() {
|
private fun finishWithDeniedMessage() {
|
||||||
if (isFinishing) return
|
if (isFinishing) return
|
||||||
|
|
|
@ -107,6 +107,7 @@ import org.mariotaku.twidere.util.premium.ExtraFeaturesService
|
||||||
import org.mariotaku.twidere.view.HomeDrawerLayout
|
import org.mariotaku.twidere.view.HomeDrawerLayout
|
||||||
import org.mariotaku.twidere.view.TabPagerIndicator
|
import org.mariotaku.twidere.view.TabPagerIndicator
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
|
import kotlin.math.floor
|
||||||
|
|
||||||
class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, SupportFragmentCallback,
|
class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, SupportFragmentCallback,
|
||||||
OnLongClickListener, DrawerLayout.DrawerListener {
|
OnLongClickListener, DrawerLayout.DrawerListener {
|
||||||
|
@ -860,7 +861,7 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
|
||||||
"wide" -> resources.getDimension(R.dimen.preferred_tab_column_width_wide)
|
"wide" -> resources.getDimension(R.dimen.preferred_tab_column_width_wide)
|
||||||
else -> resources.getDimension(R.dimen.preferred_tab_column_width_normal)
|
else -> resources.getDimension(R.dimen.preferred_tab_column_width_normal)
|
||||||
}
|
}
|
||||||
mainTabs.columns = Math.floor(1.0 / pagerAdapter.getPageWidth(0)).toInt()
|
mainTabs.columns = floor(1.0 / pagerAdapter.getPageWidth(0)).toInt()
|
||||||
} else {
|
} else {
|
||||||
mainPager.pageMargin = 0
|
mainPager.pageMargin = 0
|
||||||
mainPager.setPageMarginDrawable(null)
|
mainPager.setPageMarginDrawable(null)
|
||||||
|
|
|
@ -119,7 +119,7 @@ class KeyboardShortcutPreferenceCompatActivity : BaseActivity(), OnClickListener
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val EXTRA_CONTEXT_TAG = "context_tag"
|
const val EXTRA_CONTEXT_TAG = "context_tag"
|
||||||
val EXTRA_KEY_ACTION = "key_action"
|
const val EXTRA_KEY_ACTION = "key_action"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,8 @@ import org.mariotaku.twidere.view.viewer.MediaSwipeCloseContainer
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.concurrent.thread
|
import kotlin.concurrent.thread
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.roundToInt
|
||||||
import android.Manifest.permission as AndroidPermissions
|
import android.Manifest.permission as AndroidPermissions
|
||||||
|
|
||||||
class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeCloseContainer.Listener,
|
class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeCloseContainer.Listener,
|
||||||
|
@ -145,7 +147,7 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
|
||||||
activityLayout.statusBarAlpha = offset
|
activityLayout.statusBarAlpha = offset
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
actionBar.hideOffset = Math.round(controlBarHeight * (1f - offset))
|
actionBar.hideOffset = (controlBarHeight * (1f - offset)).roundToInt()
|
||||||
} catch (e: UnsupportedOperationException) {
|
} catch (e: UnsupportedOperationException) {
|
||||||
// Some device will throw this exception
|
// Some device will throw this exception
|
||||||
hideOffsetNotSupported = true
|
hideOffsetNotSupported = true
|
||||||
|
@ -367,10 +369,10 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
|
||||||
ParcelableMedia.Type.IMAGE -> {
|
ParcelableMedia.Type.IMAGE -> {
|
||||||
val mediaUrl = media.media_url ?: return Fragment.instantiate(this, ExternalBrowserPageFragment::class.java.name, args) as MediaViewerFragment
|
val mediaUrl = media.media_url ?: return Fragment.instantiate(this, ExternalBrowserPageFragment::class.java.name, args) as MediaViewerFragment
|
||||||
args.putParcelable(EXTRA_MEDIA_URI, Uri.parse(mediaUrl))
|
args.putParcelable(EXTRA_MEDIA_URI, Uri.parse(mediaUrl))
|
||||||
if (mediaUrl.endsWith(".gif")) {
|
return if (mediaUrl.endsWith(".gif")) {
|
||||||
return Fragment.instantiate(this, GifPageFragment::class.java.name, args) as MediaViewerFragment
|
Fragment.instantiate(this, GifPageFragment::class.java.name, args) as MediaViewerFragment
|
||||||
} else {
|
} else {
|
||||||
return Fragment.instantiate(this, ImagePageFragment::class.java.name, args) as MediaViewerFragment
|
Fragment.instantiate(this, ImagePageFragment::class.java.name, args) as MediaViewerFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ParcelableMedia.Type.ANIMATED_GIF, ParcelableMedia.Type.CARD_ANIMATED_GIF -> {
|
ParcelableMedia.Type.ANIMATED_GIF, ParcelableMedia.Type.CARD_ANIMATED_GIF -> {
|
||||||
|
@ -408,10 +410,10 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSwipeOffsetChanged(offset: Int) {
|
override fun onSwipeOffsetChanged(offset: Int) {
|
||||||
val offsetFactor = 1 - (Math.abs(offset).toFloat() / swipeContainer.height)
|
val offsetFactor = 1 - (abs(offset).toFloat() / swipeContainer.height)
|
||||||
swipeContainer.backgroundAlpha = offsetFactor
|
swipeContainer.backgroundAlpha = offsetFactor
|
||||||
val colorToolbar = overrideTheme.colorToolbar
|
val colorToolbar = overrideTheme.colorToolbar
|
||||||
val alpha = Math.round(Color.alpha(colorToolbar) * offsetFactor).coerceIn(0..255)
|
val alpha = (Color.alpha(colorToolbar) * offsetFactor).roundToInt().coerceIn(0..255)
|
||||||
activityLayout.statusBarAlpha = alpha / 255f
|
activityLayout.statusBarAlpha = alpha / 255f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,11 +466,10 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
|
||||||
if (checkAllSelfPermissionsGranted(AndroidPermissions.WRITE_EXTERNAL_STORAGE)) {
|
if (checkAllSelfPermissionsGranted(AndroidPermissions.WRITE_EXTERNAL_STORAGE)) {
|
||||||
saveToStorage()
|
saveToStorage()
|
||||||
} else {
|
} else {
|
||||||
val permissions: Array<String>
|
val permissions: Array<String> = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
arrayOf(AndroidPermissions.WRITE_EXTERNAL_STORAGE, AndroidPermissions.READ_EXTERNAL_STORAGE)
|
||||||
permissions = arrayOf(AndroidPermissions.WRITE_EXTERNAL_STORAGE, AndroidPermissions.READ_EXTERNAL_STORAGE)
|
|
||||||
} else {
|
} else {
|
||||||
permissions = arrayOf(AndroidPermissions.WRITE_EXTERNAL_STORAGE)
|
arrayOf(AndroidPermissions.WRITE_EXTERNAL_STORAGE)
|
||||||
}
|
}
|
||||||
PermissionRequestDialog.show(supportFragmentManager, getString(R.string.message_permission_request_save_media),
|
PermissionRequestDialog.show(supportFragmentManager, getString(R.string.message_permission_request_save_media),
|
||||||
permissions, REQUEST_PERMISSION_SAVE_MEDIA)
|
permissions, REQUEST_PERMISSION_SAVE_MEDIA)
|
||||||
|
@ -499,8 +500,7 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
|
||||||
|
|
||||||
private fun saveToStorage() {
|
private fun saveToStorage() {
|
||||||
val fileInfo = getCurrentCacheFileInfo(saveToStoragePosition) ?: return
|
val fileInfo = getCurrentCacheFileInfo(saveToStoragePosition) ?: return
|
||||||
val type = (fileInfo as? CacheProvider.CacheFileTypeSupport)?.cacheFileType
|
val pubDir = when ((fileInfo as? CacheProvider.CacheFileTypeSupport)?.cacheFileType) {
|
||||||
val pubDir = when (type) {
|
|
||||||
CacheFileType.VIDEO -> {
|
CacheFileType.VIDEO -> {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)
|
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)
|
||||||
|
@ -636,10 +636,10 @@ class MediaViewerActivity : BaseActivity(), IMediaViewerActivity, MediaSwipeClos
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private val REQUEST_SHARE_MEDIA = 201
|
private const val REQUEST_SHARE_MEDIA = 201
|
||||||
private val REQUEST_PERMISSION_SAVE_MEDIA = 202
|
private const val REQUEST_PERMISSION_SAVE_MEDIA = 202
|
||||||
private val REQUEST_PERMISSION_SHARE_MEDIA = 203
|
private const val REQUEST_PERMISSION_SHARE_MEDIA = 203
|
||||||
private val REQUEST_SELECT_SAVE_MEDIA = 204
|
private const val REQUEST_SELECT_SAVE_MEDIA = 204
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
|
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||||
const val FLAG_SYSTEM_UI_HIDE_BARS = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
|
const val FLAG_SYSTEM_UI_HIDE_BARS = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
|
||||||
|
|
|
@ -171,7 +171,7 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
|
||||||
override fun onDismiss(listView: ListView, reverseSortedPositions: IntArray) {
|
override fun onDismiss(listView: ListView, reverseSortedPositions: IntArray) {
|
||||||
val adapter = suggestionsList.adapter as SuggestionsAdapter
|
val adapter = suggestionsList.adapter as SuggestionsAdapter
|
||||||
val ids = LongArray(reverseSortedPositions.size)
|
val ids = LongArray(reverseSortedPositions.size)
|
||||||
for (i in 0 until reverseSortedPositions.size) {
|
for (i in reverseSortedPositions.indices) {
|
||||||
val position = reverseSortedPositions[i]
|
val position = reverseSortedPositions[i]
|
||||||
val item = adapter.getSuggestionItem(position) ?: return
|
val item = adapter.getSuggestionItem(position) ?: return
|
||||||
ids[i] = item._id
|
ids[i] = item._id
|
||||||
|
@ -505,7 +505,7 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
|
||||||
private fun getActualPosition(position: Int): Int {
|
private fun getActualPosition(position: Int): Int {
|
||||||
var skipped = 0
|
var skipped = 0
|
||||||
for (i in 0 until removedPositions.size) {
|
for (i in 0 until removedPositions.size) {
|
||||||
if (position + skipped >= removedPositions.get(i)) {
|
if (position + skipped >= removedPositions[i]) {
|
||||||
skipped++
|
skipped++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -538,10 +538,10 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
internal val VIEW_TYPE_SEARCH_HISTORY = 0
|
internal const val VIEW_TYPE_SEARCH_HISTORY = 0
|
||||||
internal val VIEW_TYPE_SAVED_SEARCH = 1
|
internal const val VIEW_TYPE_SAVED_SEARCH = 1
|
||||||
internal val VIEW_TYPE_USER_SUGGESTION_ITEM = 2
|
internal const val VIEW_TYPE_USER_SUGGESTION_ITEM = 2
|
||||||
internal val VIEW_TYPE_USER_SCREEN_NAME = 3
|
internal const val VIEW_TYPE_USER_SCREEN_NAME = 3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ import org.mariotaku.twidere.util.DeviceUtils
|
||||||
import org.mariotaku.twidere.util.KeyboardShortcutsHandler
|
import org.mariotaku.twidere.util.KeyboardShortcutsHandler
|
||||||
import org.mariotaku.twidere.util.ThemeUtils
|
import org.mariotaku.twidere.util.ThemeUtils
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
class SettingsActivity : BaseActivity(), OnItemClickListener, OnPreferenceStartFragmentCallback {
|
class SettingsActivity : BaseActivity(), OnItemClickListener, OnPreferenceStartFragmentCallback {
|
||||||
|
|
||||||
|
@ -74,8 +75,7 @@ class SettingsActivity : BaseActivity(), OnItemClickListener, OnPreferenceStartF
|
||||||
shouldTerminate = savedInstanceState.getBoolean(EXTRA_SHOULD_TERMINATE, shouldTerminate)
|
shouldTerminate = savedInstanceState.getBoolean(EXTRA_SHOULD_TERMINATE, shouldTerminate)
|
||||||
} else if (intent.getBooleanExtra(EXTRA_SHOULD_TERMINATE, false)) {
|
} else if (intent.getBooleanExtra(EXTRA_SHOULD_TERMINATE, false)) {
|
||||||
finishNoRestart()
|
finishNoRestart()
|
||||||
System.exit(0)
|
exitProcess(0)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val backgroundOption = currentThemeBackgroundOption
|
val backgroundOption = currentThemeBackgroundOption
|
||||||
|
@ -349,8 +349,8 @@ class SettingsActivity : BaseActivity(), OnItemClickListener, OnPreferenceStartF
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val VIEW_TYPE_PREFERENCE_ENTRY = 0
|
const val VIEW_TYPE_PREFERENCE_ENTRY = 0
|
||||||
val VIEW_TYPE_HEADER_ENTRY = 1
|
const val VIEW_TYPE_HEADER_ENTRY = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,7 +424,7 @@ class SettingsActivity : BaseActivity(), OnItemClickListener, OnPreferenceStartF
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private val RESULT_SETTINGS_CHANGED = 10
|
private const val RESULT_SETTINGS_CHANGED = 10
|
||||||
|
|
||||||
fun setShouldRecreate(activity: Activity) {
|
fun setShouldRecreate(activity: Activity) {
|
||||||
if (activity !is SettingsActivity) return
|
if (activity !is SettingsActivity) return
|
||||||
|
|
|
@ -428,24 +428,31 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
||||||
internal fun onSignInError(exception: Exception) {
|
internal fun onSignInError(exception: Exception) {
|
||||||
DebugLog.w(LOGTAG, "Sign in error", exception)
|
DebugLog.w(LOGTAG, "Sign in error", exception)
|
||||||
var errorReason: String? = null
|
var errorReason: String? = null
|
||||||
if (exception is AuthenticityTokenException) {
|
when (exception) {
|
||||||
|
is AuthenticityTokenException -> {
|
||||||
Toast.makeText(this, R.string.message_toast_wrong_api_key, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.message_toast_wrong_api_key, Toast.LENGTH_SHORT).show()
|
||||||
errorReason = "wrong_api_key"
|
errorReason = "wrong_api_key"
|
||||||
} else if (exception is WrongUserPassException) {
|
}
|
||||||
|
is WrongUserPassException -> {
|
||||||
Toast.makeText(this, R.string.message_toast_wrong_username_password, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.message_toast_wrong_username_password, Toast.LENGTH_SHORT).show()
|
||||||
errorReason = "wrong_username_password"
|
errorReason = "wrong_username_password"
|
||||||
} else if (exception is SignInTask.WrongBasicCredentialException) {
|
}
|
||||||
|
is SignInTask.WrongBasicCredentialException -> {
|
||||||
Toast.makeText(this, R.string.message_toast_wrong_username_password, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.message_toast_wrong_username_password, Toast.LENGTH_SHORT).show()
|
||||||
errorReason = "wrong_username_password"
|
errorReason = "wrong_username_password"
|
||||||
} else if (exception is SignInTask.WrongAPIURLFormatException) {
|
}
|
||||||
|
is SignInTask.WrongAPIURLFormatException -> {
|
||||||
Toast.makeText(this, R.string.message_toast_wrong_api_key, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.message_toast_wrong_api_key, Toast.LENGTH_SHORT).show()
|
||||||
errorReason = "wrong_api_key"
|
errorReason = "wrong_api_key"
|
||||||
} else if (exception is LoginVerificationException) {
|
}
|
||||||
|
is LoginVerificationException -> {
|
||||||
Toast.makeText(this, R.string.message_toast_login_verification_failed, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.message_toast_login_verification_failed, Toast.LENGTH_SHORT).show()
|
||||||
errorReason = "login_verification_failed"
|
errorReason = "login_verification_failed"
|
||||||
} else {
|
}
|
||||||
|
else -> {
|
||||||
Toast.makeText(this, exception.getErrorMessage(this), Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, exception.getErrorMessage(this), Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Analyzer.log(SignIn(false, credentialsType = apiConfig.credentialsType,
|
Analyzer.log(SignIn(false, credentialsType = apiConfig.credentialsType,
|
||||||
errorReason = errorReason, accountType = apiConfig.type))
|
errorReason = errorReason, accountType = apiConfig.type))
|
||||||
}
|
}
|
||||||
|
@ -809,10 +816,10 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
||||||
val oauth = newMicroBlogInstance(context, endpoint = endpoint, auth = auth,
|
val oauth = newMicroBlogInstance(context, endpoint = endpoint, auth = auth,
|
||||||
accountType = apiConfig.type, cls = TwitterOAuth::class.java)
|
accountType = apiConfig.type, cls = TwitterOAuth::class.java)
|
||||||
val accessToken: OAuthToken
|
val accessToken: OAuthToken
|
||||||
if (oauthVerifier != null) {
|
accessToken = if (oauthVerifier != null) {
|
||||||
accessToken = oauth.getAccessToken(requestToken, oauthVerifier)
|
oauth.getAccessToken(requestToken, oauthVerifier)
|
||||||
} else {
|
} else {
|
||||||
accessToken = oauth.getAccessToken(requestToken)
|
oauth.getAccessToken(requestToken)
|
||||||
}
|
}
|
||||||
auth = apiConfig.getOAuthAuthorization(accessToken) ?:
|
auth = apiConfig.getOAuthAuthorization(accessToken) ?:
|
||||||
throw MicroBlogException("Invalid OAuth credential")
|
throw MicroBlogException("Invalid OAuth credential")
|
||||||
|
@ -823,7 +830,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
||||||
accountType = apiConfig.type, cls = MicroBlog::class.java)
|
accountType = apiConfig.type, cls = MicroBlog::class.java)
|
||||||
val apiUser = twitter.verifyCredentials()
|
val apiUser = twitter.verifyCredentials()
|
||||||
var color = analyseUserProfileColor(apiUser)
|
var color = analyseUserProfileColor(apiUser)
|
||||||
val (type, extras) = SignInActivity.detectAccountType(twitter, apiUser, apiConfig.type)
|
val (type, extras) = detectAccountType(twitter, apiUser, apiConfig.type)
|
||||||
val accountKey = apiUser.key
|
val accountKey = apiUser.key
|
||||||
val user = apiUser.toParcelable(accountKey, type, profileImageSize = profileImageSize)
|
val user = apiUser.toParcelable(accountKey, type, profileImageSize = profileImageSize)
|
||||||
val am = AccountManager.get(context)
|
val am = AccountManager.get(context)
|
||||||
|
@ -901,7 +908,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
||||||
return authOAuth()
|
return authOAuth()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(OAuthPasswordAuthenticator.AuthenticationException::class, MicroBlogException::class)
|
@Throws(AuthenticationException::class, MicroBlogException::class)
|
||||||
private fun authOAuth(): SignInResponse {
|
private fun authOAuth(): SignInResponse {
|
||||||
val activity = activityRef.get() ?: throw InterruptedException()
|
val activity = activityRef.get() ?: throw InterruptedException()
|
||||||
val endpoint = MicroBlogAPIFactory.getOAuthSignInEndpoint(apiUrlFormat,
|
val endpoint = MicroBlogAPIFactory.getOAuthSignInEndpoint(apiUrlFormat,
|
||||||
|
@ -940,7 +947,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
||||||
return getOAuthSignInResponse(activity, accessToken, Credentials.Type.XAUTH)
|
return getOAuthSignInResponse(activity, accessToken, Credentials.Type.XAUTH)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(MicroBlogException::class, OAuthPasswordAuthenticator.AuthenticationException::class)
|
@Throws(MicroBlogException::class, AuthenticationException::class)
|
||||||
private fun authBasic(): SignInResponse {
|
private fun authBasic(): SignInResponse {
|
||||||
val activity = activityRef.get() ?: throw InterruptedException()
|
val activity = activityRef.get() ?: throw InterruptedException()
|
||||||
val versionSuffix = if (apiConfig.isNoVersionSuffix) null else "1.1"
|
val versionSuffix = if (apiConfig.isNoVersionSuffix) null else "1.1"
|
||||||
|
@ -962,7 +969,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
||||||
}
|
}
|
||||||
|
|
||||||
var color = analyseUserProfileColor(apiUser)
|
var color = analyseUserProfileColor(apiUser)
|
||||||
val (type, extras) = SignInActivity.detectAccountType(twitter, apiUser, apiConfig.type)
|
val (type, extras) = detectAccountType(twitter, apiUser, apiConfig.type)
|
||||||
val accountKey = apiUser.key
|
val accountKey = apiUser.key
|
||||||
val user = apiUser.toParcelable(accountKey, type, profileImageSize = profileImageSize)
|
val user = apiUser.toParcelable(accountKey, type, profileImageSize = profileImageSize)
|
||||||
val am = AccountManager.get(activity)
|
val am = AccountManager.get(activity)
|
||||||
|
@ -991,7 +998,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
||||||
accountType = apiConfig.type, cls = MicroBlog::class.java)
|
accountType = apiConfig.type, cls = MicroBlog::class.java)
|
||||||
val apiUser = twitter.verifyCredentials()
|
val apiUser = twitter.verifyCredentials()
|
||||||
var color = analyseUserProfileColor(apiUser)
|
var color = analyseUserProfileColor(apiUser)
|
||||||
val (type, extras) = SignInActivity.detectAccountType(twitter, apiUser, apiConfig.type)
|
val (type, extras) = detectAccountType(twitter, apiUser, apiConfig.type)
|
||||||
val accountKey = apiUser.key
|
val accountKey = apiUser.key
|
||||||
val user = apiUser.toParcelable(accountKey, type, profileImageSize = profileImageSize)
|
val user = apiUser.toParcelable(accountKey, type, profileImageSize = profileImageSize)
|
||||||
val am = AccountManager.get(activity)
|
val am = AccountManager.get(activity)
|
||||||
|
@ -1018,7 +1025,7 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
||||||
accountType = apiConfig.type, cls = MicroBlog::class.java)
|
accountType = apiConfig.type, cls = MicroBlog::class.java)
|
||||||
val apiUser = twitter.verifyCredentials()
|
val apiUser = twitter.verifyCredentials()
|
||||||
var color = analyseUserProfileColor(apiUser)
|
var color = analyseUserProfileColor(apiUser)
|
||||||
val (type, extras) = SignInActivity.detectAccountType(twitter, apiUser, apiConfig.type)
|
val (type, extras) = detectAccountType(twitter, apiUser, apiConfig.type)
|
||||||
val accountKey = apiUser.key
|
val accountKey = apiUser.key
|
||||||
val user = apiUser.toParcelable(accountKey, type, profileImageSize = profileImageSize)
|
val user = apiUser.toParcelable(accountKey, type, profileImageSize = profileImageSize)
|
||||||
val am = AccountManager.get(activity)
|
val am = AccountManager.get(activity)
|
||||||
|
@ -1040,11 +1047,11 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
||||||
return SignInResponse(account != null, authType, credentials, user, color, type, extras)
|
return SignInResponse(account != null, authType, credentials, user, color, type, extras)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class WrongBasicCredentialException : OAuthPasswordAuthenticator.AuthenticationException()
|
internal class WrongBasicCredentialException : AuthenticationException()
|
||||||
|
|
||||||
internal class WrongAPIURLFormatException : OAuthPasswordAuthenticator.AuthenticationException()
|
internal class WrongAPIURLFormatException : AuthenticationException()
|
||||||
|
|
||||||
internal inner class InputLoginVerificationCallback : OAuthPasswordAuthenticator.LoginVerificationCallback {
|
internal inner class InputLoginVerificationCallback : LoginVerificationCallback {
|
||||||
|
|
||||||
override fun getLoginVerification(challengeType: String): String? {
|
override fun getLoginVerification(challengeType: String): String? {
|
||||||
// Dismiss current progress dialog
|
// Dismiss current progress dialog
|
||||||
|
@ -1087,10 +1094,10 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
||||||
protected val profileImageSize: String = activity.getString(R.string.profile_image_size)
|
protected val profileImageSize: String = activity.getString(R.string.profile_image_size)
|
||||||
|
|
||||||
final override fun doInBackground(vararg args: Any?): SingleResponse<SignInResponse> {
|
final override fun doInBackground(vararg args: Any?): SingleResponse<SignInResponse> {
|
||||||
try {
|
return try {
|
||||||
return SingleResponse.getInstance(performLogin())
|
SingleResponse.getInstance(performLogin())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
return SingleResponse.getInstance(e)
|
SingleResponse.getInstance(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1189,8 +1196,8 @@ class SignInActivity : BaseActivity(), OnClickListener, TextWatcher,
|
||||||
const val REQUEST_BROWSER_TWITTER_SIGN_IN = 101
|
const val REQUEST_BROWSER_TWITTER_SIGN_IN = 101
|
||||||
const val REQUEST_BROWSER_MASTODON_SIGN_IN = 102
|
const val REQUEST_BROWSER_MASTODON_SIGN_IN = 102
|
||||||
|
|
||||||
private val FRAGMENT_TAG_SIGN_IN_PROGRESS = "sign_in_progress"
|
private const val FRAGMENT_TAG_SIGN_IN_PROGRESS = "sign_in_progress"
|
||||||
private val EXTRA_API_LAST_CHANGE = "api_last_change"
|
private const val EXTRA_API_LAST_CHANGE = "api_last_change"
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
internal fun detectAccountType(twitter: MicroBlog, user: User, type: String?): Pair<String, AccountExtras?> {
|
internal fun detectAccountType(twitter: MicroBlog, user: User, type: String?): Pair<String, AccountExtras?> {
|
||||||
|
|
|
@ -41,8 +41,8 @@ class ThemedMediaPickerActivity : MediaPickerActivity() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun withThemed(context: Context): MediaPickerActivity.IntentBuilder {
|
fun withThemed(context: Context): IntentBuilder {
|
||||||
val builder = MediaPickerActivity.IntentBuilder(context, ThemedMediaPickerActivity::class.java)
|
val builder = IntentBuilder(context, ThemedMediaPickerActivity::class.java)
|
||||||
builder.cropImageActivityClass(ImageCropperActivity::class.java)
|
builder.cropImageActivityClass(ImageCropperActivity::class.java)
|
||||||
builder.streamDownloaderClass(RestFuNetworkStreamDownloader::class.java)
|
builder.streamDownloaderClass(RestFuNetworkStreamDownloader::class.java)
|
||||||
return builder
|
return builder
|
||||||
|
|
|
@ -177,23 +177,14 @@ class TrendsLocationSelectorActivity : BaseActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getGroupView(groupPosition: Int, isExpanded: Boolean, convertView: View?, parent: ViewGroup): View {
|
override fun getGroupView(groupPosition: Int, isExpanded: Boolean, convertView: View?, parent: ViewGroup): View {
|
||||||
val view: View
|
val view: View = convertView ?: inflater.inflate(android.R.layout.simple_expandable_list_item_1, parent, false)
|
||||||
if (convertView != null) {
|
|
||||||
view = convertView
|
|
||||||
} else {
|
|
||||||
view = inflater.inflate(android.R.layout.simple_expandable_list_item_1, parent, false)
|
|
||||||
}
|
|
||||||
view.findViewById<TextView>(android.R.id.text1).text = getGroup(groupPosition).name
|
view.findViewById<TextView>(android.R.id.text1).text = getGroup(groupPosition).name
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getChildView(groupPosition: Int, childPosition: Int, isLastChild: Boolean, convertView: View?, parent: ViewGroup): View {
|
override fun getChildView(groupPosition: Int, childPosition: Int, isLastChild: Boolean, convertView: View?, parent: ViewGroup): View {
|
||||||
val view: View
|
val view: View =
|
||||||
if (convertView != null) {
|
convertView ?: inflater.inflate(android.R.layout.simple_list_item_1, parent, false)
|
||||||
view = convertView
|
|
||||||
} else {
|
|
||||||
view = inflater.inflate(android.R.layout.simple_list_item_1, parent, false)
|
|
||||||
}
|
|
||||||
val location = getChild(groupPosition, childPosition)
|
val location = getChild(groupPosition, childPosition)
|
||||||
val text1 = view.findViewById<TextView>(android.R.id.text1)
|
val text1 = view.findViewById<TextView>(android.R.id.text1)
|
||||||
if (location.parentId == WORLDWIDE) {
|
if (location.parentId == WORLDWIDE) {
|
||||||
|
|
|
@ -95,8 +95,7 @@ class UserListSelectorActivity : BaseActivity(),
|
||||||
listView.setOnScrollListener(handler)
|
listView.setOnScrollListener(handler)
|
||||||
listView.setOnTouchListener(handler.touchListener)
|
listView.setOnTouchListener(handler.touchListener)
|
||||||
listView.onItemClickListener = OnItemClickListener { view, _, position, _ ->
|
listView.onItemClickListener = OnItemClickListener { view, _, position, _ ->
|
||||||
val item = view.getItemAtPosition(position)
|
when (val item = view.getItemAtPosition(position)) {
|
||||||
when (item) {
|
|
||||||
is ParcelableUserList -> {
|
is ParcelableUserList -> {
|
||||||
val data = Intent()
|
val data = Intent()
|
||||||
data.putExtra(EXTRA_USER_LIST, item)
|
data.putExtra(EXTRA_USER_LIST, item)
|
||||||
|
|
|
@ -114,7 +114,10 @@ class UserSelectorActivity : BaseActivity(), OnItemClickListener, LoaderManager.
|
||||||
if (!fromCache) {
|
if (!fromCache) {
|
||||||
showProgress()
|
showProgress()
|
||||||
}
|
}
|
||||||
return CacheUserSearchLoader(this, accountKey, query, !fromCache, true, true)
|
return CacheUserSearchLoader(this, accountKey, query, !fromCache,
|
||||||
|
fromCache = true,
|
||||||
|
fromUser = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLoaderReset(loader: Loader<List<ParcelableUser>>) {
|
override fun onLoaderReset(loader: Loader<List<ParcelableUser>>) {
|
||||||
|
@ -126,14 +129,18 @@ class UserSelectorActivity : BaseActivity(), OnItemClickListener, LoaderManager.
|
||||||
listContainer.visibility = View.VISIBLE
|
listContainer.visibility = View.VISIBLE
|
||||||
adapter.setData(data, true)
|
adapter.setData(data, true)
|
||||||
loader as CacheUserSearchLoader
|
loader as CacheUserSearchLoader
|
||||||
if (data.isNotNullOrEmpty()) {
|
when {
|
||||||
|
data.isNotNullOrEmpty() -> {
|
||||||
showList()
|
showList()
|
||||||
} else if (loader.query.isEmpty()) {
|
}
|
||||||
|
loader.query.isEmpty() -> {
|
||||||
showSearchHint()
|
showSearchHint()
|
||||||
} else {
|
}
|
||||||
|
else -> {
|
||||||
showNotFound()
|
showNotFound()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun searchUser(accountKey: UserKey, query: String, fromCache: Boolean) {
|
private fun searchUser(accountKey: UserKey, query: String, fromCache: Boolean) {
|
||||||
if (isEmpty(query)) {
|
if (isEmpty(query)) {
|
||||||
|
|
|
@ -47,7 +47,7 @@ class WebLinkHandlerActivity : Activity() {
|
||||||
startActivity(handledIntent)
|
startActivity(handledIntent)
|
||||||
} else {
|
} else {
|
||||||
if (!handledSuccessfully) {
|
if (!handledSuccessfully) {
|
||||||
Analyzer.logException(TwitterLinkException("Unable to handle twitter uri " + uri))
|
Analyzer.logException(TwitterLinkException("Unable to handle twitter uri $uri"))
|
||||||
}
|
}
|
||||||
val fallbackIntent = Intent(Intent.ACTION_VIEW, uri)
|
val fallbackIntent = Intent(Intent.ACTION_VIEW, uri)
|
||||||
fallbackIntent.addCategory(Intent.CATEGORY_BROWSABLE)
|
fallbackIntent.addCategory(Intent.CATEGORY_BROWSABLE)
|
||||||
|
@ -277,7 +277,7 @@ class WebLinkHandlerActivity : Activity() {
|
||||||
sb.append(text)
|
sb.append(text)
|
||||||
}
|
}
|
||||||
if (!url.isNullOrEmpty()) {
|
if (!url.isNullOrEmpty()) {
|
||||||
if (!sb.isEmpty()) {
|
if (sb.isNotEmpty()) {
|
||||||
sb.append(" ")
|
sb.append(" ")
|
||||||
}
|
}
|
||||||
sb.append(url)
|
sb.append(url)
|
||||||
|
@ -366,7 +366,7 @@ class WebLinkHandlerActivity : Activity() {
|
||||||
"photo", "album", "paipai", "q", "userview", "dialogue")
|
"photo", "album", "paipai", "q", "userview", "dialogue")
|
||||||
|
|
||||||
|
|
||||||
private val AUTHORITY_TWITTER_COM = "twitter.com"
|
private const val AUTHORITY_TWITTER_COM = "twitter.com"
|
||||||
|
|
||||||
|
|
||||||
private fun regulateTwitterUri(data: Uri): Uri {
|
private fun regulateTwitterUri(data: Uri): Uri {
|
||||||
|
|
|
@ -63,12 +63,12 @@ interface IControlBarActivity {
|
||||||
}
|
}
|
||||||
val animator: ObjectAnimator
|
val animator: ObjectAnimator
|
||||||
val offset = activity.controlBarOffset
|
val offset = activity.controlBarOffset
|
||||||
if (visible) {
|
animator = if (visible) {
|
||||||
if (offset >= 1) return
|
if (offset >= 1) return
|
||||||
animator = ObjectAnimator.ofFloat(activity, ControlBarOffsetProperty, offset, 1f)
|
ObjectAnimator.ofFloat(activity, ControlBarOffsetProperty, offset, 1f)
|
||||||
} else {
|
} else {
|
||||||
if (offset <= 0) return
|
if (offset <= 0) return
|
||||||
animator = ObjectAnimator.ofFloat(activity, ControlBarOffsetProperty, offset, 0f)
|
ObjectAnimator.ofFloat(activity, ControlBarOffsetProperty, offset, 0f)
|
||||||
}
|
}
|
||||||
animator.interpolator = DecelerateInterpolator()
|
animator.interpolator = DecelerateInterpolator()
|
||||||
animator.addListener(object : AnimatorListener {
|
animator.addListener(object : AnimatorListener {
|
||||||
|
|
|
@ -31,6 +31,7 @@ import org.mariotaku.twidere.model.AccountDetails
|
||||||
import org.mariotaku.twidere.view.holder.AccountProfileImageViewHolder
|
import org.mariotaku.twidere.view.holder.AccountProfileImageViewHolder
|
||||||
import org.mariotaku.twidere.view.transformer.AccountsSelectorTransformer
|
import org.mariotaku.twidere.view.transformer.AccountsSelectorTransformer
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
class AccountSelectorAdapter(
|
class AccountSelectorAdapter(
|
||||||
private val inflater: LayoutInflater,
|
private val inflater: LayoutInflater,
|
||||||
|
@ -46,7 +47,7 @@ class AccountSelectorAdapter(
|
||||||
set(value) {
|
set(value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
val previousAccounts = accounts
|
val previousAccounts = accounts
|
||||||
if (previousAccounts != null) {
|
field = if (previousAccounts != null) {
|
||||||
val tmpList = arrayListOf(*value)
|
val tmpList = arrayListOf(*value)
|
||||||
val tmpResult = ArrayList<AccountDetails>()
|
val tmpResult = ArrayList<AccountDetails>()
|
||||||
previousAccounts.forEach { previousAccount ->
|
previousAccounts.forEach { previousAccount ->
|
||||||
|
@ -56,9 +57,9 @@ class AccountSelectorAdapter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tmpResult.addAll(tmpList)
|
tmpResult.addAll(tmpList)
|
||||||
field = tmpResult.toTypedArray()
|
tmpResult.toTypedArray()
|
||||||
} else {
|
} else {
|
||||||
field = value
|
value
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
field = null
|
field = null
|
||||||
|
@ -115,16 +116,16 @@ class AccountSelectorAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getCount(): Int {
|
override fun getCount(): Int {
|
||||||
return Math.max(3, accountsCount)
|
return max(3, accountsCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
val accountStart: Int
|
val accountStart: Int
|
||||||
get() = Math.max(0, 3 - accountsCount)
|
get() = max(0, 3 - accountsCount)
|
||||||
|
|
||||||
val accountsCount: Int
|
val accountsCount: Int
|
||||||
get() {
|
get() {
|
||||||
val accounts = this.accounts ?: return 0
|
val accounts = this.accounts ?: return 0
|
||||||
return Math.max(0, accounts.size - 1)
|
return max(0, accounts.size - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPageWidth(position: Int): Float {
|
override fun getPageWidth(position: Int): Float {
|
||||||
|
|
|
@ -80,14 +80,18 @@ class DummyItemAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getStatus(position: Int, raw: Boolean): ParcelableStatus {
|
override fun getStatus(position: Int, raw: Boolean): ParcelableStatus {
|
||||||
if (adapter is ParcelableStatusesAdapter) {
|
return when (adapter) {
|
||||||
return adapter.getStatus(position, raw)
|
is ParcelableStatusesAdapter -> {
|
||||||
} else if (adapter is VariousItemsAdapter) {
|
adapter.getStatus(position, raw)
|
||||||
return adapter.getItem(position) as ParcelableStatus
|
}
|
||||||
} else if (adapter is ParcelableActivitiesAdapter) {
|
is VariousItemsAdapter -> {
|
||||||
return adapter.getActivity(position).activityStatus!!
|
adapter.getItem(position) as ParcelableStatus
|
||||||
|
}
|
||||||
|
is ParcelableActivitiesAdapter -> {
|
||||||
|
adapter.getActivity(position).activityStatus!!
|
||||||
|
}
|
||||||
|
else -> throw IndexOutOfBoundsException()
|
||||||
}
|
}
|
||||||
throw IndexOutOfBoundsException()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getStatusCount(raw: Boolean) = 0
|
override fun getStatusCount(raw: Boolean) = 0
|
||||||
|
|
|
@ -150,20 +150,19 @@ class MessagesConversationAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getItemViewType(position: Int): Int {
|
||||||
val countIndex = itemCounts.getItemCountIndex(position)
|
return when (val countIndex = itemCounts.getItemCountIndex(position)) {
|
||||||
when (countIndex) {
|
|
||||||
ITEM_START_MESSAGE -> when (getMessage(position, reuse = true).message_type) {
|
ITEM_START_MESSAGE -> when (getMessage(position, reuse = true).message_type) {
|
||||||
MessageType.STICKER -> {
|
MessageType.STICKER -> {
|
||||||
return ITEM_TYPE_STICKER_MESSAGE
|
ITEM_TYPE_STICKER_MESSAGE
|
||||||
}
|
}
|
||||||
MessageType.CONVERSATION_CREATE, MessageType.JOIN_CONVERSATION,
|
MessageType.CONVERSATION_CREATE, MessageType.JOIN_CONVERSATION,
|
||||||
MessageType.PARTICIPANTS_LEAVE, MessageType.PARTICIPANTS_JOIN,
|
MessageType.PARTICIPANTS_LEAVE, MessageType.PARTICIPANTS_JOIN,
|
||||||
MessageType.CONVERSATION_NAME_UPDATE, MessageType.CONVERSATION_AVATAR_UPDATE -> {
|
MessageType.CONVERSATION_NAME_UPDATE, MessageType.CONVERSATION_AVATAR_UPDATE -> {
|
||||||
return ITEM_TYPE_NOTICE_MESSAGE
|
ITEM_TYPE_NOTICE_MESSAGE
|
||||||
}
|
}
|
||||||
else -> return ITEM_TYPE_TEXT_MESSAGE
|
else -> ITEM_TYPE_TEXT_MESSAGE
|
||||||
}
|
}
|
||||||
ITEM_START_LOAD_OLDER -> return ITEM_LOAD_OLDER_INDICATOR
|
ITEM_START_LOAD_OLDER -> ITEM_LOAD_OLDER_INDICATOR
|
||||||
else -> throw UnsupportedCountIndexException(countIndex, position)
|
else -> throw UnsupportedCountIndexException(countIndex, position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,10 +77,9 @@ class MessagesEntriesAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getItemViewType(position: Int): Int {
|
||||||
val countIndex = itemCounts.getItemCountIndex(position)
|
return when (val countIndex = itemCounts.getItemCountIndex(position)) {
|
||||||
when (countIndex) {
|
0 -> ITEM_TYPE_MESSAGE_ENTRY
|
||||||
0 -> return ITEM_TYPE_MESSAGE_ENTRY
|
1 -> ITEM_VIEW_TYPE_LOAD_INDICATOR
|
||||||
1 -> return ITEM_VIEW_TYPE_LOAD_INDICATOR
|
|
||||||
else -> throw UnsupportedCountIndexException(countIndex, position)
|
else -> throw UnsupportedCountIndexException(countIndex, position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,13 +152,12 @@ class ParcelableActivitiesAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemId(position: Int): Long {
|
override fun getItemId(position: Int): Long {
|
||||||
val countIndex = itemCounts.getItemCountIndex(position)
|
return when (val countIndex = itemCounts.getItemCountIndex(position)) {
|
||||||
when (countIndex) {
|
|
||||||
ITEM_INDEX_ACTIVITY -> {
|
ITEM_INDEX_ACTIVITY -> {
|
||||||
return getRowId(position, false)
|
getRowId(position, false)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
return (countIndex.toLong() shl 32) or getItemViewType(position).toLong()
|
(countIndex.toLong() shl 32) or getItemViewType(position).toLong()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,7 +215,7 @@ class ParcelableActivitiesAdapter(
|
||||||
return EmptyViewHolder(Space(context))
|
return EmptyViewHolder(Space(context))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw UnsupportedOperationException("Unsupported viewType " + viewType)
|
throw UnsupportedOperationException("Unsupported viewType $viewType")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -245,14 +244,12 @@ class ParcelableActivitiesAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getItemViewType(position: Int): Int {
|
||||||
val countIndex = getItemCountIndex(position)
|
when (val countIndex = getItemCountIndex(position)) {
|
||||||
when (countIndex) {
|
|
||||||
ITEM_INDEX_ACTIVITY -> {
|
ITEM_INDEX_ACTIVITY -> {
|
||||||
if (isGapItem(position)) {
|
if (isGapItem(position)) {
|
||||||
return ITEM_VIEW_TYPE_GAP
|
return ITEM_VIEW_TYPE_GAP
|
||||||
}
|
}
|
||||||
val action = getAction(position)
|
when (getAction(position)) {
|
||||||
when (action) {
|
|
||||||
Activity.Action.MENTION, Activity.Action.QUOTE, Activity.Action.REPLY -> {
|
Activity.Action.MENTION, Activity.Action.QUOTE, Activity.Action.REPLY -> {
|
||||||
return ITEM_VIEW_TYPE_STATUS
|
return ITEM_VIEW_TYPE_STATUS
|
||||||
}
|
}
|
||||||
|
@ -350,12 +347,12 @@ class ParcelableActivitiesAdapter(
|
||||||
throw IndexOutOfBoundsException("index: $position, valid range is $validRange")
|
throw IndexOutOfBoundsException("index: $position, valid range is $validRange")
|
||||||
}
|
}
|
||||||
val data = this.data!!
|
val data = this.data!!
|
||||||
if (reuse && data is ObjectCursor) {
|
return if (reuse && data is ObjectCursor) {
|
||||||
val activity = data.setInto(dataPosition, reuseActivity)
|
val activity = data.setInto(dataPosition, reuseActivity)
|
||||||
activity.after_filtered_sources = null
|
activity.after_filtered_sources = null
|
||||||
return activity
|
activity
|
||||||
} else {
|
} else {
|
||||||
return data[dataPosition]
|
data[dataPosition]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,7 +425,7 @@ class ParcelableActivitiesAdapter(
|
||||||
internal val text2 = itemView.findViewById<TextView>(android.R.id.text2)
|
internal val text2 = itemView.findViewById<TextView>(android.R.id.text2)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
text2.setSingleLine(false)
|
text2.isSingleLine = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
|
@ -529,7 +526,7 @@ class ParcelableActivitiesAdapter(
|
||||||
result = 31 * result + timestamp.hashCode()
|
result = 31 * result + timestamp.hashCode()
|
||||||
result = 31 * result + gap.hashCode()
|
result = 31 * result + gap.hashCode()
|
||||||
result = 31 * result + action.hashCode()
|
result = 31 * result + action.hashCode()
|
||||||
result = 31 * result + (filteredSources?.let { Arrays.hashCode(it) } ?: 0)
|
result = 31 * result + (filteredSources?.contentHashCode() ?: 0)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ class ParcelableGroupsAdapter(
|
||||||
return LoadIndicatorViewHolder(view)
|
return LoadIndicatorViewHolder(view)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw IllegalStateException("Unknown view type " + viewType)
|
throw IllegalStateException("Unknown view type $viewType")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
@ -142,6 +142,6 @@ class ParcelableGroupsAdapter(
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val ITEM_VIEW_TYPE_USER_LIST = 2
|
const val ITEM_VIEW_TYPE_USER_LIST = 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,13 +171,16 @@ abstract class ParcelableStatusesAdapter(
|
||||||
|
|
||||||
override fun setData(data: List<ParcelableStatus>?): Boolean {
|
override fun setData(data: List<ParcelableStatus>?): Boolean {
|
||||||
var changed = true
|
var changed = true
|
||||||
if (data == null) {
|
when (data) {
|
||||||
|
null -> {
|
||||||
displayPositions = null
|
displayPositions = null
|
||||||
displayDataCount = 0
|
displayDataCount = 0
|
||||||
} else if (data is ObjectCursor) {
|
}
|
||||||
|
is ObjectCursor -> {
|
||||||
displayPositions = null
|
displayPositions = null
|
||||||
displayDataCount = data.size
|
displayDataCount = data.size
|
||||||
} else {
|
}
|
||||||
|
else -> {
|
||||||
var filteredCount = 0
|
var filteredCount = 0
|
||||||
displayPositions = IntArray(data.size).apply {
|
displayPositions = IntArray(data.size).apply {
|
||||||
data.forEachIndexed { i, item ->
|
data.forEachIndexed { i, item ->
|
||||||
|
@ -191,6 +194,7 @@ abstract class ParcelableStatusesAdapter(
|
||||||
displayDataCount = data.size - filteredCount
|
displayDataCount = data.size - filteredCount
|
||||||
changed = this.data != data
|
changed = this.data != data
|
||||||
}
|
}
|
||||||
|
}
|
||||||
this.data = data
|
this.data = data
|
||||||
this.infoCache = if (data != null) arrayOfNulls(data.size) else null
|
this.infoCache = if (data != null) arrayOfNulls(data.size) else null
|
||||||
gapLoadingIds.clear()
|
gapLoadingIds.clear()
|
||||||
|
@ -324,7 +328,7 @@ abstract class ParcelableStatusesAdapter(
|
||||||
return TimelineFilterHeaderViewHolder(this, view)
|
return TimelineFilterHeaderViewHolder(this, view)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw IllegalStateException("Unknown view type " + viewType)
|
throw IllegalStateException("Unknown view type $viewType")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
@ -350,8 +354,7 @@ abstract class ParcelableStatusesAdapter(
|
||||||
if (position == 0 && ILoadMoreSupportAdapter.START in loadMoreIndicatorPosition) {
|
if (position == 0 && ILoadMoreSupportAdapter.START in loadMoreIndicatorPosition) {
|
||||||
return ITEM_VIEW_TYPE_LOAD_INDICATOR
|
return ITEM_VIEW_TYPE_LOAD_INDICATOR
|
||||||
}
|
}
|
||||||
val countIndex = getItemCountIndex(position)
|
when (val countIndex = getItemCountIndex(position)) {
|
||||||
when (countIndex) {
|
|
||||||
ITEM_INDEX_LOAD_START_INDICATOR, ITEM_INDEX_LOAD_END_INDICATOR -> {
|
ITEM_INDEX_LOAD_START_INDICATOR, ITEM_INDEX_LOAD_END_INDICATOR -> {
|
||||||
return ITEM_VIEW_TYPE_LOAD_INDICATOR
|
return ITEM_VIEW_TYPE_LOAD_INDICATOR
|
||||||
}
|
}
|
||||||
|
@ -410,7 +413,7 @@ abstract class ParcelableStatusesAdapter(
|
||||||
// lesser equals than read position
|
// lesser equals than read position
|
||||||
if (positionKey <= 0) return RecyclerView.NO_POSITION
|
if (positionKey <= 0) return RecyclerView.NO_POSITION
|
||||||
val range = rangeOfSize(statusStartIndex, getStatusCount(raw))
|
val range = rangeOfSize(statusStartIndex, getStatusCount(raw))
|
||||||
if (range.isEmpty() || range.start < 0) return RecyclerView.NO_POSITION
|
if (range.isEmpty() || range.first < 0) return RecyclerView.NO_POSITION
|
||||||
if (positionKey < getStatusPositionKey(range.last, raw)) {
|
if (positionKey < getStatusPositionKey(range.last, raw)) {
|
||||||
return range.last
|
return range.last
|
||||||
}
|
}
|
||||||
|
@ -422,7 +425,7 @@ abstract class ParcelableStatusesAdapter(
|
||||||
// lesser equals than read position
|
// lesser equals than read position
|
||||||
if (sortId <= 0) return RecyclerView.NO_POSITION
|
if (sortId <= 0) return RecyclerView.NO_POSITION
|
||||||
val range = rangeOfSize(statusStartIndex, getStatusCount(raw))
|
val range = rangeOfSize(statusStartIndex, getStatusCount(raw))
|
||||||
if (range.isEmpty() || range.start < 0) return RecyclerView.NO_POSITION
|
if (range.isEmpty() || range.first < 0) return RecyclerView.NO_POSITION
|
||||||
if (sortId < getStatusSortId(range.last, raw)) {
|
if (sortId < getStatusSortId(range.last, raw)) {
|
||||||
return range.last
|
return range.last
|
||||||
}
|
}
|
||||||
|
@ -489,11 +492,11 @@ abstract class ParcelableStatusesAdapter(
|
||||||
} else {
|
} else {
|
||||||
dataPosition
|
dataPosition
|
||||||
}
|
}
|
||||||
if (reuse && data is ObjectCursor) {
|
return if (reuse && data is ObjectCursor) {
|
||||||
reuseStatus.is_filtered = false
|
reuseStatus.is_filtered = false
|
||||||
return data.setInto(listPosition, reuseStatus)
|
data.setInto(listPosition, reuseStatus)
|
||||||
} else {
|
} else {
|
||||||
return data[listPosition]
|
data[listPosition]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ class ParcelableUserListsAdapter(
|
||||||
return LoadIndicatorViewHolder(view)
|
return LoadIndicatorViewHolder(view)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw IllegalStateException("Unknown view type " + viewType)
|
throw IllegalStateException("Unknown view type $viewType")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
@ -122,7 +122,7 @@ class ParcelableUserListsAdapter(
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val ITEM_VIEW_TYPE_USER_LIST = 2
|
const val ITEM_VIEW_TYPE_USER_LIST = 2
|
||||||
|
|
||||||
fun createUserListViewHolder(adapter: IUserListsAdapter<*>,
|
fun createUserListViewHolder(adapter: IUserListsAdapter<*>,
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
|
|
|
@ -140,7 +140,7 @@ class ParcelableUsersAdapter(
|
||||||
return LoadIndicatorViewHolder(view)
|
return LoadIndicatorViewHolder(view)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw IllegalStateException("Unknown view type " + viewType)
|
throw IllegalStateException("Unknown view type $viewType")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
|
|
@ -77,7 +77,7 @@ class SelectableUsersAdapter(
|
||||||
return LoadIndicatorViewHolder(view)
|
return LoadIndicatorViewHolder(view)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw IllegalStateException("Unknown view type " + viewType)
|
throw IllegalStateException("Unknown view type $viewType")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
@ -89,18 +89,16 @@ class SelectableUsersAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getItemViewType(position: Int): Int {
|
||||||
val countIndex = itemCounts.getItemCountIndex(position)
|
return when (val countIndex = itemCounts.getItemCountIndex(position)) {
|
||||||
when (countIndex) {
|
ITEM_TYPE_START_INDICATOR, ITEM_TYPE_END_INDICATOR -> ITEM_VIEW_TYPE_LOAD_INDICATOR
|
||||||
ITEM_TYPE_START_INDICATOR, ITEM_TYPE_END_INDICATOR -> return ITEM_VIEW_TYPE_LOAD_INDICATOR
|
ITEM_TYPE_USER -> ITEM_VIEW_TYPE_USER
|
||||||
ITEM_TYPE_USER -> return ITEM_VIEW_TYPE_USER
|
|
||||||
else -> throw UnsupportedCountIndexException(countIndex, position)
|
else -> throw UnsupportedCountIndexException(countIndex, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemId(position: Int): Long {
|
override fun getItemId(position: Int): Long {
|
||||||
val countIndex = itemCounts.getItemCountIndex(position)
|
return when (val countIndex = itemCounts.getItemCountIndex(position)) {
|
||||||
return when (countIndex) {
|
|
||||||
ITEM_TYPE_START_INDICATOR, ITEM_TYPE_END_INDICATOR -> (countIndex.toLong() shl 32)
|
ITEM_TYPE_START_INDICATOR, ITEM_TYPE_END_INDICATOR -> (countIndex.toLong() shl 32)
|
||||||
ITEM_TYPE_USER -> (countIndex.toLong() shl 32) or getUser(position).hashCode().toLong()
|
ITEM_TYPE_USER -> (countIndex.toLong() shl 32) or getUser(position).hashCode().toLong()
|
||||||
else -> throw UnsupportedCountIndexException(countIndex, position)
|
else -> throw UnsupportedCountIndexException(countIndex, position)
|
||||||
|
|
|
@ -36,11 +36,7 @@ class SimpleParcelableUsersAdapter(
|
||||||
|
|
||||||
override fun getItemId(position: Int): Long {
|
override fun getItemId(position: Int): Long {
|
||||||
val item = getItem(position)
|
val item = getItem(position)
|
||||||
if (item != null) {
|
return item?.hashCode()?.toLong() ?: -1
|
||||||
return item.hashCode().toLong()
|
|
||||||
} else {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||||
|
|
|
@ -80,10 +80,10 @@ class StatusDetailsAdapter(
|
||||||
internal set
|
internal set
|
||||||
var translationResult: TranslationResult? = null
|
var translationResult: TranslationResult? = null
|
||||||
internal set(translation) {
|
internal set(translation) {
|
||||||
if (translation == null || status?.originalId != translation.id) {
|
field = if (translation == null || status?.originalId != translation.id) {
|
||||||
field = null
|
null
|
||||||
} else {
|
} else {
|
||||||
field = translation
|
translation
|
||||||
}
|
}
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
@ -402,7 +402,7 @@ class StatusDetailsAdapter(
|
||||||
if (position in typeStart until typeEnd) return type
|
if (position in typeStart until typeEnd) return type
|
||||||
typeStart = typeEnd
|
typeStart = typeEnd
|
||||||
}
|
}
|
||||||
throw IllegalStateException("Unknown position " + position)
|
throw IllegalStateException("Unknown position $position")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getItemTypeStart(position: Int): Int {
|
fun getItemTypeStart(position: Int): Int {
|
||||||
|
@ -502,10 +502,10 @@ class StatusDetailsAdapter(
|
||||||
var isConversationsLoading: Boolean
|
var isConversationsLoading: Boolean
|
||||||
get() = ILoadMoreSupportAdapter.START in loadMoreIndicatorPosition
|
get() = ILoadMoreSupportAdapter.START in loadMoreIndicatorPosition
|
||||||
set(loading) {
|
set(loading) {
|
||||||
if (loading) {
|
loadMoreIndicatorPosition = if (loading) {
|
||||||
loadMoreIndicatorPosition = loadMoreIndicatorPosition or ILoadMoreSupportAdapter.START
|
loadMoreIndicatorPosition or ILoadMoreSupportAdapter.START
|
||||||
} else {
|
} else {
|
||||||
loadMoreIndicatorPosition = loadMoreIndicatorPosition and ILoadMoreSupportAdapter.START.inv()
|
loadMoreIndicatorPosition and ILoadMoreSupportAdapter.START.inv()
|
||||||
}
|
}
|
||||||
updateItemDecoration()
|
updateItemDecoration()
|
||||||
}
|
}
|
||||||
|
@ -513,10 +513,10 @@ class StatusDetailsAdapter(
|
||||||
var isRepliesLoading: Boolean
|
var isRepliesLoading: Boolean
|
||||||
get() = ILoadMoreSupportAdapter.END in loadMoreIndicatorPosition
|
get() = ILoadMoreSupportAdapter.END in loadMoreIndicatorPosition
|
||||||
set(loading) {
|
set(loading) {
|
||||||
if (loading) {
|
loadMoreIndicatorPosition = if (loading) {
|
||||||
loadMoreIndicatorPosition = loadMoreIndicatorPosition or ILoadMoreSupportAdapter.END
|
loadMoreIndicatorPosition or ILoadMoreSupportAdapter.END
|
||||||
} else {
|
} else {
|
||||||
loadMoreIndicatorPosition = loadMoreIndicatorPosition and ILoadMoreSupportAdapter.END.inv()
|
loadMoreIndicatorPosition and ILoadMoreSupportAdapter.END.inv()
|
||||||
}
|
}
|
||||||
updateItemDecoration()
|
updateItemDecoration()
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,6 +162,6 @@ class SupportTabsAdapter(
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private val EXTRA_ADAPTER_POSITION = "adapter_position"
|
private const val EXTRA_ADAPTER_POSITION = "adapter_position"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,12 +87,12 @@ class VariousItemsAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getItemViewType(obj: Any): Int {
|
private fun getItemViewType(obj: Any): Int {
|
||||||
when (obj) {
|
return when (obj) {
|
||||||
is ParcelableStatus -> return VIEW_TYPE_STATUS
|
is ParcelableStatus -> VIEW_TYPE_STATUS
|
||||||
is ParcelableUser -> return VIEW_TYPE_USER
|
is ParcelableUser -> VIEW_TYPE_USER
|
||||||
is ParcelableUserList -> return VIEW_TYPE_USER_LIST
|
is ParcelableUserList -> VIEW_TYPE_USER_LIST
|
||||||
is ParcelableHashtag -> return VIEW_TYPE_HASHTAG
|
is ParcelableHashtag -> VIEW_TYPE_HASHTAG
|
||||||
else -> throw UnsupportedOperationException("Unsupported object " + obj)
|
else -> throw UnsupportedOperationException("Unsupported object $obj")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,9 +112,9 @@ class VariousItemsAdapter(
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val VIEW_TYPE_STATUS = 1
|
const val VIEW_TYPE_STATUS = 1
|
||||||
val VIEW_TYPE_USER = 2
|
const val VIEW_TYPE_USER = 2
|
||||||
val VIEW_TYPE_USER_LIST = 3
|
const val VIEW_TYPE_USER_LIST = 3
|
||||||
val VIEW_TYPE_HASHTAG = 4
|
const val VIEW_TYPE_HASHTAG = 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ interface ILoadMoreSupportAdapter {
|
||||||
annotation class IndicatorPosition
|
annotation class IndicatorPosition
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val ITEM_VIEW_TYPE_LOAD_INDICATOR = 0
|
const val ITEM_VIEW_TYPE_LOAD_INDICATOR = 0
|
||||||
|
|
||||||
const val NONE: Long = 0
|
const val NONE: Long = 0
|
||||||
const val START: Long = 1
|
const val START: Long = 1
|
||||||
|
|
|
@ -329,7 +329,7 @@ class TwidereApplication : Application(), OnSharedPreferenceChangeListener {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private val KEY_KEYBOARD_SHORTCUT_INITIALIZED = "keyboard_shortcut_initialized"
|
private const val KEY_KEYBOARD_SHORTCUT_INITIALIZED = "keyboard_shortcut_initialized"
|
||||||
var instance: TwidereApplication? = null
|
var instance: TwidereApplication? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
|
|
@ -147,10 +147,10 @@ object profileImageStyleKey : KSimpleKey<Int>(KEY_PROFILE_IMAGE_STYLE, ImageShap
|
||||||
|
|
||||||
object mediaPreviewStyleKey : KSimpleKey<Int>(KEY_MEDIA_PREVIEW_STYLE, PreviewStyle.CROP) {
|
object mediaPreviewStyleKey : KSimpleKey<Int>(KEY_MEDIA_PREVIEW_STYLE, PreviewStyle.CROP) {
|
||||||
override fun read(preferences: SharedPreferences): Int {
|
override fun read(preferences: SharedPreferences): Int {
|
||||||
when (preferences.getString(key, null)) {
|
return when (preferences.getString(key, null)) {
|
||||||
VALUE_MEDIA_PREVIEW_STYLE_SCALE -> return PreviewStyle.SCALE
|
VALUE_MEDIA_PREVIEW_STYLE_SCALE -> PreviewStyle.SCALE
|
||||||
VALUE_MEDIA_PREVIEW_STYLE_REAL_SIZE -> return PreviewStyle.ACTUAL_SIZE
|
VALUE_MEDIA_PREVIEW_STYLE_REAL_SIZE -> PreviewStyle.ACTUAL_SIZE
|
||||||
else -> return PreviewStyle.CROP
|
else -> PreviewStyle.CROP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package org.mariotaku.twidere.extension
|
package org.mariotaku.twidere.extension
|
||||||
|
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
fun BitmapFactory.Options.calculateInSampleSize(preferredWidth: Int, preferredHeight: Int): Int {
|
fun BitmapFactory.Options.calculateInSampleSize(preferredWidth: Int, preferredHeight: Int): Int {
|
||||||
if (preferredHeight > outHeight && preferredWidth > outWidth) {
|
if (preferredHeight > outHeight && preferredWidth > outWidth) {
|
||||||
|
@ -9,6 +11,7 @@ fun BitmapFactory.Options.calculateInSampleSize(preferredWidth: Int, preferredHe
|
||||||
if (preferredHeight <= 0 && preferredWidth <= 0) {
|
if (preferredHeight <= 0 && preferredWidth <= 0) {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
val result = Math.round(Math.max(outWidth, outHeight) / Math.max(preferredWidth, preferredHeight).toFloat())
|
val result = (max(outWidth, outHeight) / max(preferredWidth, preferredHeight)
|
||||||
return Math.max(1, result)
|
.toFloat()).roundToInt()
|
||||||
|
return max(1, result)
|
||||||
}
|
}
|
|
@ -114,19 +114,19 @@ fun RequestManager.loadProfileImage(context: Context, conversation: ParcelableMe
|
||||||
size: String? = null): RequestBuilder<*> {
|
size: String? = null): RequestBuilder<*> {
|
||||||
if (conversation.conversation_type == ParcelableMessageConversation.ConversationType.ONE_TO_ONE) {
|
if (conversation.conversation_type == ParcelableMessageConversation.ConversationType.ONE_TO_ONE) {
|
||||||
val user = conversation.user
|
val user = conversation.user
|
||||||
if (user != null) {
|
return if (user != null) {
|
||||||
return loadProfileImage(context, user, shapeStyle, cornerRadius, cornerRadiusRatio, size)
|
loadProfileImage(context, user, shapeStyle, cornerRadius, cornerRadiusRatio, size)
|
||||||
} else {
|
} else {
|
||||||
// TODO: show default conversation icon
|
// TODO: show default conversation icon
|
||||||
return loadProfileImage(context, R.drawable.ic_profile_image_default_group, shapeStyle,
|
loadProfileImage(context, R.drawable.ic_profile_image_default_group, shapeStyle,
|
||||||
cornerRadius, cornerRadiusRatio)
|
cornerRadius, cornerRadiusRatio)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (conversation.conversation_avatar != null) {
|
return if (conversation.conversation_avatar != null) {
|
||||||
return loadProfileImage(context, conversation.conversation_avatar, shapeStyle, cornerRadius,
|
loadProfileImage(context, conversation.conversation_avatar, shapeStyle, cornerRadius,
|
||||||
cornerRadiusRatio, size)
|
cornerRadiusRatio, size)
|
||||||
} else {
|
} else {
|
||||||
return loadProfileImage(context, R.drawable.ic_profile_image_default_group, shapeStyle,
|
loadProfileImage(context, R.drawable.ic_profile_image_default_group, shapeStyle,
|
||||||
cornerRadius, cornerRadiusRatio)
|
cornerRadius, cornerRadiusRatio)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,5 +30,5 @@ fun ListView.updateSelectionItems(menu: Menu) {
|
||||||
val listCount = count
|
val listCount = count
|
||||||
menu.setItemAvailability(R.id.select_none, checkedCount > 0)
|
menu.setItemAvailability(R.id.select_none, checkedCount > 0)
|
||||||
menu.setItemAvailability(R.id.select_all, checkedCount < listCount)
|
menu.setItemAvailability(R.id.select_all, checkedCount < listCount)
|
||||||
menu.setItemAvailability(R.id.invert_selection, checkedCount > 0 && checkedCount < listCount)
|
menu.setItemAvailability(R.id.invert_selection, checkedCount in 1 until listCount)
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,17 +62,17 @@ fun Rect.offsetEndTo(x: Int, layoutDirection: Int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Rect.getStart(layoutDirection: Int): Int {
|
fun Rect.getStart(layoutDirection: Int): Int {
|
||||||
if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL) {
|
return if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL) {
|
||||||
return this.right
|
this.right
|
||||||
} else {
|
} else {
|
||||||
return this.left
|
this.left
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Rect.getEnd(layoutDirection: Int): Int {
|
fun Rect.getEnd(layoutDirection: Int): Int {
|
||||||
if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL) {
|
return if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL) {
|
||||||
return this.left
|
this.left
|
||||||
} else {
|
} else {
|
||||||
return this.right
|
this.right
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -43,16 +43,20 @@ fun View.getFrame(rect: Rect) {
|
||||||
@UiThread
|
@UiThread
|
||||||
fun View.getFrameRelatedTo(rect: Rect, other: View? = null) {
|
fun View.getFrameRelatedTo(rect: Rect, other: View? = null) {
|
||||||
this.getFrame(rect)
|
this.getFrame(rect)
|
||||||
if (other == null) {
|
when {
|
||||||
|
other == null -> {
|
||||||
offsetToRoot(this, rect)
|
offsetToRoot(this, rect)
|
||||||
} else if (other === this) {
|
}
|
||||||
|
other === this -> {
|
||||||
rect.offsetTo(0, 0)
|
rect.offsetTo(0, 0)
|
||||||
} else if (other !== parent) {
|
}
|
||||||
|
other !== parent -> {
|
||||||
offsetToRoot(this, rect)
|
offsetToRoot(this, rect)
|
||||||
other.getFrame(tempRect)
|
other.getFrame(tempRect)
|
||||||
offsetToRoot(other, tempRect)
|
offsetToRoot(other, tempRect)
|
||||||
rect.offset(-tempRect.left, -tempRect.top)
|
rect.offset(-tempRect.left, -tempRect.top)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun View.getLocationOnScreen(rect: Rect) {
|
fun View.getLocationOnScreen(rect: Rect) {
|
||||||
|
|
|
@ -30,5 +30,5 @@ fun ContentTypeField.getIntParameter(name: String, def: Int): Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ContentTypeField.getBooleanParameter(name: String): Boolean {
|
fun ContentTypeField.getBooleanParameter(name: String): Boolean {
|
||||||
return getParameter(name).toBoolean()
|
return this.getParameter(name)!!.toBoolean()
|
||||||
}
|
}
|
|
@ -15,6 +15,7 @@ import org.mariotaku.twidere.util.InternalTwitterContentUtils
|
||||||
import org.mariotaku.twidere.util.text.FanfouValidator
|
import org.mariotaku.twidere.util.text.FanfouValidator
|
||||||
import org.mariotaku.twidere.util.text.MastodonValidator
|
import org.mariotaku.twidere.util.text.MastodonValidator
|
||||||
import org.mariotaku.twidere.util.text.TwitterValidator
|
import org.mariotaku.twidere.util.text.TwitterValidator
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
fun AccountDetails.isOfficial(context: Context?): Boolean {
|
fun AccountDetails.isOfficial(context: Context?): Boolean {
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
|
@ -115,10 +116,10 @@ val Array<AccountDetails>.textLimit: Int
|
||||||
forEach { details ->
|
forEach { details ->
|
||||||
val currentLimit = details.textLimit
|
val currentLimit = details.textLimit
|
||||||
if (currentLimit != 0) {
|
if (currentLimit != 0) {
|
||||||
if (limit <= 0) {
|
limit = if (limit <= 0) {
|
||||||
limit = currentLimit
|
currentLimit
|
||||||
} else {
|
} else {
|
||||||
limit = Math.min(limit, currentLimit)
|
min(limit, currentLimit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,10 +175,10 @@ internal object AccountDataQueue {
|
||||||
return callable.call()
|
return callable.call()
|
||||||
}
|
}
|
||||||
val future = executor.submit(callable)
|
val future = executor.submit(callable)
|
||||||
try {
|
return try {
|
||||||
return future.get(1, TimeUnit.SECONDS)
|
future.get(1, TimeUnit.SECONDS)
|
||||||
} catch (e: TimeoutException) {
|
} catch (e: TimeoutException) {
|
||||||
return manager.getUserData(account, key)
|
manager.getUserData(account, key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,10 +190,10 @@ internal object AccountDataQueue {
|
||||||
return callable.call()
|
return callable.call()
|
||||||
}
|
}
|
||||||
val future = executor.submit(callable)
|
val future = executor.submit(callable)
|
||||||
try {
|
return try {
|
||||||
return future.get(1, TimeUnit.SECONDS)
|
future.get(1, TimeUnit.SECONDS)
|
||||||
} catch (e: TimeoutException) {
|
} catch (e: TimeoutException) {
|
||||||
return manager.peekAuthToken(account, authTokenType)
|
manager.peekAuthToken(account, authTokenType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,12 +63,11 @@ fun Credentials.getAuthorization(cls: Class<*>?): Authorization {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Credentials.getEndpoint(cls: Class<*>): Endpoint {
|
fun Credentials.getEndpoint(cls: Class<*>): Endpoint {
|
||||||
val apiUrlFormat: String
|
|
||||||
val noVersionSuffix = this.no_version_suffix
|
val noVersionSuffix = this.no_version_suffix
|
||||||
if (!TextUtils.isEmpty(this.api_url_format)) {
|
val apiUrlFormat: String = if (!TextUtils.isEmpty(this.api_url_format)) {
|
||||||
apiUrlFormat = this.api_url_format
|
this.api_url_format
|
||||||
} else {
|
} else {
|
||||||
apiUrlFormat = DEFAULT_TWITTER_API_URL_FORMAT
|
DEFAULT_TWITTER_API_URL_FORMAT
|
||||||
}
|
}
|
||||||
val domain: String?
|
val domain: String?
|
||||||
val versionSuffix: String?
|
val versionSuffix: String?
|
||||||
|
@ -113,11 +112,10 @@ fun Credentials.getEndpoint(cls: Class<*>): Endpoint {
|
||||||
}
|
}
|
||||||
val endpointUrl = MicroBlogAPIFactory.getApiUrl(apiUrlFormat, domain, versionSuffix)
|
val endpointUrl = MicroBlogAPIFactory.getApiUrl(apiUrlFormat, domain, versionSuffix)
|
||||||
if (this is OAuthCredentials) {
|
if (this is OAuthCredentials) {
|
||||||
val signEndpointUrl: String
|
val signEndpointUrl: String = if (same_oauth_signing_url) {
|
||||||
if (same_oauth_signing_url) {
|
endpointUrl
|
||||||
signEndpointUrl = endpointUrl
|
|
||||||
} else {
|
} else {
|
||||||
signEndpointUrl = MicroBlogAPIFactory.getApiUrl(DEFAULT_TWITTER_API_URL_FORMAT, domain, versionSuffix)
|
MicroBlogAPIFactory.getApiUrl(DEFAULT_TWITTER_API_URL_FORMAT, domain, versionSuffix)
|
||||||
}
|
}
|
||||||
return OAuthEndpoint(endpointUrl, signEndpointUrl)
|
return OAuthEndpoint(endpointUrl, signEndpointUrl)
|
||||||
}
|
}
|
||||||
|
@ -180,11 +178,11 @@ internal fun Credentials.authorizationHeader(
|
||||||
): String {
|
): String {
|
||||||
val auth = getAuthorization(cls)
|
val auth = getAuthorization(cls)
|
||||||
val endpoint: Endpoint
|
val endpoint: Endpoint
|
||||||
if (auth is OAuthAuthorization) {
|
endpoint = if (auth is OAuthAuthorization) {
|
||||||
endpoint = OAuthEndpoint(TwidereMediaDownloader.getEndpoint(modifiedUri),
|
OAuthEndpoint(TwidereMediaDownloader.getEndpoint(modifiedUri),
|
||||||
TwidereMediaDownloader.getEndpoint(uri))
|
TwidereMediaDownloader.getEndpoint(uri))
|
||||||
} else {
|
} else {
|
||||||
endpoint = Endpoint(TwidereMediaDownloader.getEndpoint(modifiedUri))
|
Endpoint(TwidereMediaDownloader.getEndpoint(modifiedUri))
|
||||||
}
|
}
|
||||||
val queries = MultiValueMap<String>()
|
val queries = MultiValueMap<String>()
|
||||||
for (name in uri.queryParameterNames) {
|
for (name in uri.queryParameterNames) {
|
||||||
|
|
|
@ -122,23 +122,23 @@ fun Draft.readMimeMessageFrom(context: Context, st: InputStream): Boolean {
|
||||||
fun Draft.getActionName(context: Context): String? {
|
fun Draft.getActionName(context: Context): String? {
|
||||||
if (TextUtils.isEmpty(action_type)) return context.getString(R.string.update_status)
|
if (TextUtils.isEmpty(action_type)) return context.getString(R.string.update_status)
|
||||||
when (action_type) {
|
when (action_type) {
|
||||||
Draft.Action.UPDATE_STATUS, Draft.Action.UPDATE_STATUS_COMPAT_1,
|
Action.UPDATE_STATUS, Action.UPDATE_STATUS_COMPAT_1,
|
||||||
Draft.Action.UPDATE_STATUS_COMPAT_2 -> {
|
Action.UPDATE_STATUS_COMPAT_2 -> {
|
||||||
return context.getString(R.string.update_status)
|
return context.getString(R.string.update_status)
|
||||||
}
|
}
|
||||||
Draft.Action.REPLY -> {
|
Action.REPLY -> {
|
||||||
return context.getString(R.string.action_reply)
|
return context.getString(R.string.action_reply)
|
||||||
}
|
}
|
||||||
Draft.Action.QUOTE -> {
|
Action.QUOTE -> {
|
||||||
return context.getString(R.string.action_quote)
|
return context.getString(R.string.action_quote)
|
||||||
}
|
}
|
||||||
Draft.Action.FAVORITE -> {
|
Action.FAVORITE -> {
|
||||||
return context.getString(R.string.action_favorite)
|
return context.getString(R.string.action_favorite)
|
||||||
}
|
}
|
||||||
Draft.Action.RETWEET -> {
|
Action.RETWEET -> {
|
||||||
return context.getString(R.string.action_retweet)
|
return context.getString(R.string.action_retweet)
|
||||||
}
|
}
|
||||||
Draft.Action.SEND_DIRECT_MESSAGE, Draft.Action.SEND_DIRECT_MESSAGE_COMPAT -> {
|
Action.SEND_DIRECT_MESSAGE, Action.SEND_DIRECT_MESSAGE_COMPAT -> {
|
||||||
return context.getString(R.string.send_direct_message)
|
return context.getString(R.string.send_direct_message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,8 +157,8 @@ fun Draft.applyUpdateStatus(statusUpdate: ParcelableStatusUpdate) {
|
||||||
|
|
||||||
fun draftActionTypeString(@Draft.Action action: String?): String {
|
fun draftActionTypeString(@Draft.Action action: String?): String {
|
||||||
return when (action) {
|
return when (action) {
|
||||||
Draft.Action.QUOTE -> "quote"
|
Action.QUOTE -> "quote"
|
||||||
Draft.Action.REPLY -> "reply"
|
Action.REPLY -> "reply"
|
||||||
else -> "tweet"
|
else -> "tweet"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@ import androidx.core.os.LocaleListCompat
|
||||||
import org.mariotaku.ktextension.localesCompat
|
import org.mariotaku.ktextension.localesCompat
|
||||||
import org.mariotaku.twidere.model.presentation.LaunchPresentation
|
import org.mariotaku.twidere.model.presentation.LaunchPresentation
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
fun LaunchPresentation.shouldShow(context: Context): Boolean {
|
fun LaunchPresentation.shouldShow(context: Context): Boolean {
|
||||||
// Check language
|
// Check language
|
||||||
|
@ -69,16 +71,16 @@ fun LaunchPresentation.Image.displayingScore(viewDensity: Float, viewWidth: Int,
|
||||||
viewWidth < width && viewHeight < height -> {
|
viewWidth < width && viewHeight < height -> {
|
||||||
val diffW = (width / viewWidth.toFloat() - 1).coerceAtMost(0.5f)
|
val diffW = (width / viewWidth.toFloat() - 1).coerceAtMost(0.5f)
|
||||||
val diffH = (height / viewHeight.toFloat() - 1).coerceAtMost(0.5f)
|
val diffH = (height / viewHeight.toFloat() - 1).coerceAtMost(0.5f)
|
||||||
100 - Math.round(diffH * 100) - Math.round(diffW * 100)
|
100 - (diffH * 100).roundToInt() - (diffW * 100).roundToInt()
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val diffW = (width / viewWidth.toFloat() - 1).coerceAtMost(0.5f)
|
val diffW = (width / viewWidth.toFloat() - 1).coerceAtMost(0.5f)
|
||||||
val diffH = (height / viewHeight.toFloat() - 1).coerceAtMost(0.5f)
|
val diffH = (height / viewHeight.toFloat() - 1).coerceAtMost(0.5f)
|
||||||
100 - Math.round(diffH * 50) - Math.round(diffW * 50)
|
100 - (diffH * 50).roundToInt() - (diffW * 50).roundToInt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.density != 0f) {
|
if (this.density != 0f) {
|
||||||
score += 100 - Math.round(Math.abs(this.density / viewDensity - 1).coerceAtMost(1f))
|
score += 100 - abs(this.density / viewDensity - 1).coerceAtMost(1f).roundToInt()
|
||||||
}
|
}
|
||||||
return score
|
return score
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ fun CardEntity.toParcelable(accountKey: UserKey, accountType: String): Parcelabl
|
||||||
|
|
||||||
fun ParcelableCardEntity.getAsBoolean(key: String, def: Boolean): Boolean {
|
fun ParcelableCardEntity.getAsBoolean(key: String, def: Boolean): Boolean {
|
||||||
val value = getValue(key) ?: return def
|
val value = getValue(key) ?: return def
|
||||||
return value.value.toBoolean()
|
return value.value!!.toBoolean()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ParcelableCardEntity.getAsString(key: String, def: String?): String? {
|
fun ParcelableCardEntity.getAsString(key: String, def: String?): String? {
|
||||||
|
@ -71,9 +71,9 @@ fun ParcelableCardEntity.getAsLong(key: String, def: Long): Long {
|
||||||
|
|
||||||
fun ParcelableCardEntity.getAsDate(key: String, def: Date): Date {
|
fun ParcelableCardEntity.getAsDate(key: String, def: Date): Date {
|
||||||
val value = getValue(key) ?: return def
|
val value = getValue(key) ?: return def
|
||||||
try {
|
return try {
|
||||||
return ParcelableCardEntityUtils.sISOFormat.parse(value.value)
|
ParcelableCardEntityUtils.sISOFormat.parse(value.value)
|
||||||
} catch (e: ParseException) {
|
} catch (e: ParseException) {
|
||||||
return def
|
def
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ fun ParcelableMedia.getBestVideoUrlAndType(supportedTypes: Array<String>): Pair<
|
||||||
val videoInfo = video_info ?: return Pair(mediaUrl, null)
|
val videoInfo = video_info ?: return Pair(mediaUrl, null)
|
||||||
val firstMatch = videoInfo.variants.filter { variant ->
|
val firstMatch = videoInfo.variants.filter { variant ->
|
||||||
supportedTypes.any { it.equals(variant.content_type, ignoreCase = true) }
|
supportedTypes.any { it.equals(variant.content_type, ignoreCase = true) }
|
||||||
}.sortedByDescending(ParcelableMedia.VideoInfo.Variant::bitrate).firstOrNull() ?: return null
|
}.maxBy(ParcelableMedia.VideoInfo.Variant::bitrate) ?: return null
|
||||||
return Pair(firstMatch.url, firstMatch.content_type)
|
return Pair(firstMatch.url, firstMatch.content_type)
|
||||||
}
|
}
|
||||||
ParcelableMedia.Type.CARD_ANIMATED_GIF -> {
|
ParcelableMedia.Type.CARD_ANIMATED_GIF -> {
|
||||||
|
|
|
@ -12,16 +12,16 @@ import org.mariotaku.twidere.util.BitmapFactoryUtils
|
||||||
*/
|
*/
|
||||||
fun ParcelableMediaUpdate.getMimeType(resolver: ContentResolver): String? {
|
fun ParcelableMediaUpdate.getMimeType(resolver: ContentResolver): String? {
|
||||||
val uri = Uri.parse(this.uri)
|
val uri = Uri.parse(this.uri)
|
||||||
return resolver.getType(uri) ?: when (type) {
|
return resolver.getType(uri) ?: return when (type) {
|
||||||
ParcelableMedia.Type.ANIMATED_GIF -> {
|
ParcelableMedia.Type.ANIMATED_GIF -> {
|
||||||
return "image/gif"
|
"image/gif"
|
||||||
}
|
}
|
||||||
ParcelableMedia.Type.IMAGE -> {
|
ParcelableMedia.Type.IMAGE -> {
|
||||||
val o = BitmapFactory.Options()
|
val o = BitmapFactory.Options()
|
||||||
o.inJustDecodeBounds = true
|
o.inJustDecodeBounds = true
|
||||||
BitmapFactoryUtils.decodeUri(resolver, uri, opts = o)
|
BitmapFactoryUtils.decodeUri(resolver, uri, opts = o)
|
||||||
return o.outMimeType
|
o.outMimeType
|
||||||
}
|
}
|
||||||
else -> return null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -53,12 +53,12 @@ val ParcelableMessageConversation.readOnly: Boolean
|
||||||
|
|
||||||
var ParcelableMessageConversation.notificationDisabled: Boolean
|
var ParcelableMessageConversation.notificationDisabled: Boolean
|
||||||
get() {
|
get() {
|
||||||
when (conversation_extras_type) {
|
return when (conversation_extras_type) {
|
||||||
ExtrasType.TWITTER_OFFICIAL -> {
|
ExtrasType.TWITTER_OFFICIAL -> {
|
||||||
return (conversation_extras as? TwitterOfficialConversationExtras)?.notificationsDisabled ?: false
|
(conversation_extras as? TwitterOfficialConversationExtras)?.notificationsDisabled ?: false
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
return (conversation_extras as? DefaultConversationExtras)?.notificationsDisabled ?: false
|
(conversation_extras as? DefaultConversationExtras)?.notificationsDisabled ?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,42 +46,42 @@ internal fun getSummaryText(context: Context, manager: UserColorNameManager, nam
|
||||||
} else {
|
} else {
|
||||||
res.getQuantityString(R.plurals.N_users, users.size, users.size)
|
res.getQuantityString(R.plurals.N_users, users.size, users.size)
|
||||||
}
|
}
|
||||||
if (sender != null) {
|
return if (sender != null) {
|
||||||
return res.getString(R.string.message_format_participants_join_added,
|
res.getString(R.string.message_format_participants_join_added,
|
||||||
manager.getDisplayName(sender, nameFirst), joinName)
|
manager.getDisplayName(sender, nameFirst), joinName)
|
||||||
} else {
|
} else {
|
||||||
return res.getString(R.string.message_format_participants_join, joinName)
|
res.getString(R.string.message_format_participants_join, joinName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MessageType.PARTICIPANTS_LEAVE -> {
|
MessageType.PARTICIPANTS_LEAVE -> {
|
||||||
val users = (extras as UserArrayExtras).users
|
val users = (extras as UserArrayExtras).users
|
||||||
val res = context.resources
|
val res = context.resources
|
||||||
if (users.size == 1) {
|
return if (users.size == 1) {
|
||||||
val displayName = manager.getDisplayName(users[0], nameFirst)
|
val displayName = manager.getDisplayName(users[0], nameFirst)
|
||||||
return res.getString(R.string.message_format_participants_leave, displayName)
|
res.getString(R.string.message_format_participants_leave, displayName)
|
||||||
} else {
|
} else {
|
||||||
val usersName = res.getQuantityString(R.plurals.N_users, users.size, users.size)
|
val usersName = res.getQuantityString(R.plurals.N_users, users.size, users.size)
|
||||||
return res.getString(R.string.message_format_participants_leave, usersName)
|
res.getString(R.string.message_format_participants_leave, usersName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MessageType.CONVERSATION_NAME_UPDATE -> {
|
MessageType.CONVERSATION_NAME_UPDATE -> {
|
||||||
extras as ConversationInfoUpdatedExtras
|
extras as ConversationInfoUpdatedExtras
|
||||||
val res = context.resources
|
val res = context.resources
|
||||||
if (extras.user != null) {
|
return if (extras.user != null) {
|
||||||
return res.getString(R.string.message_format_conversation_name_update_by_user,
|
res.getString(R.string.message_format_conversation_name_update_by_user,
|
||||||
manager.getDisplayName(extras.user, nameFirst), extras.name)
|
manager.getDisplayName(extras.user, nameFirst), extras.name)
|
||||||
} else {
|
} else {
|
||||||
return res.getString(R.string.message_format_conversation_name_update, extras.name)
|
res.getString(R.string.message_format_conversation_name_update, extras.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MessageType.CONVERSATION_AVATAR_UPDATE -> {
|
MessageType.CONVERSATION_AVATAR_UPDATE -> {
|
||||||
extras as ConversationInfoUpdatedExtras
|
extras as ConversationInfoUpdatedExtras
|
||||||
val res = context.resources
|
val res = context.resources
|
||||||
if (extras.user != null) {
|
return if (extras.user != null) {
|
||||||
return res.getString(R.string.message_format_conversation_avatar_update_by_user,
|
res.getString(R.string.message_format_conversation_avatar_update_by_user,
|
||||||
manager.getDisplayName(extras.user, nameFirst))
|
manager.getDisplayName(extras.user, nameFirst))
|
||||||
} else {
|
} else {
|
||||||
return res.getString(R.string.message_format_conversation_avatar_update)
|
res.getString(R.string.message_format_conversation_avatar_update)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,9 +26,9 @@ import org.mariotaku.twidere.model.UserKey
|
||||||
* Created by mariotaku on 2017/4/23.
|
* Created by mariotaku on 2017/4/23.
|
||||||
*/
|
*/
|
||||||
fun ParcelableUserMention.getAcct(accountKey: UserKey): String {
|
fun ParcelableUserMention.getAcct(accountKey: UserKey): String {
|
||||||
if (accountKey.host == key.host) {
|
return if (accountKey.host == key.host) {
|
||||||
return screen_name
|
screen_name
|
||||||
} else {
|
} else {
|
||||||
return "$screen_name@${key.host}"
|
"$screen_name@${key.host}"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -220,7 +220,11 @@ fun Status.applyTo(accountKey: UserKey, accountType: String, profileImageSize: S
|
||||||
|
|
||||||
fun Status.formattedTextWithIndices(): StatusTextWithIndices {
|
fun Status.formattedTextWithIndices(): StatusTextWithIndices {
|
||||||
val source = CodePointArray(this.fullText ?: this.text!!)
|
val source = CodePointArray(this.fullText ?: this.text!!)
|
||||||
val builder = HtmlBuilder(source, false, true, false)
|
val builder = HtmlBuilder(source,
|
||||||
|
throwExceptions = false,
|
||||||
|
sourceIsEscaped = true,
|
||||||
|
shouldReEscape = false
|
||||||
|
)
|
||||||
builder.addEntities(this)
|
builder.addEntities(this)
|
||||||
val textWithIndices = StatusTextWithIndices()
|
val textWithIndices = StatusTextWithIndices()
|
||||||
val (text, spans) = builder.buildWithIndices()
|
val (text, spans) = builder.buildWithIndices()
|
||||||
|
|
|
@ -29,15 +29,19 @@ fun Attachment.toParcelable(externalUrl: String?) : ParcelableMedia? {
|
||||||
val mimeType = mimetype ?: return null
|
val mimeType = mimetype ?: return null
|
||||||
val result = ParcelableMedia()
|
val result = ParcelableMedia()
|
||||||
|
|
||||||
if (mimeType.startsWith("image/")) {
|
when {
|
||||||
|
mimeType.startsWith("image/") -> {
|
||||||
result.type = ParcelableMedia.Type.IMAGE
|
result.type = ParcelableMedia.Type.IMAGE
|
||||||
} else if (mimeType.startsWith("video/")) {
|
}
|
||||||
|
mimeType.startsWith("video/") -> {
|
||||||
result.type = ParcelableMedia.Type.VIDEO
|
result.type = ParcelableMedia.Type.VIDEO
|
||||||
} else {
|
}
|
||||||
|
else -> {
|
||||||
// https://github.com/TwidereProject/Twidere-Android/issues/729
|
// https://github.com/TwidereProject/Twidere-Android/issues/729
|
||||||
// Skip unsupported attachment
|
// Skip unsupported attachment
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
}
|
||||||
result.width = width
|
result.width = width
|
||||||
result.height = height
|
result.height = height
|
||||||
result.url = externalUrl ?: url
|
result.url = externalUrl ?: url
|
||||||
|
|
|
@ -33,9 +33,9 @@ fun Extractor.extractMentionsAndNonMentionStartIndex(text: String, mentions: Arr
|
||||||
if (entity.start != nextExpectedPos) break
|
if (entity.start != nextExpectedPos) break
|
||||||
// Break at first mention not found in `inReplyTo.mentions`
|
// Break at first mention not found in `inReplyTo.mentions`
|
||||||
if (mentions?.none { entity.value.equals(it.screen_name, ignoreCase = true) } == true) break
|
if (mentions?.none { entity.value.equals(it.screen_name, ignoreCase = true) } == true) break
|
||||||
nextExpectedPos = (entity.end..text.indices.endInclusive).firstOrNull {
|
nextExpectedPos = (entity.end..text.indices.last).firstOrNull {
|
||||||
!text[it].isWhitespace()
|
!text[it].isWhitespace()
|
||||||
} ?: text.indices.endInclusive + 1
|
} ?: text.indices.last + 1
|
||||||
}
|
}
|
||||||
return MentionsAndNonMentionStartIndex(entities, nextExpectedPos)
|
return MentionsAndNonMentionStartIndex(entities, nextExpectedPos)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ package org.mariotaku.twidere.extension.view
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.recyclerview.widget.recyclerView
|
import androidx.recyclerview.widget.recyclerView
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
fun RecyclerView.LayoutManager.calculateSpaceItemHeight(child: View, spaceViewType: Int, typeStart: Int): Int {
|
fun RecyclerView.LayoutManager.calculateSpaceItemHeight(child: View, spaceViewType: Int, typeStart: Int): Int {
|
||||||
val recyclerView = recyclerView ?: return 0
|
val recyclerView = recyclerView ?: return 0
|
||||||
|
@ -39,7 +40,7 @@ fun RecyclerView.LayoutManager.calculateSpaceItemHeight(child: View, spaceViewTy
|
||||||
if (heightBeforeSpace != 0) {
|
if (heightBeforeSpace != 0) {
|
||||||
val spaceHeight = recyclerView.measuredHeight - recyclerView.paddingTop -
|
val spaceHeight = recyclerView.measuredHeight - recyclerView.paddingTop -
|
||||||
recyclerView.paddingBottom - heightBeforeSpace
|
recyclerView.paddingBottom - heightBeforeSpace
|
||||||
return Math.max(0, spaceHeight)
|
return max(0, spaceHeight)
|
||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
|
@ -48,16 +48,21 @@ class APIEditorDialogFragment : BaseDialogFragment() {
|
||||||
val targetFragment = this.targetFragment
|
val targetFragment = this.targetFragment
|
||||||
val parentFragment = this.parentFragment
|
val parentFragment = this.parentFragment
|
||||||
val host = this.host
|
val host = this.host
|
||||||
if (targetFragment is APIEditorCallback) {
|
when {
|
||||||
|
targetFragment is APIEditorCallback -> {
|
||||||
targetFragment.onSaveAPIConfig(applyCustomAPIConfig())
|
targetFragment.onSaveAPIConfig(applyCustomAPIConfig())
|
||||||
} else if (parentFragment is APIEditorCallback) {
|
}
|
||||||
|
parentFragment is APIEditorCallback -> {
|
||||||
parentFragment.onSaveAPIConfig(applyCustomAPIConfig())
|
parentFragment.onSaveAPIConfig(applyCustomAPIConfig())
|
||||||
} else if (host is APIEditorCallback) {
|
}
|
||||||
|
host is APIEditorCallback -> {
|
||||||
host.onSaveAPIConfig(applyCustomAPIConfig())
|
host.onSaveAPIConfig(applyCustomAPIConfig())
|
||||||
} else {
|
}
|
||||||
|
else -> {
|
||||||
kPreferences[defaultAPIConfigKey] = applyCustomAPIConfig()
|
kPreferences[defaultAPIConfigKey] = applyCustomAPIConfig()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
builder.setNegativeButton(android.R.string.cancel, null)
|
builder.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
|
||||||
val dialog = builder.create()
|
val dialog = builder.create()
|
||||||
|
@ -94,10 +99,10 @@ class APIEditorDialogFragment : BaseDialogFragment() {
|
||||||
tag = "api_url_format_help")
|
tag = "api_url_format_help")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
apiConfig = if (savedInstanceState != null) {
|
||||||
apiConfig = savedInstanceState.getParcelable(EXTRA_API_CONFIG)!!
|
savedInstanceState.getParcelable(EXTRA_API_CONFIG)!!
|
||||||
} else {
|
} else {
|
||||||
apiConfig = arguments?.getParcelable(EXTRA_API_CONFIG) ?: kPreferences[defaultAPIConfigKey]
|
arguments?.getParcelable(EXTRA_API_CONFIG) ?: kPreferences[defaultAPIConfigKey]
|
||||||
}
|
}
|
||||||
displayCustomApiConfig()
|
displayCustomApiConfig()
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,8 +103,10 @@ abstract class AbsActivitiesFragment protected constructor() :
|
||||||
registerForContextMenu(recyclerView)
|
registerForContextMenu(recyclerView)
|
||||||
navigationHelper = RecyclerViewNavigationHelper(recyclerView, layoutManager, adapter,
|
navigationHelper = RecyclerViewNavigationHelper(recyclerView, layoutManager, adapter,
|
||||||
this)
|
this)
|
||||||
pauseOnScrollListener = PauseRecyclerViewOnScrollListener(false, false,
|
pauseOnScrollListener = PauseRecyclerViewOnScrollListener(
|
||||||
requestManager)
|
pauseOnScroll = false, pauseOnFling = false,
|
||||||
|
requestManager = requestManager
|
||||||
|
)
|
||||||
|
|
||||||
val loaderArgs = Bundle(arguments)
|
val loaderArgs = Bundle(arguments)
|
||||||
loaderArgs.putBoolean(EXTRA_FROM_USER, true)
|
loaderArgs.putBoolean(EXTRA_FROM_USER, true)
|
||||||
|
@ -237,7 +239,7 @@ abstract class AbsActivitiesFragment protected constructor() :
|
||||||
adapter.getTimestamp(lastReadPosition)
|
adapter.getTimestamp(lastReadPosition)
|
||||||
}
|
}
|
||||||
lastReadViewTop = layoutManager.findViewByPosition(lastReadPosition)?.top ?: 0
|
lastReadViewTop = layoutManager.findViewByPosition(lastReadPosition)?.top ?: 0
|
||||||
loadMore = activityRange.endInclusive in 0..lastVisibleItemPosition
|
loadMore = activityRange.last in 0..lastVisibleItemPosition
|
||||||
} else if (rememberPosition && readPositionTag != null) {
|
} else if (rememberPosition && readPositionTag != null) {
|
||||||
val syncManager = timelineSyncManager
|
val syncManager = timelineSyncManager
|
||||||
val positionTag = this.readPositionTag
|
val positionTag = this.readPositionTag
|
||||||
|
@ -547,13 +549,13 @@ abstract class AbsActivitiesFragment protected constructor() :
|
||||||
(recyclerView.layoutManager as LinearLayoutManager).orientation) {
|
(recyclerView.layoutManager as LinearLayoutManager).orientation) {
|
||||||
override fun isDividerEnabled(childPos: Int): Boolean {
|
override fun isDividerEnabled(childPos: Int): Boolean {
|
||||||
if (childPos >= layoutManager.itemCount || childPos < 0) return false
|
if (childPos >= layoutManager.itemCount || childPos < 0) return false
|
||||||
when (adapter.getItemViewType(childPos)) {
|
return when (adapter.getItemViewType(childPos)) {
|
||||||
ITEM_VIEW_TYPE_STATUS, ITEM_VIEW_TYPE_TITLE_SUMMARY, ITEM_VIEW_TYPE_GAP,
|
ITEM_VIEW_TYPE_STATUS, ITEM_VIEW_TYPE_TITLE_SUMMARY, ITEM_VIEW_TYPE_GAP,
|
||||||
ITEM_VIEW_TYPE_STUB -> {
|
ITEM_VIEW_TYPE_STUB -> {
|
||||||
return true
|
true
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
return false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ import org.mariotaku.twidere.util.ContentScrollHandler.ContentListSupport
|
||||||
import org.mariotaku.twidere.util.ListViewScrollHandler
|
import org.mariotaku.twidere.util.ListViewScrollHandler
|
||||||
import org.mariotaku.twidere.util.ThemeUtils
|
import org.mariotaku.twidere.util.ThemeUtils
|
||||||
import org.mariotaku.twidere.util.TwidereColorUtils
|
import org.mariotaku.twidere.util.TwidereColorUtils
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by mariotaku on 15/4/16.
|
* Created by mariotaku on 15/4/16.
|
||||||
|
@ -211,10 +212,11 @@ abstract class AbsContentListViewFragment<A : ListAdapter> : BaseFragment(),
|
||||||
}
|
}
|
||||||
val density = resources.displayMetrics.density
|
val density = resources.displayMetrics.density
|
||||||
val progressCircleDiameter = swipeLayout.progressCircleDiameter
|
val progressCircleDiameter = swipeLayout.progressCircleDiameter
|
||||||
val controlBarOffsetPixels = Math.round(activity.controlBarHeight * (1 - activity.controlBarOffset))
|
val controlBarOffsetPixels =
|
||||||
|
(activity.controlBarHeight * (1 - activity.controlBarOffset)).roundToInt()
|
||||||
val swipeStart = systemWindowsInsets.top - controlBarOffsetPixels - progressCircleDiameter
|
val swipeStart = systemWindowsInsets.top - controlBarOffsetPixels - progressCircleDiameter
|
||||||
// 64: SwipeRefreshLayout.DEFAULT_CIRCLE_TARGET
|
// 64: SwipeRefreshLayout.DEFAULT_CIRCLE_TARGET
|
||||||
val swipeDistance = Math.round(64 * density)
|
val swipeDistance = (64 * density).roundToInt()
|
||||||
swipeLayout.setProgressViewOffset(false, swipeStart, swipeStart + swipeDistance)
|
swipeLayout.setProgressViewOffset(false, swipeStart, swipeStart + swipeDistance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,7 @@ abstract class AbsMediaStatusesFragment : AbsContentRecyclerViewFragment<Stagger
|
||||||
val maxId = pagination?.maxId?.takeIf(String::isNotEmpty)
|
val maxId = pagination?.maxId?.takeIf(String::isNotEmpty)
|
||||||
val sinceId = pagination?.sinceId?.takeIf(String::isNotEmpty)
|
val sinceId = pagination?.sinceId?.takeIf(String::isNotEmpty)
|
||||||
if (sinceId == null && maxId != null) {
|
if (sinceId == null && maxId != null) {
|
||||||
if (data != null && !data.isEmpty()) {
|
if (data != null && data.isNotEmpty()) {
|
||||||
return changed
|
return changed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,8 +147,10 @@ abstract class AbsStatusesFragment : AbsContentListRecyclerViewFragment<Parcelab
|
||||||
adapter.statusClickListener = this
|
adapter.statusClickListener = this
|
||||||
registerForContextMenu(recyclerView)
|
registerForContextMenu(recyclerView)
|
||||||
navigationHelper = RecyclerViewNavigationHelper(recyclerView, layoutManager, adapter, this)
|
navigationHelper = RecyclerViewNavigationHelper(recyclerView, layoutManager, adapter, this)
|
||||||
pauseOnScrollListener = PauseRecyclerViewOnScrollListener(false, false,
|
pauseOnScrollListener = PauseRecyclerViewOnScrollListener(
|
||||||
requestManager)
|
pauseOnScroll = false, pauseOnFling = false,
|
||||||
|
requestManager = requestManager
|
||||||
|
)
|
||||||
|
|
||||||
if (shouldInitLoader) {
|
if (shouldInitLoader) {
|
||||||
initLoaderIfNeeded()
|
initLoaderIfNeeded()
|
||||||
|
@ -288,15 +290,19 @@ abstract class AbsStatusesFragment : AbsContentListRecyclerViewFragment<Parcelab
|
||||||
} else {
|
} else {
|
||||||
firstVisibleItemPosition
|
firstVisibleItemPosition
|
||||||
}.coerceInOr(statusRange, -1)
|
}.coerceInOr(statusRange, -1)
|
||||||
lastReadId = if (lastReadPosition < 0) {
|
lastReadId = when {
|
||||||
|
lastReadPosition < 0 -> {
|
||||||
-1
|
-1
|
||||||
} else if (useSortIdAsReadPosition) {
|
}
|
||||||
|
useSortIdAsReadPosition -> {
|
||||||
adapter.getStatusSortId(lastReadPosition, false)
|
adapter.getStatusSortId(lastReadPosition, false)
|
||||||
} else {
|
}
|
||||||
|
else -> {
|
||||||
adapter.getStatusPositionKey(lastReadPosition)
|
adapter.getStatusPositionKey(lastReadPosition)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
lastReadViewTop = layoutManager.findViewByPosition(lastReadPosition)?.top ?: 0
|
lastReadViewTop = layoutManager.findViewByPosition(lastReadPosition)?.top ?: 0
|
||||||
loadMore = statusRange.endInclusive in 0..lastVisibleItemPosition
|
loadMore = statusRange.last in 0..lastVisibleItemPosition
|
||||||
} else if (rememberPosition) {
|
} else if (rememberPosition) {
|
||||||
val syncManager = timelineSyncManager
|
val syncManager = timelineSyncManager
|
||||||
val positionTag = this.readPositionTag
|
val positionTag = this.readPositionTag
|
||||||
|
@ -621,19 +627,23 @@ abstract class AbsStatusesFragment : AbsContentListRecyclerViewFragment<Parcelab
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
R.id.favorite -> {
|
R.id.favorite -> {
|
||||||
if (fragment.preferences[favoriteConfirmationKey]) {
|
when {
|
||||||
|
fragment.preferences[favoriteConfirmationKey] -> {
|
||||||
fragment.executeAfterFragmentResumed {
|
fragment.executeAfterFragmentResumed {
|
||||||
FavoriteConfirmDialogFragment.show(it.childFragmentManager,
|
FavoriteConfirmDialogFragment.show(it.childFragmentManager,
|
||||||
status.account_key, status.id, status)
|
status.account_key, status.id, status)
|
||||||
}
|
}
|
||||||
} else if (status.is_favorite) {
|
}
|
||||||
|
status.is_favorite -> {
|
||||||
fragment.twitterWrapper.destroyFavoriteAsync(status.account_key, status.id)
|
fragment.twitterWrapper.destroyFavoriteAsync(status.account_key, status.id)
|
||||||
} else {
|
}
|
||||||
|
else -> {
|
||||||
holder.playLikeAnimation(DefaultOnLikedListener(fragment.twitterWrapper, status))
|
holder.playLikeAnimation(DefaultOnLikedListener(fragment.twitterWrapper, status))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun handleActionLongClick(fragment: Fragment, status: ParcelableStatus, itemId: Long, id: Int): Boolean {
|
fun handleActionLongClick(fragment: Fragment, status: ParcelableStatus, itemId: Long, id: Int): Boolean {
|
||||||
when (id) {
|
when (id) {
|
||||||
|
@ -653,7 +663,7 @@ abstract class AbsStatusesFragment : AbsContentListRecyclerViewFragment<Parcelab
|
||||||
|
|
||||||
fun handleActionActivityResult(fragment: BaseFragment, requestCode: Int, resultCode: Int, data: Intent?) {
|
fun handleActionActivityResult(fragment: BaseFragment, requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
when (requestCode) {
|
when (requestCode) {
|
||||||
AbsStatusesFragment.REQUEST_FAVORITE_SELECT_ACCOUNT -> {
|
REQUEST_FAVORITE_SELECT_ACCOUNT -> {
|
||||||
if (resultCode != Activity.RESULT_OK || data == null) return
|
if (resultCode != Activity.RESULT_OK || data == null) return
|
||||||
val accountKey = data.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY)!!
|
val accountKey = data.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY)!!
|
||||||
val extras = data.getBundleExtra(EXTRA_EXTRAS)!!
|
val extras = data.getBundleExtra(EXTRA_EXTRAS)!!
|
||||||
|
@ -667,7 +677,7 @@ abstract class AbsStatusesFragment : AbsContentListRecyclerViewFragment<Parcelab
|
||||||
fragment.twitterWrapper.createFavoriteAsync(accountKey, status)
|
fragment.twitterWrapper.createFavoriteAsync(accountKey, status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AbsStatusesFragment.REQUEST_RETWEET_SELECT_ACCOUNT -> {
|
REQUEST_RETWEET_SELECT_ACCOUNT -> {
|
||||||
if (resultCode != Activity.RESULT_OK || data == null) return
|
if (resultCode != Activity.RESULT_OK || data == null) return
|
||||||
val accountKey = data.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY)!!
|
val accountKey = data.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY)!!
|
||||||
val extras = data.getBundleExtra(EXTRA_EXTRAS)!!
|
val extras = data.getBundleExtra(EXTRA_EXTRAS)!!
|
||||||
|
@ -719,17 +729,21 @@ abstract class AbsStatusesFragment : AbsContentListRecyclerViewFragment<Parcelab
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
ACTION_STATUS_FAVORITE -> {
|
ACTION_STATUS_FAVORITE -> {
|
||||||
if (fragment.preferences[favoriteConfirmationKey]) {
|
when {
|
||||||
|
fragment.preferences[favoriteConfirmationKey] -> {
|
||||||
fragment.executeAfterFragmentResumed {
|
fragment.executeAfterFragmentResumed {
|
||||||
FavoriteConfirmDialogFragment.show(it.childFragmentManager,
|
FavoriteConfirmDialogFragment.show(it.childFragmentManager,
|
||||||
status.account_key, status.id, status)
|
status.account_key, status.id, status)
|
||||||
}
|
}
|
||||||
} else if (status.is_favorite) {
|
}
|
||||||
|
status.is_favorite -> {
|
||||||
fragment.twitterWrapper.destroyFavoriteAsync(status.account_key, status.id)
|
fragment.twitterWrapper.destroyFavoriteAsync(status.account_key, status.id)
|
||||||
} else {
|
}
|
||||||
|
else -> {
|
||||||
val holder = fragment.recyclerView.findViewHolderForLayoutPosition(position) as StatusViewHolder
|
val holder = fragment.recyclerView.findViewHolderForLayoutPosition(position) as StatusViewHolder
|
||||||
holder.playLikeAnimation(DefaultOnLikedListener(fragment.twitterWrapper, status))
|
holder.playLikeAnimation(DefaultOnLikedListener(fragment.twitterWrapper, status))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -532,13 +532,17 @@ class AccountsDashboardFragment : BaseFragment(), LoaderCallbacks<AccountsInfo>,
|
||||||
val width = if (bannerWidth > 0) bannerWidth else defWidth
|
val width = if (bannerWidth > 0) bannerWidth else defWidth
|
||||||
val bannerView = accountProfileBanner.nextView as ImageView
|
val bannerView = accountProfileBanner.nextView as ImageView
|
||||||
val user = account.user
|
val user = account.user
|
||||||
val fallbackBanner = if (user.link_color != 0) {
|
val fallbackBanner = when {
|
||||||
|
user.link_color != 0 -> {
|
||||||
ColorDrawable(user.link_color)
|
ColorDrawable(user.link_color)
|
||||||
} else if (user.account_color != 0) {
|
}
|
||||||
|
user.account_color != 0 -> {
|
||||||
ColorDrawable(user.account_color)
|
ColorDrawable(user.account_color)
|
||||||
} else {
|
}
|
||||||
|
else -> {
|
||||||
ColorDrawable(Chameleon.getOverrideTheme(requireActivity(), activity).colorPrimary)
|
ColorDrawable(Chameleon.getOverrideTheme(requireActivity(), activity).colorPrimary)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
requestManager.loadProfileBanner(requireContext(), account.user, width).fallback(fallbackBanner)
|
requestManager.loadProfileBanner(requireContext(), account.user, width).fallback(fallbackBanner)
|
||||||
.into(bannerView)
|
.into(bannerView)
|
||||||
|
|
|
@ -241,6 +241,6 @@ class AccountsManagerFragment : BaseFragment(), LoaderManager.LoaderCallbacks<Li
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private val FRAGMENT_TAG_ACCOUNT_DELETION = "account_deletion"
|
private const val FRAGMENT_TAG_ACCOUNT_DELETION = "account_deletion"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ class AddStatusFilterDialogFragment : BaseDialogFragment() {
|
||||||
filterItems = filterItemsInfo
|
filterItems = filterItemsInfo
|
||||||
val entries = arrayOfNulls<String>(filterItems!!.size)
|
val entries = arrayOfNulls<String>(filterItems!!.size)
|
||||||
val nameFirst = preferences[nameFirstKey]
|
val nameFirst = preferences[nameFirstKey]
|
||||||
for (i in 0 until entries.size) {
|
for (i in entries.indices) {
|
||||||
val info = filterItems!![i]
|
val info = filterItems!![i]
|
||||||
when (info.type) {
|
when (info.type) {
|
||||||
FilterItemInfo.FILTER_TYPE_USER -> {
|
FilterItemInfo.FILTER_TYPE_USER -> {
|
||||||
|
@ -87,19 +87,23 @@ class AddStatusFilterDialogFragment : BaseDialogFragment() {
|
||||||
}
|
}
|
||||||
val info = filterItems!![checkPositions.keyAt(i)]
|
val info = filterItems!![checkPositions.keyAt(i)]
|
||||||
val value = info.value
|
val value = info.value
|
||||||
if (value is ParcelableUserMention) {
|
when {
|
||||||
|
value is ParcelableUserMention -> {
|
||||||
userKeys.add(value.key)
|
userKeys.add(value.key)
|
||||||
userValues.add(ContentValuesCreator.createFilteredUser(value))
|
userValues.add(ContentValuesCreator.createFilteredUser(value))
|
||||||
} else if (value is UserItem) {
|
}
|
||||||
|
value is UserItem -> {
|
||||||
userKeys.add(value.key)
|
userKeys.add(value.key)
|
||||||
userValues.add(createFilteredUser(value))
|
userValues.add(createFilteredUser(value))
|
||||||
} else if (info.type == FilterItemInfo.FILTER_TYPE_KEYWORD) {
|
}
|
||||||
|
info.type == FilterItemInfo.FILTER_TYPE_KEYWORD -> {
|
||||||
val keyword = ParseUtils.parseString(value)
|
val keyword = ParseUtils.parseString(value)
|
||||||
keywords.add(keyword)
|
keywords.add(keyword)
|
||||||
val values = ContentValues()
|
val values = ContentValues()
|
||||||
values.put(Filters.Keywords.VALUE, "#$keyword")
|
values.put(Filters.Keywords.VALUE, "#$keyword")
|
||||||
keywordValues.add(values)
|
keywordValues.add(values)
|
||||||
} else if (info.type == FilterItemInfo.FILTER_TYPE_SOURCE) {
|
}
|
||||||
|
info.type == FilterItemInfo.FILTER_TYPE_SOURCE -> {
|
||||||
val source = ParseUtils.parseString(value)
|
val source = ParseUtils.parseString(value)
|
||||||
sources.add(source)
|
sources.add(source)
|
||||||
val values = ContentValues()
|
val values = ContentValues()
|
||||||
|
@ -107,6 +111,7 @@ class AddStatusFilterDialogFragment : BaseDialogFragment() {
|
||||||
sourceValues.add(values)
|
sourceValues.add(values)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
context?.contentResolver?.let { resolver ->
|
context?.contentResolver?.let { resolver ->
|
||||||
ContentResolverUtils.bulkDelete(resolver, Filters.Users.CONTENT_URI,
|
ContentResolverUtils.bulkDelete(resolver, Filters.Users.CONTENT_URI,
|
||||||
Filters.Users.USER_KEY, false, userKeys, null, null)
|
Filters.Users.USER_KEY, false, userKeys, null, null)
|
||||||
|
@ -164,12 +169,15 @@ class AddStatusFilterDialogFragment : BaseDialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getName(manager: UserColorNameManager, value: Any, nameFirst: Boolean): String {
|
private fun getName(manager: UserColorNameManager, value: Any, nameFirst: Boolean): String {
|
||||||
if (value is ParcelableUserMention) {
|
return when (value) {
|
||||||
return manager.getDisplayName(value.key, value.name, value.screen_name, nameFirst)
|
is ParcelableUserMention -> {
|
||||||
} else if (value is UserItem) {
|
manager.getDisplayName(value.key, value.name, value.screen_name, nameFirst)
|
||||||
return manager.getDisplayName(value.key, value.name, value.screen_name, nameFirst)
|
}
|
||||||
} else
|
is UserItem -> {
|
||||||
return ParseUtils.parseString(value)
|
manager.getDisplayName(value.key, value.name, value.screen_name, nameFirst)
|
||||||
|
}
|
||||||
|
else -> ParseUtils.parseString(value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal data class FilterItemInfo(
|
internal data class FilterItemInfo(
|
||||||
|
@ -194,7 +202,7 @@ class AddStatusFilterDialogFragment : BaseDialogFragment() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val FRAGMENT_TAG = "add_status_filter"
|
const val FRAGMENT_TAG = "add_status_filter"
|
||||||
|
|
||||||
private fun createFilteredUser(item: UserItem): ContentValues {
|
private fun createFilteredUser(item: UserItem): ContentValues {
|
||||||
val values = ContentValues()
|
val values = ContentValues()
|
||||||
|
|
|
@ -140,8 +140,8 @@ abstract class BasePreferenceFragment : PreferenceFragmentCompat(), IBaseFragmen
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private val REQUEST_PICK_RINGTONE = 301
|
private const val REQUEST_PICK_RINGTONE = 301
|
||||||
private val EXTRA_RINGTONE_PREFERENCE_KEY = "internal:ringtone_preference_key"
|
private const val EXTRA_RINGTONE_PREFERENCE_KEY = "internal:ringtone_preference_key"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,11 +61,8 @@ class ColorPickerDialogFragment : BaseDialogFragment(), DialogInterface.OnClickL
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
val color: Int
|
val color: Int
|
||||||
val args = arguments
|
val args = arguments
|
||||||
if (savedInstanceState != null) {
|
color =
|
||||||
color = savedInstanceState.getInt(EXTRA_COLOR, Color.WHITE)
|
savedInstanceState?.getInt(EXTRA_COLOR, Color.WHITE) ?: args!!.getInt(EXTRA_COLOR, Color.WHITE)
|
||||||
} else {
|
|
||||||
color = args!!.getInt(EXTRA_COLOR, Color.WHITE)
|
|
||||||
}
|
|
||||||
|
|
||||||
val activity = activity
|
val activity = activity
|
||||||
val builder = AlertDialog.Builder(requireActivity())
|
val builder = AlertDialog.Builder(requireActivity())
|
||||||
|
|
|
@ -48,7 +48,7 @@ class CreateUserBlockDialogFragment : AbsUserMuteBlockDialogFragment() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val FRAGMENT_TAG = "create_user_block"
|
const val FRAGMENT_TAG = "create_user_block"
|
||||||
|
|
||||||
fun show(fm: FragmentManager, user: ParcelableUser): CreateUserBlockDialogFragment {
|
fun show(fm: FragmentManager, user: ParcelableUser): CreateUserBlockDialogFragment {
|
||||||
val args = Bundle()
|
val args = Bundle()
|
||||||
|
|
|
@ -49,7 +49,7 @@ class CreateUserMuteDialogFragment : AbsUserMuteBlockDialogFragment() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val FRAGMENT_TAG = "create_user_mute"
|
const val FRAGMENT_TAG = "create_user_mute"
|
||||||
|
|
||||||
fun show(fm: FragmentManager, user: ParcelableUser): CreateUserMuteDialogFragment {
|
fun show(fm: FragmentManager, user: ParcelableUser): CreateUserMuteDialogFragment {
|
||||||
val args = Bundle()
|
val args = Bundle()
|
||||||
|
|
|
@ -51,6 +51,8 @@ import org.mariotaku.twidere.util.DataStoreUtils
|
||||||
import org.mariotaku.twidere.util.DataStoreUtils.getTableNameByUri
|
import org.mariotaku.twidere.util.DataStoreUtils.getTableNameByUri
|
||||||
import org.mariotaku.twidere.util.ErrorInfoStore
|
import org.mariotaku.twidere.util.ErrorInfoStore
|
||||||
import org.mariotaku.twidere.util.Utils
|
import org.mariotaku.twidere.util.Utils
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays statuses from database
|
* Displays statuses from database
|
||||||
|
@ -241,8 +243,8 @@ abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
|
||||||
fun replaceStatusStates(result: ParcelableStatus?) {
|
fun replaceStatusStates(result: ParcelableStatus?) {
|
||||||
if (result == null) return
|
if (result == null) return
|
||||||
val lm = layoutManager
|
val lm = layoutManager
|
||||||
val rangeStart = Math.max(adapter.activityStartIndex, lm.findFirstVisibleItemPosition())
|
val rangeStart = max(adapter.activityStartIndex, lm.findFirstVisibleItemPosition())
|
||||||
val rangeEnd = Math.min(lm.findLastVisibleItemPosition(), adapter.activityStartIndex + adapter.getActivityCount(false) - 1)
|
val rangeEnd = min(lm.findLastVisibleItemPosition(), adapter.activityStartIndex + adapter.getActivityCount(false) - 1)
|
||||||
loop@ for (i in rangeStart..rangeEnd) {
|
loop@ for (i in rangeStart..rangeEnd) {
|
||||||
val activity = adapter.getActivity(i, false)
|
val activity = adapter.getActivity(i, false)
|
||||||
if (result.account_key == activity.account_key && result.id == activity.id) {
|
if (result.account_key == activity.account_key && result.id == activity.id) {
|
||||||
|
@ -353,7 +355,7 @@ abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
|
||||||
|
|
||||||
class ActivityCursor(
|
class ActivityCursor(
|
||||||
cursor: Cursor,
|
cursor: Cursor,
|
||||||
indies: ObjectCursor.CursorIndices<ParcelableActivity>,
|
indies: CursorIndices<ParcelableActivity>,
|
||||||
val filteredUserIds: Array<UserKey>,
|
val filteredUserIds: Array<UserKey>,
|
||||||
val filteredUserNames: Array<String>,
|
val filteredUserNames: Array<String>,
|
||||||
val filteredUserDescriptions: Array<String>
|
val filteredUserDescriptions: Array<String>
|
||||||
|
|
|
@ -90,7 +90,7 @@ class DeleteUserListMembersDialogFragment : BaseDialogFragment(), DialogInterfac
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val FRAGMENT_TAG = "destroy_user_list_member"
|
const val FRAGMENT_TAG = "destroy_user_list_member"
|
||||||
|
|
||||||
fun show(fm: FragmentManager, userList: ParcelableUserList,
|
fun show(fm: FragmentManager, userList: ParcelableUserList,
|
||||||
vararg users: ParcelableUser): DeleteUserListMembersDialogFragment {
|
vararg users: ParcelableUser): DeleteUserListMembersDialogFragment {
|
||||||
|
|
|
@ -65,7 +65,7 @@ class DestroyFriendshipDialogFragment : BaseDialogFragment(), DialogInterface.On
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val FRAGMENT_TAG = "destroy_friendship"
|
const val FRAGMENT_TAG = "destroy_friendship"
|
||||||
|
|
||||||
fun show(fm: FragmentManager, user: ParcelableUser): DestroyFriendshipDialogFragment {
|
fun show(fm: FragmentManager, user: ParcelableUser): DestroyFriendshipDialogFragment {
|
||||||
val f = DestroyFriendshipDialogFragment()
|
val f = DestroyFriendshipDialogFragment()
|
||||||
|
|
|
@ -69,7 +69,7 @@ class DestroyUserListSubscriptionDialogFragment : BaseDialogFragment(), DialogIn
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val FRAGMENT_TAG = "destroy_user_list"
|
const val FRAGMENT_TAG = "destroy_user_list"
|
||||||
|
|
||||||
fun show(fm: FragmentManager,
|
fun show(fm: FragmentManager,
|
||||||
userList: ParcelableUserList): DestroyUserListSubscriptionDialogFragment {
|
userList: ParcelableUserList): DestroyUserListSubscriptionDialogFragment {
|
||||||
|
|
|
@ -89,16 +89,21 @@ class ExtraFeaturesIntroductionDialogFragment : BaseDialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startActivityForResultOnTarget(intent: Intent) {
|
private fun startActivityForResultOnTarget(intent: Intent) {
|
||||||
if (targetFragment != null) {
|
when {
|
||||||
|
targetFragment != null -> {
|
||||||
targetFragment?.startActivityForResult(intent, targetRequestCode)
|
targetFragment?.startActivityForResult(intent, targetRequestCode)
|
||||||
} else if (requestCode == 0) {
|
}
|
||||||
|
requestCode == 0 -> {
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
} else if (parentFragment != null) {
|
}
|
||||||
|
parentFragment != null -> {
|
||||||
parentFragment?.startActivityForResult(intent, requestCode)
|
parentFragment?.startActivityForResult(intent, requestCode)
|
||||||
} else {
|
}
|
||||||
|
else -> {
|
||||||
activity?.startActivityForResult(intent, requestCode)
|
activity?.startActivityForResult(intent, requestCode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val EXTRA_FEATURE = "feature"
|
const val EXTRA_FEATURE = "feature"
|
||||||
|
|
|
@ -113,13 +113,17 @@ class GroupFragment : AbsToolbarTabPagesFragment(), LoaderCallbacks<SingleRespon
|
||||||
val twitter = MicroBlogAPIFactory.getInstance(context, accountKey) ?:
|
val twitter = MicroBlogAPIFactory.getInstance(context, accountKey) ?:
|
||||||
throw MicroBlogException("No account")
|
throw MicroBlogException("No account")
|
||||||
val group: Group
|
val group: Group
|
||||||
if (groupId != null) {
|
group = when {
|
||||||
group = twitter.showGroup(groupId)
|
groupId != null -> {
|
||||||
} else if (groupName != null) {
|
twitter.showGroup(groupId)
|
||||||
group = twitter.showGroupByName(groupName)
|
}
|
||||||
} else {
|
groupName != null -> {
|
||||||
|
twitter.showGroupByName(groupName)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
return SingleResponse()
|
return SingleResponse()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return SingleResponse.getInstance(ParcelableGroupUtils.from(group, accountKey, 0,
|
return SingleResponse.getInstance(ParcelableGroupUtils.from(group, accountKey, 0,
|
||||||
group.isMember))
|
group.isMember))
|
||||||
} catch (e: MicroBlogException) {
|
} catch (e: MicroBlogException) {
|
||||||
|
|
|
@ -257,10 +257,10 @@ class HostMappingsListFragment : AbsContentListViewFragment<HostMappingsListFrag
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private val EXTRA_EDIT_MODE = "edit_mode"
|
private const val EXTRA_EDIT_MODE = "edit_mode"
|
||||||
private val EXTRA_HOST = "host"
|
private const val EXTRA_HOST = "host"
|
||||||
private val EXTRA_ADDRESS = "address"
|
private const val EXTRA_ADDRESS = "address"
|
||||||
private val EXTRA_EXCLUDED = "excluded"
|
private const val EXTRA_EXCLUDED = "excluded"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,10 +153,10 @@ class NetworkDiagnosticsFragment : BaseFragment() {
|
||||||
logPrintln()
|
logPrintln()
|
||||||
|
|
||||||
val baseUrl: String
|
val baseUrl: String
|
||||||
if (details.credentials.api_url_format != null) {
|
baseUrl = if (details.credentials.api_url_format != null) {
|
||||||
baseUrl = MicroBlogAPIFactory.getApiBaseUrl(details.credentials.api_url_format, "api")
|
MicroBlogAPIFactory.getApiBaseUrl(details.credentials.api_url_format, "api")
|
||||||
} else {
|
} else {
|
||||||
baseUrl = MicroBlogAPIFactory.getApiBaseUrl(DEFAULT_TWITTER_API_URL_FORMAT, "api")
|
MicroBlogAPIFactory.getApiBaseUrl(DEFAULT_TWITTER_API_URL_FORMAT, "api")
|
||||||
}
|
}
|
||||||
val client = DependencyHolder.get(context).restHttpClient
|
val client = DependencyHolder.get(context).restHttpClient
|
||||||
var response: HttpResponse? = null
|
var response: HttpResponse? = null
|
||||||
|
@ -319,8 +319,8 @@ class NetworkDiagnosticsFragment : BaseFragment() {
|
||||||
startDiagnostics.setOnClickListener {
|
startDiagnostics.setOnClickListener {
|
||||||
val intent = Intent(Intent.ACTION_SEND)
|
val intent = Intent(Intent.ACTION_SEND)
|
||||||
intent.type = "text/plain"
|
intent.type = "text/plain"
|
||||||
intent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Twidere Network Diagnostics")
|
intent.putExtra(Intent.EXTRA_SUBJECT, "Twidere Network Diagnostics")
|
||||||
intent.putExtra(android.content.Intent.EXTRA_TEXT, logText.text)
|
intent.putExtra(Intent.EXTRA_TEXT, logText.text)
|
||||||
startActivity(Intent.createChooser(intent, getString(R.string.action_send)))
|
startActivity(Intent.createChooser(intent, getString(R.string.action_send)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ abstract class ParcelableGroupsFragment : AbsContentListRecyclerViewFragment<Par
|
||||||
get() = arguments?.getParcelable<UserKey?>(EXTRA_ACCOUNT_KEY)
|
get() = arguments?.getParcelable<UserKey?>(EXTRA_ACCOUNT_KEY)
|
||||||
|
|
||||||
protected fun hasMoreData(data: List<ParcelableGroup>?): Boolean {
|
protected fun hasMoreData(data: List<ParcelableGroup>?): Boolean {
|
||||||
return data == null || !data.isEmpty()
|
return data == null || data.isNotEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLoadFinished(loader: Loader<List<ParcelableGroup>?>, data: List<ParcelableGroup>?) {
|
override fun onLoadFinished(loader: Loader<List<ParcelableGroup>?>, data: List<ParcelableGroup>?) {
|
||||||
|
|
|
@ -46,6 +46,8 @@ import org.mariotaku.twidere.model.pagination.Pagination
|
||||||
import org.mariotaku.twidere.model.pagination.SinceMaxPagination
|
import org.mariotaku.twidere.model.pagination.SinceMaxPagination
|
||||||
import org.mariotaku.twidere.util.Utils
|
import org.mariotaku.twidere.util.Utils
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by mariotaku on 14/12/3.
|
* Created by mariotaku on 14/12/3.
|
||||||
|
@ -193,13 +195,12 @@ abstract class ParcelableStatusesFragment : AbsStatusesFragment() {
|
||||||
fun removeStatus(statusId: String) {
|
fun removeStatus(statusId: String) {
|
||||||
val list = adapterData ?: return
|
val list = adapterData ?: return
|
||||||
val dataToRemove = HashSet<ParcelableStatus>()
|
val dataToRemove = HashSet<ParcelableStatus>()
|
||||||
for (i in 0 until list.size) {
|
for (element in list) {
|
||||||
val status = list[i]
|
if (element.id == statusId || element.retweet_id == statusId) {
|
||||||
if (status.id == statusId || status.retweet_id == statusId) {
|
dataToRemove.add(element)
|
||||||
dataToRemove.add(status)
|
} else if (element.my_retweet_id == statusId) {
|
||||||
} else if (status.my_retweet_id == statusId) {
|
element.my_retweet_id = null
|
||||||
status.my_retweet_id = null
|
element.retweet_count = element.retweet_count - 1
|
||||||
status.retweet_count = status.retweet_count - 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (list is MutableList) {
|
if (list is MutableList) {
|
||||||
|
@ -211,8 +212,8 @@ abstract class ParcelableStatusesFragment : AbsStatusesFragment() {
|
||||||
fun replaceStatusStates(status: ParcelableStatus?) {
|
fun replaceStatusStates(status: ParcelableStatus?) {
|
||||||
if (status == null) return
|
if (status == null) return
|
||||||
val lm = layoutManager
|
val lm = layoutManager
|
||||||
val rangeStart = Math.max(adapter.statusStartIndex, lm.findFirstVisibleItemPosition())
|
val rangeStart = max(adapter.statusStartIndex, lm.findFirstVisibleItemPosition())
|
||||||
val rangeEnd = Math.min(lm.findLastVisibleItemPosition(), adapter.statusStartIndex + adapter.getStatusCount(false) - 1)
|
val rangeEnd = min(lm.findLastVisibleItemPosition(), adapter.statusStartIndex + adapter.getStatusCount(false) - 1)
|
||||||
for (i in rangeStart..rangeEnd) {
|
for (i in rangeStart..rangeEnd) {
|
||||||
val item = adapter.getStatus(i, false)
|
val item = adapter.getStatus(i, false)
|
||||||
if (status == item) {
|
if (status == item) {
|
||||||
|
|
|
@ -73,7 +73,7 @@ abstract class ParcelableUserListsFragment : AbsContentListRecyclerViewFragment<
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun hasMoreData(data: List<ParcelableUserList>?): Boolean {
|
protected fun hasMoreData(data: List<ParcelableUserList>?): Boolean {
|
||||||
return data == null || !data.isEmpty()
|
return data == null || data.isNotEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLoadFinished(loader: Loader<List<ParcelableUserList>>, data: List<ParcelableUserList>) {
|
override fun onLoadFinished(loader: Loader<List<ParcelableUserList>>, data: List<ParcelableUserList>) {
|
||||||
|
|
|
@ -270,7 +270,7 @@ abstract class ParcelableUsersFragment : AbsContentListRecyclerViewFragment<Parc
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun hasMoreData(data: List<ParcelableUser>?): Boolean {
|
protected fun hasMoreData(data: List<ParcelableUser>?): Boolean {
|
||||||
return data == null || !data.isEmpty()
|
return data == null || data.isNotEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun createMessageBusCallback(): Any {
|
protected fun createMessageBusCallback(): Any {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue