Merge branch 'new_wysiwyg' into develop

This commit is contained in:
tom79 2019-07-21 19:00:37 +02:00
commit b961aa9c54
30 changed files with 1238 additions and 148 deletions

View File

@ -118,4 +118,6 @@ dependencies {
implementation "ch.acra:acra-mail:$acraVersion"
implementation "ch.acra:acra-limiter:$acraVersion"
implementation "ch.acra:acra-notification:$acraVersion"
implementation 'com.github.irshulx:laser-native-editor:3.0.3'
implementation 'com.github.duanhong169:colorpicker:1.1.6'
}

View File

@ -23,7 +23,9 @@
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"
tools:node="remove" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.INTERNET" />
@ -283,7 +285,7 @@
android:fitsSystemWindows="true"
android:configChanges="orientation|screenSize"
android:label="@string/app_name"
android:theme="@style/AppTheme_NoActionBar"
android:theme="@style/AppTheme_NoActionBar_Fedilab"
/>
<activity android:name="app.fedilab.android.activities.EditProfileActivity"
android:windowSoftInputMode="stateAlwaysHidden"

View File

@ -222,7 +222,7 @@ public abstract class BaseMainActivity extends BaseActivity
final int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
switch (theme){
case Helper.THEME_LIGHT:
setTheme(R.style.AppTheme_NoActionBar);
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
break;
case Helper.THEME_DARK:
setTheme(R.style.AppThemeDark_NoActionBar);

View File

@ -76,7 +76,7 @@ public class HashTagActivity extends BaseActivity implements OnRetrieveFeedsInte
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
switch (theme){
case Helper.THEME_LIGHT:
setTheme(R.style.AppTheme_NoActionBar);
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
break;
case Helper.THEME_DARK:
setTheme(R.style.AppThemeDark_NoActionBar);

View File

@ -79,7 +79,7 @@ public class ListActivity extends BaseActivity implements OnListActionInterface
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
switch (theme){
case Helper.THEME_LIGHT:
setTheme(R.style.AppTheme_NoActionBar);
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
break;
case Helper.THEME_DARK:
setTheme(R.style.AppThemeDark_NoActionBar);

View File

@ -70,7 +70,7 @@ public class ManageAccountsInListActivity extends BaseActivity implements OnList
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
switch (theme){
case Helper.THEME_LIGHT:
setTheme(R.style.AppTheme_NoActionBar);
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
getWindow().getDecorView().setBackgroundColor(ContextCompat.getColor(ManageAccountsInListActivity.this, R.color.mastodonC3__));
break;
case Helper.THEME_DARK:

View File

@ -103,7 +103,7 @@ public class OwnerStatusActivity extends BaseActivity implements OnRetrieveFeeds
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
switch (theme){
case Helper.THEME_LIGHT:
setTheme(R.style.AppTheme_NoActionBar);
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
break;
case Helper.THEME_DARK:
setTheme(R.style.AppThemeDark_NoActionBar);

View File

@ -78,7 +78,7 @@ public class PlaylistsActivity extends BaseActivity implements OnPlaylistActionI
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
switch (theme){
case Helper.THEME_LIGHT:
setTheme(R.style.AppTheme_NoActionBar);
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
break;
case Helper.THEME_DARK:
setTheme(R.style.AppThemeDark_NoActionBar);

View File

@ -52,7 +52,7 @@ public class ProxyActivity extends BaseActivity {
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
switch (theme){
case Helper.THEME_LIGHT:
setTheme(R.style.AppTheme_NoActionBar);
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
getWindow().getDecorView().setBackgroundColor(ContextCompat.getColor(ProxyActivity.this, R.color.mastodonC3__));
break;
case Helper.THEME_DARK:

View File

@ -72,7 +72,7 @@ public class SettingsActivity extends BaseActivity implements ViewAnimator.ViewA
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
switch (theme){
case Helper.THEME_LIGHT:
setTheme(R.style.AppTheme_NoActionBar);
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
break;
case Helper.THEME_DARK:
setTheme(R.style.AppThemeDark_NoActionBar);

View File

@ -156,7 +156,7 @@ public class ShowAccountActivity extends BaseActivity implements OnPostActionInt
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
switch (theme){
case Helper.THEME_LIGHT:
setTheme(R.style.AppTheme_NoActionBar);
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
break;
case Helper.THEME_DARK:
setTheme(R.style.AppThemeDark_NoActionBar);

View File

@ -86,7 +86,7 @@ public class ShowConversationActivity extends BaseActivity implements OnRetriev
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
switch (theme){
case Helper.THEME_LIGHT:
setTheme(R.style.AppTheme_NoActionBar);
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
break;
case Helper.THEME_DARK:
setTheme(R.style.AppThemeDark_NoActionBar);
@ -402,7 +402,7 @@ public class ShowConversationActivity extends BaseActivity implements OnRetriev
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
switch (theme){
case Helper.THEME_LIGHT:
setTheme(R.style.AppTheme_NoActionBar);
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
break;
case Helper.THEME_DARK:
setTheme(R.style.AppThemeDark_NoActionBar);

View File

@ -60,7 +60,7 @@ public class TagCacheActivity extends BaseActivity {
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
switch (theme){
case Helper.THEME_LIGHT:
setTheme(R.style.AppTheme_NoActionBar);
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
getWindow().getDecorView().setBackgroundColor(ContextCompat.getColor(TagCacheActivity.this, R.color.mastodonC3__));
break;
case Helper.THEME_DARK:

View File

@ -77,7 +77,7 @@ public class WhoToFollowActivity extends BaseActivity implements OnRetrieveWhoTo
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
switch (theme){
case Helper.THEME_LIGHT:
setTheme(R.style.AppTheme_NoActionBar);
setTheme(R.style.AppTheme_NoActionBar_Fedilab);
break;
case Helper.THEME_DARK:
setTheme(R.style.AppThemeDark_NoActionBar);

View File

@ -70,6 +70,7 @@ import app.fedilab.android.asynctasks.UpdateAccountInfoAsyncTask;
import app.fedilab.android.helper.CrossActions;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.interfaces.OnRetrieveEmojiInterface;
import app.fedilab.android.interfaces.OnRetrieveImageInterface;
import static app.fedilab.android.helper.Helper.THEME_BLACK;
import static app.fedilab.android.helper.Helper.THEME_DARK;
@ -112,6 +113,7 @@ public class Status implements Parcelable{
private String language;
private boolean isTranslated = false;
private boolean isEmojiFound = false;
private boolean isImageFound = false;
private boolean isEmojiTranslateFound = false;
private boolean isClickable = false;
private boolean isTranslationShown = false;
@ -144,6 +146,7 @@ public class Status implements Parcelable{
private boolean shortReply = false;
private int warningFetched = -1;
private List<String> imageURL;
@Override
public void writeToParcel(Parcel dest, int flags) {
@ -207,6 +210,7 @@ public class Status implements Parcelable{
dest.writeByte(this.customFeaturesDisplayed ? (byte) 1 : (byte) 0);
dest.writeByte(this.shortReply ? (byte) 1 : (byte) 0);
dest.writeInt(this.warningFetched);
dest.writeStringList(this.imageURL);
}
protected Status(Parcel in) {
@ -272,6 +276,7 @@ public class Status implements Parcelable{
this.customFeaturesDisplayed = in.readByte() != 0;
this.shortReply = in.readByte() != 0;
this.warningFetched = in.readInt();
this.imageURL = in.createStringArrayList();
}
public static final Creator<Status> CREATOR = new Creator<Status>() {
@ -559,6 +564,9 @@ public class Status implements Parcelable{
return isEmojiFound;
}
public boolean isImageFound() {
return isImageFound;
}
@ -567,6 +575,10 @@ public class Status implements Parcelable{
isEmojiFound = emojiFound;
}
public void setImageFound(boolean imageFound) {
isImageFound = imageFound;
}
public static void transform(Context context, Status status){
@ -605,7 +617,54 @@ public class Status implements Parcelable{
content = content.replaceFirst(Pattern.quote(beforemodification), Matcher.quoteReplacement(urlText));
}
}
Pattern imgPattern = Pattern.compile("<img [^>]*src=\"([^\"]+)\"[^>]*>");
Matcher matcher = imgPattern.matcher(content);
List<String> imgs = new ArrayList<>();
int i = 1;
while (matcher.find()) {
content = content.replaceAll(Pattern.quote(matcher.group(0)), "<br/>[media_"+i+"]<br/>");
imgs.add("[media_"+i+"]|"+matcher.group(1));
i++;
}
status.setImageURL(imgs);
spannableStringContent = new SpannableString(content);
final int[] j = {0};
if( status.getImageURL() != null && status.getImageURL().size() > 0){
for(String val: status.getImageURL()){
String[] valArray = val.split("\\|");
if( valArray.length > 1 ){
String contentOriginal = valArray[0];
String url = valArray[1];
Glide.with(context)
.asBitmap()
.load(url)
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
final String targetedEmoji = contentOriginal;
if (spannableStringContent != null && spannableStringContent.toString().contains(targetedEmoji)) {
//emojis can be used several times so we have to loop
for (int startPosition = -1; (startPosition = spannableStringContent.toString().indexOf(targetedEmoji, startPosition + 1)) != -1; startPosition++) {
final int endPosition = startPosition + targetedEmoji.length();
if( endPosition <= spannableStringContent.toString().length() && endPosition >= startPosition) {
spannableStringContent.setSpan(
new ImageSpan(context,
Bitmap.createScaledBitmap(resource, (int) Helper.convertDpToPixel(300, context),
(int) Helper.convertDpToPixel(300, context), false)), startPosition,
endPosition, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
}
}
}
j[0]++;
if( j[0] == (status.getImageURL().size())) {
status.setContentSpan(spannableStringContent);
}
}
});
}
}
}
String spoilerText = "";
if( status.getReblog() != null && status.getReblog().getSpoiler_text() != null)
spoilerText = status.getReblog().getSpoiler_text();
@ -704,6 +763,9 @@ public class Status implements Parcelable{
accountsMentionUnknown.put(key, account);
}
}
SpannableString spannableStringT;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
spannableStringT = new SpannableString(Html.fromHtml(spannableString.toString().replaceAll("^<p>","").replaceAll("<p>","<br/><br/>").replaceAll("</p>","").replaceAll("<br />","<br/>").replaceAll("[\\s]{2}","&nbsp;&nbsp;"), Html.FROM_HTML_MODE_LEGACY));
@ -1057,6 +1119,75 @@ public class Status implements Parcelable{
}
public static void makeImage(final Context context, final OnRetrieveImageInterface listener, Status status){
if( ((Activity)context).isFinishing() )
return;
if( status.getAccount() == null)
return;
if( status.getImageURL() == null || status.getImageURL().size() == 0)
return;
SpannableString contentSpan = status.getContentSpan();
final int[] i = {0};
for (final String img : status.getImageURL()) {
final String name = img.split("\\|")[0];
final String imgURL = img.split("\\|")[1];
Glide.with(context)
.asBitmap()
.load(imgURL)
.listener(new RequestListener<Bitmap>() {
@Override
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
i[0]++;
if( i[0] == (status.getImageURL().size())) {
listener.onRetrieveImage(status,false);
}
return false;
}
})
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(@NonNull Bitmap resource, Transition<? super Bitmap> transition) {
int w = resource.getWidth();
int h = resource.getHeight();
if( w > 300 ){
h = (h * 300) / w;
w = 300;
}
final String targetedEmoji = name;
if (contentSpan != null && contentSpan.toString().contains(targetedEmoji)) {
//emojis can be used several times so we have to loop
for (int startPosition = -1; (startPosition = contentSpan.toString().indexOf(targetedEmoji, startPosition + 1)) != -1; startPosition++) {
final int endPosition = startPosition + targetedEmoji.length();
if( endPosition <= contentSpan.toString().length() && endPosition >= startPosition)
contentSpan.setSpan(
new ImageSpan(context,
Bitmap.createScaledBitmap(resource, (int) Helper.convertDpToPixel(w, context),
(int) Helper.convertDpToPixel(h, context), false)), startPosition,
endPosition, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
}
}
i[0]++;
if( i[0] == (status.getImageURL().size())) {
status.setContentSpan(contentSpan);
status.setImageFound(true);
listener.onRetrieveImage(status, false);
}
}
});
}
}
public static void makeEmojisTranslation(final Context context, final OnRetrieveEmojiInterface listener, Status status){
if( ((Activity)context).isFinishing() )
@ -1383,4 +1514,12 @@ public class Status implements Parcelable{
public void setWarningFetched(int warningFetched) {
this.warningFetched = warningFetched;
}
public List<String> getImageURL() {
return imageURL;
}
public void setImageURL(List<String> imageURL) {
this.imageURL = imageURL;
}
}

View File

@ -0,0 +1,52 @@
package app.fedilab.android.client.Entities;
/* Copyright 2019 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
public class Suggestion {
private String content;
private String imageUrl;
private suggestionType type;
public enum suggestionType{
TAG,
ACCOUNT,
EMOJI
}
public suggestionType getType() {
return type;
}
public void setType(suggestionType type) {
this.type = type;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}

View File

@ -133,6 +133,7 @@ import app.fedilab.android.helper.CustomTextView;
import app.fedilab.android.helper.Helper;
import app.fedilab.android.helper.MastalabAutoCompleteTextView;
import app.fedilab.android.interfaces.OnPostStatusActionInterface;
import app.fedilab.android.interfaces.OnRetrieveImageInterface;
import app.fedilab.android.interfaces.OnRetrieveRelationshipInterface;
import app.fedilab.android.interfaces.OnRetrieveRelationshipQuickReplyInterface;
import app.fedilab.android.interfaces.OnRetrieveSearcAccountshInterface;
@ -185,7 +186,7 @@ import static app.fedilab.android.helper.Helper.changeDrawableColor;
* Created by Thomas on 24/04/2017.
* Adapter for Status
*/
public class StatusListAdapter extends RecyclerView.Adapter implements OnPostActionInterface, OnRetrieveFeedsInterface, OnRetrieveEmojiInterface, OnRetrieveRepliesInterface, OnRetrieveCardInterface, OnPollInterface, OnRefreshCachedStatusInterface, OnRetrieveSearcAccountshInterface, OnRetrieveSearchInterface, OnPostStatusActionInterface, OnRetrieveRelationshipQuickReplyInterface {
public class StatusListAdapter extends RecyclerView.Adapter implements OnPostActionInterface, OnRetrieveFeedsInterface, OnRetrieveImageInterface, OnRetrieveEmojiInterface, OnRetrieveRepliesInterface, OnRetrieveCardInterface, OnPollInterface, OnRefreshCachedStatusInterface, OnRetrieveSearcAccountshInterface, OnRetrieveSearchInterface, OnPostStatusActionInterface, OnRetrieveRelationshipQuickReplyInterface {
private Context context;
private List<Status> statuses;
@ -537,6 +538,7 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
}
private class ViewHolderEmpty extends RecyclerView.ViewHolder{
ViewHolderEmpty(View itemView) {
super(itemView);
@ -1457,6 +1459,9 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
Status.transform(context, status);
if (!status.isEmojiFound())
Status.makeEmojis(context, this, status);
if (!status.isImageFound())
Status.makeImage(context, this, status);
holder.status_content.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
@ -4110,6 +4115,19 @@ public class StatusListAdapter extends RecyclerView.Adapter implements OnPostAct
}
@Override
public void onRetrieveImage(Status status, boolean fromTranslation) {
if( status != null) {
if( !fromTranslation) {
status.setImageFound(true);
}else {
status.setImageFound(true);
}
notifyStatusChanged(status);
}
}
@Override
public void onRetrieveEmoji(Status status, boolean fromTranslation) {
if( status != null) {

View File

@ -0,0 +1,95 @@
package app.fedilab.android.drawers;
/* Copyright 2019 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
import app.fedilab.android.R;
import app.fedilab.android.client.Entities.Suggestion;
import app.fedilab.android.helper.Helper;
/**
* Created by Thomas on 19/07/2019.
* Adapter for suggestions results
*/
public class SuggestionsAdapter extends RecyclerView.Adapter {
private Context context;
private List<Suggestion> suggestions;
private LayoutInflater layoutInflater;
public SuggestionsAdapter(Context context, List<Suggestion> suggestions){
this.context = context;
this.suggestions = suggestions;
layoutInflater = LayoutInflater.from(context);
}
public Suggestion getItem(int position) {
return suggestions.get(position);
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int i) {
return new ViewHolder(layoutInflater.inflate(R.layout.drawer_suggestions, parent, false));
}
class ViewHolder extends RecyclerView.ViewHolder{
private TextView suggestion_content;
private ImageView suggestion_image;
public ViewHolder(@NonNull View itemView) {
super(itemView);
suggestion_content = itemView.findViewById(R.id.suggestion_content);
suggestion_image = itemView.findViewById(R.id.suggestion_image);
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
final ViewHolder holder = (ViewHolder) viewHolder;
final Suggestion suggestion = getItem(i);
if( suggestion.getType() == Suggestion.suggestionType.TAG) {
holder.suggestion_content.setText(String.format("#%s", suggestion.getContent()));
holder.suggestion_image.setVisibility(View.GONE);
}else{
holder.suggestion_content.setText(suggestion.getContent());
Helper.loadGiF(context, suggestion.getImageUrl(), holder.suggestion_image);
}
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemCount() {
return suggestions.size();
}
}

View File

@ -67,6 +67,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.google.android.material.navigation.NavigationView;
import com.google.common.collect.ImmutableSet;
import org.apache.poi.sl.usermodel.Line;
import org.jetbrains.annotations.NotNull;
import org.json.JSONException;
import org.json.JSONObject;
@ -1042,6 +1043,25 @@ public class ContentSettingsFragment extends Fragment implements ScreenShotable
});
if (MainActivity.social == UpdateAccountInfoAsyncTask.SOCIAL.PLEROMA) {
LinearLayout set_wysiwyg_container = rootView.findViewById(R.id.set_wysiwyg_container);
set_wysiwyg_container.setVisibility(View.VISIBLE);
}
boolean wysiwyg = sharedpreferences.getBoolean(Helper.SET_WYSIWYG, true);
final CheckBox set_wysiwyg = rootView.findViewById(R.id.set_wysiwyg);
set_wysiwyg.setChecked(wysiwyg);
set_wysiwyg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putBoolean(Helper.SET_WYSIWYG, set_wysiwyg.isChecked());
editor.apply();
}
});
final CheckBox set_embedded_browser = rootView.findViewById(R.id.set_embedded_browser);
final LinearLayout set_javascript_container = rootView.findViewById(R.id.set_javascript_container);
final CheckBox set_custom_tabs = rootView.findViewById(R.id.set_custom_tabs);

View File

@ -339,6 +339,7 @@ public class Helper {
public static final String SET_LIVE_NOTIFICATIONS = "set_live_notifications";
public static final String SET_DISABLE_GIF = "set_disable_gif";
public static final String SET_CAPITALIZE = "set_capitalize";
public static final String SET_WYSIWYG = "set_wysiwyg";
public static final String SET_PICTURE_RESIZE = "set_picture_resize";
public static final String SET_FORWARD_TAGS_IN_REPLY = "set_forward_tags_in_reply";
public static final String SET_FULL_PREVIEW = "set_full_preview";
@ -3440,6 +3441,7 @@ public class Helper {
return text.length() - countWithEmoji(text);
}
public static int countWithEmoji(String text){
int emojiCount = 0;
for (int i = 0; i < text.length(); i++) {

View File

@ -0,0 +1,51 @@
package app.fedilab.android.helper;
import android.content.Context;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
import org.jetbrains.annotations.NotNull;
/**
* Work from: https://github.com/percolate/mentions/blob/master/Mentions/sample/src/main/java/com/percolate/mentions/sample/adapters/RecyclerItemClickListener.java
* An onClick listener for items in a RecyclerView. This was taken from the sample provided in the StickyHeadersRecyclerView library.
* https://github.com/timehop/sticky-headers-recyclerview/blob/master/sample/src/main/java/com/timehop/stickyheadersrecyclerview/sample/RecyclerItemClickListener.java
*/
public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
private final OnItemClickListener mListener;
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
private final GestureDetector mGestureDetector;
public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
mListener = listener;
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override public boolean onSingleTapUp(MotionEvent e) {
return true;
}
});
}
@Override
public boolean onInterceptTouchEvent(@NotNull RecyclerView view, @NotNull MotionEvent e) {
View childView = view.findChildViewUnder(e.getX(), e.getY());
if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
}
return false;
}
@Override
public void onTouchEvent(@NotNull RecyclerView view, @NotNull MotionEvent motionEvent) { }
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
// do nothing
}
}

View File

@ -0,0 +1,26 @@
/* Copyright 2019 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
package app.fedilab.android.interfaces;
import app.fedilab.android.client.Entities.Status;
/**
* Created by Thomas on 19/07/2019.
* Interface when retrieving image from img tags
*/
public interface OnRetrieveImageInterface {
void onRetrieveImage(Status status, boolean fromTranslation);
}

View File

@ -17,6 +17,8 @@
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:aztec="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/tools"
android:fillViewport="true">
<RelativeLayout
@ -49,6 +51,7 @@
android:visibility="gone" />
<ScrollView
android:id="@+id/composer_container"
android:layout_below="@+id/toot_cw_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -71,6 +74,40 @@
android:inputType="textMultiLine|textCapSentences"
android:minLines="4" />
</ScrollView>
<HorizontalScrollView android:id="@+id/toolbar"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#e6e6e6"
android:scrollbars="none">
<include layout="@layout/editor_toolbar_linearlayout_horizontal" />
</HorizontalScrollView>
<ScrollView
android:id="@+id/wysiwyg_container"
android:visibility="gone"
android:layout_below="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/bottom_bar_tooting"
android:layout_alignParentEnd="true"
android:layout_marginEnd="0dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_marginBottom="0dp"
android:fillViewport="true">
<com.github.irshulx.Editor
android:layout_width="match_parent"
android:id="@+id/editor"
app:render_type="Editor"
android:hint="@string/toot_placeholder"
android:paddingTop="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:layout_height="wrap_content"
android:paddingBottom="100dp"
/>
</ScrollView>
<LinearLayout
android:id="@+id/bottom_bar_tooting"
android:layout_width="match_parent"

View File

@ -17,6 +17,8 @@
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:aztec="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/tools"
android:fillViewport="true">
<RelativeLayout
@ -50,12 +52,12 @@
android:visibility="gone" />
<ScrollView
android:id="@+id/composer_container"
android:layout_below="@+id/toot_cw_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/bottom_bar_tooting"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginEnd="0dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
@ -71,6 +73,44 @@
android:inputType="textMultiLine|textCapSentences"
android:minLines="4" />
</ScrollView>
<HorizontalScrollView android:id="@+id/toolbar"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#e6e6e6"
android:scrollbars="none">
<include layout="@layout/editor_toolbar_linearlayout_horizontal" />
</HorizontalScrollView>
<ScrollView
android:id="@+id/wysiwyg_container"
android:visibility="gone"
android:layout_below="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/bottom_bar_tooting"
android:layout_alignParentEnd="true"
android:layout_marginEnd="0dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_marginBottom="0dp"
android:fillViewport="true">
<com.github.irshulx.Editor
android:layout_width="match_parent"
android:id="@+id/editor"
app:render_type="Editor"
android:hint="@string/toot_placeholder"
android:paddingTop="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:layout_height="wrap_content"
android:paddingBottom="100dp"
/>
</ScrollView>
<androidx.recyclerview.widget.RecyclerView
android:visibility="gone"
android:id="@+id/suggestions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:id="@+id/bottom_bar_tooting"
android:layout_width="match_parent"

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2019 Thomas Schneider
This file is a part of Fedilab
This program is free software; you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation; either version 3 of the
License, or (at your option) any later version.
Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.
You should have received a copy of the GNU General Public License along with Fedilab; if not,
see <http://www.gnu.org/licenses>.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="2dp"
android:id="@+id/suggestion_container"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_margin="5dp"
android:layout_gravity="center"
android:id="@+id/suggestion_image"
android:layout_width="30dp"
android:layout_height="30dp"
android:contentDescription="@string/profile_picture" />
<TextView
android:layout_marginStart="10dp"
android:maxLines="1"
android:id="@+id/suggestion_content"
android:layout_gravity="center_vertical"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@ -1480,6 +1480,39 @@
</LinearLayout>
</LinearLayout>
<!-- WYSIWYG -->
<LinearLayout
android:id="@+id/set_wysiwyg_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_marginTop="@dimen/settings_checkbox_margin"
android:layout_marginBottom="@dimen/settings_checkbox_margin"
android:orientation="horizontal">
<CheckBox
android:id="@+id/set_wysiwyg"
android:layout_width="wrap_content"
android:textSize="16sp"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:textSize="16sp"
android:text="@string/set_wysiwyg"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:textColor="@color/mastodonC2"
android:text="@string/set_wysiwyg_indication"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
<CheckBox
android:textSize="16sp"
android:id="@+id/set_automatically_split_toot"

View File

@ -17,4 +17,5 @@
<dimen name="activity_vertical_margin_login">50dp</dimen>
<dimen name="badge_count_textsize">12sp</dimen>
<dimen name="editor_size">35dp</dimen>
<dimen name="format_bar_height">50dp</dimen>
</resources>

View File

@ -1120,6 +1120,8 @@
<string name="set_enable_crash_report_indication">If enabled, a crash report will be created locally and then you will be able to share it.</string>
<string name="crash_title">Fedilab has stopped :(</string>
<string name="crash_message">You can send me by email the crash report. It will help to fix it :)\n\nYou can add additional content. Thank you!</string>
<string name="set_wysiwyg">Use the wysiwyg</string>
<string name="set_wysiwyg_indication">When enabled, you will be able to format your text easily with tools.</string>
<plurals name="number_of_vote">
<item quantity="one">%d vote</item>
<item quantity="other">%d votes</item>

View File

@ -52,7 +52,7 @@
</style>
<style name="AppTheme_NoActionBar" parent="Theme.AppCompat.Light.NoActionBar">
<style name="AppTheme_NoActionBar_Fedilab" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:textColor">@color/light_black</item>
<item name="android:scrollbarThumbVertical">@color/transparent</item>
<item name="colorPrimary">@color/white</item>