Fresco and sharing (#531)

* Various improvements

This is literally the worst commit I ever did, but due to rebasing issues this is how it is.

* Fixes after rebase

Signed-off-by: Mario Danic <mario@lovelyhq.com>

* Updates post-rebase

Signed-off-by: Mario Danic <mario@lovelyhq.com>

* Updates #2 post rebase

Signed-off-by: Mario Danic <mario@lovelyhq.com>

* Update deps

Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Đanić 2019-04-24 08:32:19 +02:00 committed by GitHub
parent fd0866dfc5
commit 4143bd841e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
145 changed files with 3945 additions and 998 deletions

View File

@ -1,6 +1,7 @@
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Nextcloud Talk application&#10; &#10;@author Mario Danic&#10;Copyright (C) 2017-2018 Mario Danic &lt;mario@lovelyhq.com&gt;&#10; &#10;This program is free software: you can redistribute it and/or modify&#10;it under the terms of the GNU General Public License as published by&#10;the Free Software Foundation, either version 3 of the License, or&#10;at your option) any later version.&#10; &#10;This program is distributed in the hope that it will be useful,&#10;but WITHOUT ANY WARRANTY; without even the implied warranty of&#10;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the&#10;GNU General Public License for more details.&#10; &#10;You should have received a copy of the GNU General Public License&#10;along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;." />
<option name="allowReplaceRegexp" value="true" />
<option name="notice" value="Nextcloud Talk application&#10; &#10;@author Mario Danic&#10;Copyright (C) 2017-2019 Mario Danic &lt;mario@lovelyhq.com&gt;&#10; &#10;This program is free software: you can redistribute it and/or modify&#10;it under the terms of the GNU General Public License as published by&#10;the Free Software Foundation, either version 3 of the License, or&#10;at your option) any later version.&#10; &#10;This program is distributed in the hope that it will be useful,&#10;but WITHOUT ANY WARRANTY; without even the implied warranty of&#10;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the&#10;GNU General Public License for more details.&#10; &#10;You should have received a copy of the GNU General Public License&#10;along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;." />
<option name="myName" value="GPL3" />
</copyright>
</component>

View File

@ -1,6 +1,27 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'findbugs'
apply plugin: 'kotlin-kapt'
def taskRequest = getGradle().getStartParameter().getTaskRequests().toString()
if (taskRequest.contains("Gplay") || taskRequest.contains("findbugs") || taskRequest.contains("lint")) {
@ -17,8 +38,8 @@ android {
targetSdkVersion 28
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
versionCode 92
versionName "6.0.0beta4"
versionCode 93
versionName "6.0.0"
flavorDimensions "default"
renderscriptTargetApi 19
@ -110,8 +131,9 @@ configurations.all {
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation fileTree(include: ['*'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha4'
@ -121,6 +143,13 @@ dependencies {
implementation "android.arch.work:work-rxjava2:${workVersion}"
implementation 'com.google.android:flexbox:1.1.0'
androidTestImplementation "android.arch.work:work-testing:${workVersion}"
implementation ('com.gitlab.bitfireAT:dav4jvm:f2078bc846', {
exclude group: 'org.ogce', module: 'xpp3' // Android comes with its own XmlPullParser
})
compile 'org.conscrypt:conscrypt-android:2.0.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
implementation 'androidx.biometric:biometric:1.0.0-alpha04'
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
@ -139,76 +168,57 @@ dependencies {
implementation 'com.bluelinelabs:logansquare:1.3.7'
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.9.8'
annotationProcessor 'com.bluelinelabs:logansquare-compiler:1.3.7'
kapt 'com.bluelinelabs:logansquare-compiler:1.3.7'
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
implementation 'com.github.aurae.retrofit2:converter-logansquare:1.4.1'
implementation 'com.google.dagger:dagger:2.21'
annotationProcessor 'com.google.dagger:dagger-compiler:2.21'
kapt 'com.google.dagger:dagger-compiler:2.21'
implementation 'com.github.lukaspili.autodagger2:autodagger2:1.1'
annotationProcessor 'com.github.lukaspili.autodagger2:autodagger2-compiler:1.1'
compileOnly 'javax.annotation:jsr250-api:1.0' // Android only
kapt 'com.github.lukaspili.autodagger2:autodagger2-compiler:1.1'
compileOnly 'javax.annotation:jsr250-api:1.0'
// Android only
implementation 'org.greenrobot:eventbus:3.1.1'
implementation 'io.requery:requery:1.5.1'
implementation 'io.requery:requery-android:1.5.1'
implementation 'net.zetetic:android-database-sqlcipher:3.5.9'
annotationProcessor 'io.requery:requery-processor:1.5.1'
kapt 'io.requery:requery-processor:1.5.1'
implementation 'org.parceler:parceler-api:1.1.12'
annotationProcessor 'org.parceler:parceler:1.1.12'
kapt 'org.parceler:parceler:1.1.12'
implementation 'net.orange-box.storebox:storebox-lib:1.4.0'
compileOnly "org.projectlombok:lombok:1.18.6"
compileOnly 'org.projectlombok:lombok:1.18.6'
annotationProcessor "org.projectlombok:lombok:1.18.6"
implementation 'com.jakewharton:butterknife:10.1.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:10.1.0'
kapt 'com.jakewharton:butterknife-compiler:10.1.0'
implementation 'com.github.HITGIF:TextFieldBoxes:1.4.3'
implementation 'eu.davidea:flexible-adapter:5.1.0'
implementation 'eu.davidea:flexible-adapter-ui:1.0.0'
implementation 'com.github.bumptech.glide:glide:4.9.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
implementation 'com.github.bumptech.glide:okhttp3-integration:4.9.0@aar'
implementation 'com.facebook.fresco:fresco:1.13.0'
implementation 'com.facebook.fresco:animated-webp:1.13.0'
implementation 'com.facebook.fresco:webpsupport:1.13.0'
implementation 'com.facebook.fresco:animated-gif:1.13.0'
implementation "com.facebook.fresco:imagepipeline-okhttp3:1.13.0"
implementation 'org.webrtc:google-webrtc:1.0.23295'
implementation "org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}"
implementation 'com.yarolegovich:lovely-dialog:1.1.0'
implementation 'com.yarolegovich:lovelyinput:1.0.9'
implementation 'com.yarolegovich:mp:1.0.9'
implementation 'me.zhanghai.android.effortlesspermissions:library:1.1.0'
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.8.1'
implementation 'org.apache.commons:commons-lang3:3.8.1'
implementation 'com.github.wooplr:Spotlight:1.3'
implementation('com.github.mario:chatkit:d63d61db95', {
exclude group: 'com.facebook.fresco'
})
implementation 'com.github.mario:chatkit:d63d61db95'
implementation 'com.mario.fresco:fresco:1.11.1-headers'
implementation 'com.mario.fresco:animated-webp:1.11.1-headers'
implementation 'com.mario.fresco:webpsupport:1.11.1-headers'
implementation 'com.mario.fresco:animated-gif:1.11.1-headers'
implementation "com.mario.fresco:imagepipeline-okhttp3:1.11.1-headers"
implementation 'com.github.natario1:Autocomplete:v1.1.0'
implementation 'com.github.Kennyc1012:BottomSheet:2.4.1'
implementation 'eu.davidea:flipview:1.2.0'
implementation 'com.github.mario:PopupBubble:a365177d96'
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
implementation 'com.kevalpatel2106:emoticongifkeyboard:1.1'
implementation group: 'eu.medsea.mimeutil', name: 'mime-util', version: '2.1.3'
implementation 'eu.medsea.mimeutil:mime-util:2.1.3'
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:2.26.0'
testImplementation 'org.powermock:powermock-core:2.0.0'
@ -218,7 +228,14 @@ dependencies {
androidTestImplementation ('androidx.test.espresso:espresso-core:3.1.0-alpha4', {
exclude group: 'com.android.support', module: 'support-annotations'
})
findbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.8.0'
findbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.4.3'
}
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs +=
['-Adagger.floatingBindsMethods=enabled',
'-AparcelerStacktrace',]
}
}

View File

@ -1,3 +1,23 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
dependencies {
implementation "com.google.firebase:firebase-messaging:17.3.4"
}

View File

@ -1,3 +1,23 @@
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.nextcloud.talk">

View File

@ -1,3 +1,23 @@
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.nextcloud.talk">

View File

@ -26,26 +26,23 @@ import android.widget.*;
import androidx.annotation.Nullable;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.LazyHeaders;
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
import com.bumptech.glide.request.RequestOptions;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;
import com.nextcloud.talk.R;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.participants.Participant;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.glide.GlideApp;
import com.nextcloud.talk.utils.DisplayUtils;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
import eu.davidea.flexibleadapter.items.IFilterable;
import eu.davidea.flexibleadapter.utils.FlexibleUtils;
import eu.davidea.flipview.FlipView;
import eu.davidea.viewholders.FlexibleViewHolder;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
import java.util.regex.Pattern;
public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.UserItemViewHolder> implements
IFilterable<String> {
@ -116,23 +113,15 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User
if (userEntity != null && userEntity.getBaseUrl() != null && userEntity.getBaseUrl().startsWith("http://") || userEntity.getBaseUrl().startsWith("https://")) {
holder.avatarImageView.setVisibility(View.VISIBLE);
GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
participant.getUserId(), R.dimen.avatar_size), new LazyHeaders.Builder()
.setHeader("Accept", "image/*")
.setHeader("User-Agent", ApiUtils.getUserAgent())
.build());
int avatarSize = Math.round(NextcloudTalkApplication
.getSharedApplication().getResources().getDimension(R.dimen.avatar_size));
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(holder.avatarImageView.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
participant.getUserId(), R.dimen.avatar_size), null))
.build();
holder.avatarImageView.setController(draweeController);
GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.load(glideUrl)
.centerInside()
.override(avatarSize, avatarSize)
.apply(RequestOptions.bitmapTransform(new CircleCrop()))
.into(holder.avatarImageView.getFrontImageView());
} else {
holder.avatarImageView.setVisibility(View.GONE);
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) holder.linearLayout.getLayoutParams();
@ -146,7 +135,7 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User
@Override
public boolean filter(String constraint) {
return participant.getName() != null &&
StringUtils.containsIgnoreCase(participant.getName().trim(), constraint);
Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(participant.getName().trim()).find();
}
@ -157,7 +146,7 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User
@BindView(R.id.secondary_text)
public TextView serverUrl;
@BindView(R.id.avatar_image)
public FlipView avatarImageView;
public SimpleDraweeView avatarImageView;
@BindView(R.id.linear_layout)
LinearLayout linearLayout;
@BindView(R.id.more_menu)

View File

@ -29,11 +29,9 @@ import android.widget.ImageView;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.LazyHeaders;
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
import com.bumptech.glide.request.RequestOptions;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;
import com.nextcloud.talk.R;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.events.MoreMenuClickEvent;
@ -41,17 +39,15 @@ import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.rooms.Conversation;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.glide.GlideApp;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
import eu.davidea.flexibleadapter.items.IFilterable;
import eu.davidea.flexibleadapter.utils.FlexibleUtils;
import eu.davidea.flipview.FlipView;
import eu.davidea.viewholders.FlexibleViewHolder;
import org.apache.commons.lang3.StringUtils;
import org.greenrobot.eventbus.EventBus;
import java.util.List;
import java.util.regex.Pattern;
public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder> implements IFilterable<String> {
@ -134,21 +130,14 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
.nc_description_more_menu_one_to_one), conversation.getDisplayName()));
if (!TextUtils.isEmpty(conversation.getName())) {
GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
conversation.getName(), R.dimen.avatar_size), new LazyHeaders.Builder()
.setHeader("Accept", "image/*")
.setHeader("User-Agent", ApiUtils.getUserAgent())
.build());
GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.load(glideUrl)
.centerInside()
.override(avatarSize, avatarSize)
.apply(RequestOptions.bitmapTransform(new CircleCrop()))
.into(holder.avatarImageView.getFrontImageView());
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(holder.avatarImageView.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
conversation.getLastMessage().getActorId(),
R.dimen.avatar_size), null))
.build();
holder.avatarImageView.setController(draweeController);
} else {
holder.avatarImageView.setVisibility(View.GONE);
}
@ -156,19 +145,13 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
case ROOM_GROUP_CALL:
holder.moreMenuButton.setContentDescription(String.format(resources.getString(R.string
.nc_description_more_menu_group), conversation.getDisplayName()));
holder.avatarImageView.setFrontImageBitmap(DisplayUtils
.getRoundedBitmapFromVectorDrawableResource(resources,
R.drawable.ic_people_group_white_24px));
holder.avatarImageView.setActualImageResource(R.drawable.ic_people_group_white_24px);
holder.avatarImageView.setVisibility(View.VISIBLE);
break;
case ROOM_PUBLIC_CALL:
holder.moreMenuButton.setContentDescription(String.format(resources.getString(R.string
.nc_description_more_menu_public), conversation.getDisplayName()));
holder.avatarImageView.setFrontImageBitmap(DisplayUtils
.getRoundedBitmapFromVectorDrawableResource(resources,
R.drawable.ic_link_white_24px));
holder.avatarImageView.setActualImageResource(R.drawable.ic_link_white_24px);
holder.avatarImageView.setVisibility(View.VISIBLE);
break;
default:
@ -182,8 +165,7 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
@Override
public boolean filter(String constraint) {
return conversation.getDisplayName() != null &&
StringUtils.containsIgnoreCase(conversation.getDisplayName().trim(), constraint);
Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(conversation.getDisplayName().trim()).find();
}
static class RoomItemViewHolder extends FlexibleViewHolder {
@ -193,7 +175,7 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
@BindView(R.id.secondary_text)
public TextView roomLastPing;
@BindView(R.id.avatar_image)
public FlipView avatarImageView;
public SimpleDraweeView avatarImageView;
@BindView(R.id.more_menu)
public ImageButton moreMenuButton;
@BindView(R.id.password_protected_image_view)

View File

@ -21,6 +21,7 @@
package com.nextcloud.talk.adapters.items;
import android.content.Context;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.text.TextUtils;
@ -31,11 +32,9 @@ import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.amulyakhare.textdrawable.TextDrawable;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.LazyHeaders;
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
import com.bumptech.glide.request.RequestOptions;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;
import com.nextcloud.talk.R;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.models.database.UserEntity;
@ -43,7 +42,6 @@ import com.nextcloud.talk.models.json.chat.ChatMessage;
import com.nextcloud.talk.models.json.rooms.Conversation;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.glide.GlideApp;
import com.vanniktech.emoji.EmojiTextView;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
@ -51,9 +49,9 @@ import eu.davidea.flexibleadapter.items.IFilterable;
import eu.davidea.flexibleadapter.items.IFlexible;
import eu.davidea.flexibleadapter.utils.FlexibleUtils;
import eu.davidea.viewholders.FlexibleViewHolder;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
import java.util.regex.Pattern;
public class ConversationItem extends AbstractFlexibleItem<ConversationItem.ConversationItemViewHolder> implements
IFilterable<String> {
@ -146,10 +144,10 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
holder.dialogLastMessage.setText(conversation.getLastMessage().getText());
} else {
String authorDisplayName = "";
conversation.getLastMessage().setActiveUserId(userEntity.getUserId());
conversation.getLastMessage().setActiveUser(userEntity);
String text;
if (conversation.getLastMessage().getMessageType().equals(ChatMessage.MessageType.REGULAR_TEXT_MESSAGE)) {
if (conversation.getLastMessage().getActorId().equals(conversation.getLastMessage().getActiveUserId())) {
if (conversation.getLastMessage().getActorId().equals(userEntity.getUserId())) {
text = String.format(context.getString(R.string.nc_formatted_message_you), conversation.getLastMessage().getLastMessageDisplayText());
} else {
authorDisplayName = !TextUtils.isEmpty(conversation.getLastMessage().getActorDisplayName()) ?
@ -166,8 +164,6 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
holder.dialogLastMessage.setText(text);
int smallAvatarSize = Math.round(context.getResources().getDimension(R.dimen.small_item_height));
if (conversation.getLastMessage().getActorType().equals("guests")) {
if (TextUtils.isEmpty(authorDisplayName)) {
authorDisplayName = NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_guest);
@ -176,26 +172,18 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
TextDrawable drawable = TextDrawable.builder().beginConfig().bold()
.endConfig().buildRound(String.valueOf(authorDisplayName.charAt(0)),
context.getResources().getColor(R.color.nc_grey));
holder.dialogLastMessageUserAvatar.setImageDrawable(drawable);
} else if (!conversation.getLastMessage().getActorId().equals(userEntity.getUserId())
&& !conversation.getType().equals(Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL)) {
holder.dialogLastMessageUserAvatar.getHierarchy().setImage(drawable, 100, true);
} else if (conversation.getLastMessage().getActorId().equals(userEntity.getUserId())
|| !conversation.getType().equals(Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL)) {
holder.dialogLastMessageUserAvatar.setVisibility(View.VISIBLE);
if (!"bots".equals(conversation.getLastMessage().getActorType())) {
GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
conversation.getLastMessage().getActorId(), R.dimen.small_item_height), new LazyHeaders.Builder()
.setHeader("Accept", "image/*")
.setHeader("User-Agent", ApiUtils.getUserAgent())
.build());
GlideApp.with(context)
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.load(glideUrl)
.centerInside()
.override(smallAvatarSize, smallAvatarSize)
.apply(RequestOptions.bitmapTransform(new CircleCrop()))
.into(holder.dialogLastMessageUserAvatar);
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(holder.dialogLastMessageUserAvatar.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(), conversation.getLastMessage().getActorId(), R.dimen.small_item_height), userEntity))
.build();
holder.dialogLastMessageUserAvatar.setController(draweeController);
} else {
TextDrawable drawable =
TextDrawable.builder().beginConfig().bold().endConfig().buildRound(">", context.getResources().getColor(R.color.black));
@ -213,8 +201,6 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
holder.dialogLastMessage.setText(R.string.nc_no_messages_yet);
}
int avatarSize = Math.round(context.getResources().getDimension(R.dimen.avatar_size));
holder.dialogAvatar.setVisibility(View.VISIBLE);
@ -224,15 +210,15 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
switch (objectType) {
case "share:password":
shouldLoadAvatar = false;
holder.dialogAvatar.setImageBitmap(DisplayUtils
holder.dialogAvatar.getHierarchy().setImage(new BitmapDrawable(DisplayUtils
.getRoundedBitmapFromVectorDrawableResource(context.getResources(),
R.drawable.ic_file_password_request));
R.drawable.ic_file_password_request)), 100, true);
break;
case "file":
shouldLoadAvatar = false;
holder.dialogAvatar.setImageBitmap(DisplayUtils
holder.dialogAvatar.getHierarchy().setImage(new BitmapDrawable(DisplayUtils
.getRoundedBitmapFromVectorDrawableResource(context.getResources(),
R.drawable.ic_file_icon));
R.drawable.ic_file_icon)), 100, true);
break;
default:
break;
@ -245,14 +231,7 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
layers[1] = context.getDrawable(R.drawable.ic_launcher_foreground);
LayerDrawable layerDrawable = new LayerDrawable(layers);
GlideApp.with(context)
.asDrawable()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.load(layerDrawable)
.centerInside()
.override(avatarSize, avatarSize)
.apply(RequestOptions.bitmapTransform(new CircleCrop()))
.into(holder.dialogAvatar);
holder.dialogAvatar.getHierarchy().setPlaceholderImage(DisplayUtils.getRoundedDrawable(layerDrawable));
shouldLoadAvatar = false;
}
@ -260,37 +239,26 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
if (shouldLoadAvatar) {
switch (conversation.getType()) {
case ROOM_TYPE_ONE_TO_ONE_CALL:
if (!TextUtils.isEmpty(conversation.getName())) {
GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
conversation.getName(), R.dimen.avatar_size), new LazyHeaders.Builder()
.setHeader("Accept", "image/*")
.setHeader("User-Agent", ApiUtils.getUserAgent())
.build());
GlideApp.with(context)
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.load(glideUrl)
.centerInside()
.override(avatarSize, avatarSize)
.apply(RequestOptions.bitmapTransform(new CircleCrop()))
.into(holder.dialogAvatar);
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(holder.dialogAvatar.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(), conversation.getName(), R.dimen.avatar_size), null))
.build();
holder.dialogAvatar.setController(draweeController);
} else {
holder.dialogAvatar.setVisibility(View.GONE);
}
break;
case ROOM_GROUP_CALL:
holder.dialogAvatar.setImageBitmap(DisplayUtils
holder.dialogAvatar.getHierarchy().setImage(new BitmapDrawable(DisplayUtils
.getRoundedBitmapFromVectorDrawableResource(context.getResources(),
R.drawable.ic_people_group_white_24px));
R.drawable.ic_people_group_white_24px)), 100, true);
break;
case ROOM_PUBLIC_CALL:
holder.dialogAvatar.setImageBitmap(DisplayUtils
holder.dialogAvatar.getHierarchy().setImage(new BitmapDrawable(DisplayUtils
.getRoundedBitmapFromVectorDrawableResource(context.getResources(),
R.drawable.ic_link_white_24px));
R.drawable.ic_link_white_24px)), 100, true);
break;
default:
holder.dialogAvatar.setVisibility(View.GONE);
@ -301,18 +269,18 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
@Override
public boolean filter(String constraint) {
return conversation.getDisplayName() != null &&
StringUtils.containsIgnoreCase(conversation.getDisplayName().trim(), constraint);
Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(conversation.getDisplayName().trim()).find();
}
static class ConversationItemViewHolder extends FlexibleViewHolder {
@BindView(R.id.dialogAvatar)
ImageView dialogAvatar;
SimpleDraweeView dialogAvatar;
@BindView(R.id.dialogName)
EmojiTextView dialogName;
@BindView(R.id.dialogDate)
TextView dialogDate;
@BindView(R.id.dialogLastMessageUserAvatar)
ImageView dialogLastMessageUserAvatar;
SimpleDraweeView dialogLastMessageUserAvatar;
@BindView(R.id.dialogLastMessage)
EmojiTextView dialogLastMessage;
@BindView(R.id.dialogUnreadBubble)

View File

@ -28,14 +28,12 @@ import butterknife.ButterKnife;
import com.nextcloud.talk.R;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.items.AbstractHeaderItem;
import eu.davidea.flexibleadapter.items.IFilterable;
import eu.davidea.flexibleadapter.items.IFlexible;
import eu.davidea.viewholders.FlexibleViewHolder;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
public class GenericTextHeaderItem extends AbstractHeaderItem<GenericTextHeaderItem.HeaderViewHolder> implements IFilterable<String> {
public class GenericTextHeaderItem extends AbstractHeaderItem<GenericTextHeaderItem.HeaderViewHolder> {
private static final String TAG = "GenericTextHeaderItem";
private String title;
@ -47,11 +45,6 @@ public class GenericTextHeaderItem extends AbstractHeaderItem<GenericTextHeaderI
this.title = title;
}
@Override
public boolean filter(String constraint) {
return StringUtils.containsIgnoreCase(title, constraint);
}
public String getModel() {
return title;
}

View File

@ -22,25 +22,21 @@ package com.nextcloud.talk.adapters.items;
import android.annotation.SuppressLint;
import android.view.View;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.LazyHeaders;
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
import com.bumptech.glide.request.RequestOptions;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.interfaces.DraweeController;
import com.nextcloud.talk.R;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.glide.GlideApp;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
import eu.davidea.flexibleadapter.items.IFilterable;
import eu.davidea.flexibleadapter.items.IFlexible;
import eu.davidea.flexibleadapter.utils.FlexibleUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
import java.util.regex.Pattern;
public class MentionAutocompleteItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
implements IFilterable<String> {
@ -115,32 +111,23 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<UserItem.UserI
}
if (source.equals("calls")) {
holder.avatarFlipView.setFrontImageBitmap(DisplayUtils.getRoundedBitmapFromVectorDrawableResource(NextcloudTalkApplication.getSharedApplication().getResources(), R.drawable.ic_people_group_white_24px));
holder.simpleDraweeView.getHierarchy().setPlaceholderImage(DisplayUtils.getRoundedBitmapDrawableFromVectorDrawableResource(NextcloudTalkApplication.getSharedApplication().getResources(), R.drawable.ic_people_group_white_24px));
} else {
GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(currentUser.getBaseUrl(),
objectId, R.dimen.avatar_size), new LazyHeaders.Builder()
.setHeader("Accept", "image/*")
.setHeader("User-Agent", ApiUtils.getUserAgent())
.build());
int avatarSize = Math.round(NextcloudTalkApplication
.getSharedApplication().getResources().getDimension(R.dimen.avatar_size));
GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.load(glideUrl)
.centerInside()
.override(avatarSize, avatarSize)
.apply(RequestOptions.bitmapTransform(new CircleCrop()))
.into(holder.avatarFlipView.getFrontImageView());
holder.simpleDraweeView.setController(null);
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(holder.simpleDraweeView.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(currentUser.getBaseUrl(),
objectId, R.dimen.avatar_size_big), null))
.build();
holder.simpleDraweeView.setController(draweeController);
}
}
@Override
public boolean filter(String constraint) {
return objectId != null && StringUtils.containsIgnoreCase(objectId, constraint) ||
displayName != null && StringUtils.containsIgnoreCase(displayName, constraint);
return objectId != null && Pattern.compile(constraint,
Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(objectId).find()
|| displayName != null && Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(displayName).find();
}
}

View File

@ -20,12 +20,16 @@
package com.nextcloud.talk.adapters.items;
import android.content.res.Resources;
import android.graphics.drawable.ColorDrawable;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.facebook.drawee.view.SimpleDraweeView;
import com.nextcloud.talk.R;
import com.nextcloud.talk.utils.MagicFlipView;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
import eu.davidea.flexibleadapter.items.IFlexible;
@ -38,10 +42,6 @@ public class NotificationSoundItem extends AbstractFlexibleItem<NotificationSoun
private String notificationSoundName;
private String notificationSoundUri;
private boolean selected;
private MagicFlipView flipView;
public NotificationSoundItem(String notificationSoundName, String notificationSoundUri) {
this.notificationSoundName = notificationSoundName;
this.notificationSoundUri = notificationSoundUri;
@ -70,51 +70,34 @@ public class NotificationSoundItem extends AbstractFlexibleItem<NotificationSoun
return new NotificationSoundItemViewHolder(view, adapter);
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
public void flipToFront() {
if (flipView != null && flipView.isFlipped()) {
flipView.flip(false);
}
}
public void flipItemSelection() {
if (flipView != null) {
flipView.flip(!flipView.isFlipped());
}
}
@Override
public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, NotificationSoundItemViewHolder holder, int position, List<Object> payloads) {
flipView = holder.magicFlipView;
holder.magicFlipView.flipSilently(adapter.isSelected(position) || isSelected());
if (isSelected() && !adapter.isSelected(position)) {
adapter.toggleSelection(position);
selected = false;
}
holder.notificationName.setText(notificationSoundName);
if (position == 0) {
holder.magicFlipView.setFrontImage(R.drawable.ic_stop_white_24dp);
if (adapter.isSelected(position)) {
holder.checkedImageView.setVisibility(View.VISIBLE);
} else {
holder.magicFlipView.setFrontImage(R.drawable.ic_play_circle_outline_white_24dp);
holder.checkedImageView.setVisibility(View.GONE);
}
Resources resources = NextcloudTalkApplication.getSharedApplication().getResources();
holder.simpleDraweeView.getHierarchy().setBackgroundImage(new ColorDrawable(resources.getColor(R.color.colorPrimary)));
if (position == 0) {
holder.simpleDraweeView.getHierarchy().setImage(resources.getDrawable(R.drawable.ic_stop_white_24dp), 100,
true);
} else {
holder.simpleDraweeView.getHierarchy().setImage(resources.getDrawable(R.drawable.ic_play_circle_outline_white_24dp), 100,
true);
}
}
static class NotificationSoundItemViewHolder extends FlexibleViewHolder {
@BindView(R.id.notificationNameTextView)
public TextView notificationName;
@BindView(R.id.magicFlipView)
MagicFlipView magicFlipView;
@BindView(R.id.simpleDraweeView)
SimpleDraweeView simpleDraweeView;
@BindView(R.id.checkedImageView)
ImageView checkedImageView;
/**
* Default constructor.

View File

@ -21,17 +21,16 @@
package com.nextcloud.talk.adapters.items;
import android.content.res.Resources;
import android.graphics.drawable.BitmapDrawable;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.LazyHeaders;
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
import com.bumptech.glide.request.RequestOptions;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;
import com.nextcloud.talk.R;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.models.database.UserEntity;
@ -39,18 +38,16 @@ import com.nextcloud.talk.models.json.converters.EnumParticipantTypeConverter;
import com.nextcloud.talk.models.json.participants.Participant;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.glide.GlideApp;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
import eu.davidea.flexibleadapter.items.IFilterable;
import eu.davidea.flexibleadapter.items.ISectionable;
import eu.davidea.flexibleadapter.utils.FlexibleUtils;
import eu.davidea.flipview.FlipView;
import eu.davidea.viewholders.FlexibleViewHolder;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nullable;
import java.util.List;
import java.util.regex.Pattern;
public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder> implements
ISectionable<UserItem.UserItemViewHolder, GenericTextHeaderItem>, IFilterable<String> {
@ -59,9 +56,6 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
private UserEntity userEntity;
private GenericTextHeaderItem header;
private FlipView flipView;
public UserItem(Participant participant, UserEntity userEntity, GenericTextHeaderItem genericTextHeaderItem) {
this.participant = participant;
this.userEntity = userEntity;
@ -94,9 +88,6 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
return userEntity;
}
public void flipItemSelection() {
flipView.flip(!flipView.isFlipped());
}
@Override
public int getLayoutRes() {
@ -115,9 +106,13 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
@Override
public void bindViewHolder(FlexibleAdapter adapter, UserItemViewHolder holder, int position, List payloads) {
flipView = holder.avatarFlipView;
flipView.flipSilently(adapter.isSelected(position));
if (holder.checkedImageView != null) {
if (adapter.isSelected(position)) {
holder.checkedImageView.setVisibility(View.VISIBLE);
} else {
holder.checkedImageView.setVisibility(View.GONE);
}
}
if (adapter.hasFilter()) {
FlexibleUtils.highlightText(holder.contactDisplayName, participant.getDisplayName(),
@ -132,35 +127,23 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
}
}
int avatarSize = Math.round(NextcloudTalkApplication
.getSharedApplication().getResources().getDimension(R.dimen.avatar_size));
if (TextUtils.isEmpty(participant.getSource()) || participant.getSource().equals("users")) {
if (Participant.ParticipantType.GUEST.equals(participant.getType()) ||
Participant.ParticipantType.USER_FOLLOWING_LINK.equals(participant.getType())) {
// TODO: Show generated avatar for guests
} else {
GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
participant.getUserId(), R.dimen.avatar_size), new LazyHeaders.Builder()
.setHeader("Accept", "image/*")
.setHeader("User-Agent", ApiUtils.getUserAgent())
.build());
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(holder.simpleDraweeView.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
participant.getUserId(), R.dimen.avatar_size), null))
.build();
holder.simpleDraweeView.setController(draweeController);
GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.load(glideUrl)
.centerInside()
.override(avatarSize, avatarSize)
.apply(RequestOptions.bitmapTransform(new CircleCrop()))
.into(flipView.getFrontImageView());
}
} else if ("groups".equals(participant.getSource())) {
flipView.setFrontImageBitmap(DisplayUtils
.getRoundedBitmapFromVectorDrawableResource(NextcloudTalkApplication.getSharedApplication().getResources(),
R.drawable.ic_people_group_white_24px));
holder.simpleDraweeView.getHierarchy().setImage(new BitmapDrawable(DisplayUtils.getRoundedBitmapFromVectorDrawableResource(NextcloudTalkApplication.getSharedApplication().getResources(), R.drawable.ic_people_group_white_24px)), 100, true);
}
if (!isEnabled()) {
@ -206,6 +189,8 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
break;
}
if (holder.contactMentionId != null) {
String userType = "";
switch (new EnumParticipantTypeConverter().convertToInt(participant.getType())) {
@ -232,11 +217,12 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
holder.contactMentionId.setTextColor(NextcloudTalkApplication.getSharedApplication().getResources().getColor(R.color.colorPrimary));
}
}
}
@Override
public boolean filter(String constraint) {
return participant.getDisplayName() != null &&
StringUtils.containsIgnoreCase(participant.getDisplayName().trim(), constraint);
Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(participant.getDisplayName().trim()).find();
}
@Override
@ -254,8 +240,8 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
@BindView(R.id.name_text)
public TextView contactDisplayName;
@BindView(R.id.avatar_flip_view)
public FlipView avatarFlipView;
@BindView(R.id.simple_drawee_view)
public SimpleDraweeView simpleDraweeView;
@Nullable
@BindView(R.id.secondary_text)
public TextView contactMentionId;
@ -265,6 +251,9 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
@Nullable
@BindView(R.id.videoCallImageView)
ImageView videoCallImageView;
@Nullable
@BindView(R.id.checkedImageView)
ImageView checkedImageView;
/**
* Default constructor.

View File

@ -145,14 +145,14 @@ public class MagicIncomingTextMessageViewHolder
Map<String, String> individualHashMap = message.getMessageParameters().get(key);
if (individualHashMap != null) {
if (individualHashMap.get("type").equals("user") || individualHashMap.get("type").equals("guest") || individualHashMap.get("type").equals("call")) {
if (individualHashMap.get("id").equals(message.getActiveUserId())) {
if (individualHashMap.get("id").equals(message.getActiveUser().getUserId())) {
messageString =
DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(),
messageString,
individualHashMap.get("id"),
individualHashMap.get("name"),
individualHashMap.get("type"),
userUtils.getUserById(message.getActiveUserId()),
userUtils.getUserById(message.getActiveUser().getUserId()),
R.xml.chip_accent_background);
} else {
messageString =
@ -161,7 +161,7 @@ public class MagicIncomingTextMessageViewHolder
individualHashMap.get("id"),
individualHashMap.get("name"),
individualHashMap.get("type"),
userUtils.getUserById(message.getActiveUserId()),
userUtils.getUserById(message.getActiveUser().getUserId()),
R.xml.chip_incoming_others);
}

View File

@ -92,14 +92,14 @@ public class MagicOutcomingTextMessageViewHolder extends MessageHolders.Outcomin
Map<String, String> individualHashMap = message.getMessageParameters().get(key);
if (individualHashMap != null) {
if (individualHashMap.get("type").equals("user") || individualHashMap.get("type").equals("guest") || individualHashMap.get("type").equals("call")) {
if (!individualHashMap.get("id").equals(message.getActiveUserId())) {
if (!individualHashMap.get("id").equals(message.getActiveUser().getUserId())) {
messageString =
DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(),
messageString,
individualHashMap.get("id"),
individualHashMap.get("name"),
individualHashMap.get("type"),
userUtils.getUserById(message.getActiveUserId()),
userUtils.getUserById(message.getActiveUser().getUserId()),
R.xml.chip_outgoing_others);
} else {
messageString =
@ -108,7 +108,7 @@ public class MagicOutcomingTextMessageViewHolder extends MessageHolders.Outcomin
individualHashMap.get("id"),
individualHashMap.get("name"),
individualHashMap.get("type"),
userUtils.getUserById(message.getActiveUserId()),
userUtils.getUserById(message.getActiveUser().getUserId()),
R.xml.chip_outgoing_own_mention);
}
} else if (individualHashMap.get("type").equals("file")) {

View File

@ -21,23 +21,39 @@
package com.nextcloud.talk.adapters.messages;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import autodagger.AutoInjector;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.nextcloud.talk.R;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.components.filebrowser.models.BrowserFile;
import com.nextcloud.talk.components.filebrowser.models.DavResponse;
import com.nextcloud.talk.components.filebrowser.webdav.ReadFilesystemOperation;
import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.chat.ChatMessage;
import com.nextcloud.talk.utils.AccountUtils;
import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.DrawableUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.stfalcon.chatkit.messages.MessageHolders;
import com.vanniktech.emoji.EmojiTextView;
import io.reactivex.Single;
import io.reactivex.SingleObserver;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.OkHttpClient;
import javax.inject.Inject;
import java.util.List;
import java.util.concurrent.Callable;
@AutoInjector(NextcloudTalkApplication.class)
public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageMessageViewHolder<ChatMessage> {
@ -48,6 +64,9 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
@Inject
Context context;
@Inject
OkHttpClient okHttpClient;
public MagicPreviewMessageViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
@ -58,7 +77,6 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
@Override
public void onBind(ChatMessage message) {
super.onBind(message);
if (userAvatar != null) {
if (message.isGrouped) {
userAvatar.setVisibility(View.INVISIBLE);
@ -80,10 +98,32 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
// it's a preview for a Nextcloud share
messageText.setText(message.getSelectedIndividualHashMap().get("name"));
DisplayUtils.setClickableString(message.getSelectedIndividualHashMap().get("name"), message.getSelectedIndividualHashMap().get("link"), messageText);
if (message.getSelectedIndividualHashMap().containsKey("mimetype")) {
image.getHierarchy().setPlaceholderImage(context.getDrawable(DrawableUtils.getDrawableResourceIdForMimeType(message.getSelectedIndividualHashMap().get("mimetype"))));
} else {
fetchFileInformation("/" + message.getSelectedIndividualHashMap().get("path"), message.getActiveUser());
}
image.setOnClickListener(v -> {
String accountString =
message.getActiveUser().getUsername() + "@" + message.getActiveUser().getBaseUrl().replace("https://", "").replace("http://", "");
if (AccountUtils.canWeOpenFilesApp(context, accountString)) {
Intent filesAppIntent = new Intent(Intent.ACTION_VIEW, null);
final ComponentName componentName = new ComponentName(context.getString(R.string.nc_import_accounts_from), "com.owncloud.android.ui.activity.FileDisplayActivity");
filesAppIntent.setComponent(componentName);
filesAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
filesAppIntent.setPackage(context.getString(R.string.nc_import_accounts_from));
Bundle options = new Bundle();
options.putString(BundleKeys.KEY_ACCOUNT, accountString);
options.putString(BundleKeys.KEY_FILE_PATH, "/" + message.getSelectedIndividualHashMap().get("path"));
context.startActivity(filesAppIntent, options);
} else {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(message.getSelectedIndividualHashMap().get("link")));
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
NextcloudTalkApplication.getSharedApplication().getApplicationContext().startActivity(browserIntent);
context.startActivity(browserIntent);
}
});
} else if (message.getMessageType() == ChatMessage.MessageType.SINGLE_LINK_GIPHY_MESSAGE) {
messageText.setText("GIPHY");
@ -95,4 +135,36 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
messageText.setText("");
}
}
private void fetchFileInformation(String url, UserEntity activeUser) {
Single.fromCallable(new Callable<ReadFilesystemOperation>() {
@Override
public ReadFilesystemOperation call() {
return new ReadFilesystemOperation(okHttpClient, activeUser, url, 0);
}
}).subscribeOn(Schedulers.newThread())
.subscribe(new SingleObserver<ReadFilesystemOperation>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onSuccess(ReadFilesystemOperation readFilesystemOperation) {
DavResponse davResponse = readFilesystemOperation.readRemotePath();
if (davResponse.getData() != null) {
List<BrowserFile> browserFileList = (List<BrowserFile>) davResponse.getData();
if (!browserFileList.isEmpty()) {
image.getHierarchy().setPlaceholderImage(context.getDrawable(DrawableUtils.getDrawableResourceIdForMimeType(browserFileList.get(0).getMimeType())));
}
}
}
@Override
public void onError(Throwable e) {
}
});
}
}

View File

@ -61,7 +61,7 @@ public class MagicSystemMessageViewHolder extends MessageHolders.IncomingTextMes
int color;
if (individualHashMap != null && (individualHashMap.get("type").equals("user") || individualHashMap.get("type").equals("guest") || individualHashMap.get("type").equals("call"))) {
if (individualHashMap.get("id").equals(message.getActiveUserId())) {
if (individualHashMap.get("id").equals(message.getActiveUser().getUserId())) {
color = context.getResources().getColor(R.color.nc_incoming_text_mention_you);
} else {
color = context.getResources().getColor(R.color.nc_incoming_text_mention_others);

View File

@ -306,4 +306,11 @@ public interface NcApi {
@PUT
Observable<GenericOverall> setReadOnlyState(@Header("Authorization") String authorization, @Url String url, @Field("state") int state);
@FormUrlEncoded
@POST
Observable<Void> createRemoteShare(@Nullable @Header("Authorization") String authorization, @Url String url,
@Field("path") String remotePath,
@Field("shareWith") String roomToken,
@Field("shareType") String shareType);
}

View File

@ -35,6 +35,7 @@ import autodagger.AutoInjector;
import com.facebook.cache.disk.DiskCacheConfig;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.imagepipeline.core.ImagePipelineConfig;
import com.nextcloud.talk.components.filebrowser.webdav.DavUtils;
import com.nextcloud.talk.dagger.modules.BusModule;
import com.nextcloud.talk.dagger.modules.ContextModule;
import com.nextcloud.talk.dagger.modules.DatabaseModule;
@ -53,12 +54,14 @@ import com.nextcloud.talk.webrtc.MagicWebRTCUtils;
import com.vanniktech.emoji.EmojiManager;
import com.vanniktech.emoji.twitter.TwitterEmojiProvider;
import okhttp3.OkHttpClient;
import org.conscrypt.Conscrypt;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.voiceengine.WebRtcAudioManager;
import org.webrtc.voiceengine.WebRtcAudioUtils;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.security.Security;
import java.util.concurrent.TimeUnit;
@AutoComponent(
@ -121,6 +124,7 @@ public class NextcloudTalkApplication extends MultiDexApplication implements Lif
initializeWebRtc();
DisplayUtils.useCompatVectorIfNeeded();
buildComponent();
DavUtils.registerCustomFactories();
componentApplication.inject(this);
@ -134,6 +138,7 @@ public class NextcloudTalkApplication extends MultiDexApplication implements Lif
.build();
Fresco.initialize(this, imagePipelineConfig);
Security.insertProviderAt(Conscrypt.newProvider(), 1);
new ClosedInterfaceImpl().providerInstallerInstallIfNeededAsync();
DeviceUtils.ignoreSpecialBatteryFeatures();

View File

@ -0,0 +1,186 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.components.filebrowser.adapters.items;
import android.content.Context;
import android.text.format.Formatter;
import android.view.View;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import autodagger.AutoInjector;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;
import com.nextcloud.talk.R;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.components.filebrowser.models.BrowserFile;
import com.nextcloud.talk.interfaces.SelectionInterface;
import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.DateUtils;
import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.DrawableUtils;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
import eu.davidea.flexibleadapter.items.IFilterable;
import eu.davidea.flexibleadapter.items.IFlexible;
import eu.davidea.viewholders.FlexibleViewHolder;
import javax.inject.Inject;
import java.util.List;
@AutoInjector(NextcloudTalkApplication.class)
public class BrowserFileItem extends AbstractFlexibleItem<BrowserFileItem.ViewHolder> implements IFilterable<String> {
@Inject
Context context;
private BrowserFile browserFile;
private UserEntity activeUser;
private SelectionInterface selectionInterface;
private boolean selected;
public BrowserFileItem(BrowserFile browserFile, UserEntity activeUser, SelectionInterface selectionInterface) {
this.browserFile = browserFile;
this.activeUser = activeUser;
this.selectionInterface = selectionInterface;
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
}
@Override
public boolean equals(Object o) {
if (o instanceof BrowserFileItem) {
BrowserFileItem inItem = (BrowserFileItem) o;
return browserFile.getPath().equals(inItem.getModel().getPath());
}
return false;
}
public BrowserFile getModel() {
return browserFile;
}
@Override
public int getLayoutRes() {
return R.layout.rv_item_browser_file;
}
@Override
public ViewHolder createViewHolder(View view, FlexibleAdapter<IFlexible> adapter) {
return new ViewHolder(view, adapter);
}
private boolean isSelected() {
return selected;
}
private void setSelected(boolean selected) {
this.selected = selected;
}
@Override
public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, ViewHolder holder, int position, List<Object> payloads) {
holder.fileIconImageView.setController(null);
if (browserFile.isEncrypted()) {
holder.fileEncryptedImageView.setVisibility(View.VISIBLE);
holder.itemView.setEnabled(false);
holder.itemView.setAlpha(0.38f);
} else {
holder.fileEncryptedImageView.setVisibility(View.GONE);
holder.itemView.setEnabled(true);
holder.itemView.setAlpha(1.0f);
}
if (browserFile.isFavorite()) {
holder.fileFavoriteImageView.setVisibility(View.VISIBLE);
} else {
holder.fileFavoriteImageView.setVisibility(View.GONE);
}
holder.fileIconImageView.getHierarchy().setPlaceholderImage(context.getDrawable(DrawableUtils.getDrawableResourceIdForMimeType(browserFile.getMimeType())));
if (browserFile.isHasPreview()) {
String path = ApiUtils.getUrlForFilePreviewWithRemotePath(activeUser.getBaseUrl(),
browserFile.getPath(),
context.getResources().getDimensionPixelSize(R.dimen.small_item_height));
if (path.length() > 0) {
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(path, null))
.build();
holder.fileIconImageView.setController(draweeController);
}
}
holder.filenameTextView.setText(browserFile.getDisplayName());
holder.fileModifiedTextView.setText(String.format(context.getString(R.string.nc_last_modified),
Formatter.formatShortFileSize(context, browserFile.getSize()),
DateUtils.getLocalDateTimeStringFromTimestamp(context, browserFile.getModifiedTimestamp())));
setSelected(selectionInterface.isPathSelected(browserFile.getPath()));
holder.selectFileCheckbox.setChecked(isSelected());
if (!browserFile.isEncrypted()) {
holder.selectFileCheckbox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (((CheckBox) v).isChecked() != isSelected()) {
setSelected(((CheckBox) v).isChecked());
selectionInterface.toggleBrowserItemSelection(browserFile.getPath());
}
}
});
}
holder.filenameTextView.setSelected(true);
holder.fileModifiedTextView.setSelected(true);
}
@Override
public boolean filter(String constraint) {
return false;
}
static class ViewHolder extends FlexibleViewHolder {
@BindView(R.id.file_icon)
public SimpleDraweeView fileIconImageView;
@BindView(R.id.file_modified_info)
public TextView fileModifiedTextView;
@BindView(R.id.filename_text_view)
public TextView filenameTextView;
@BindView(R.id.select_file_checkbox)
public CheckBox selectFileCheckbox;
@BindView(R.id.fileEncryptedImageView)
public ImageView fileEncryptedImageView;
@BindView(R.id.fileFavoriteImageView)
public ImageView fileFavoriteImageView;
ViewHolder(View view, FlexibleAdapter adapter) {
super(view, adapter);
ButterKnife.bind(this, view);
}
}
}

View File

@ -0,0 +1,333 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.components.filebrowser.controllers;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Bundle;
import android.view.*;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.work.Data;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
import autodagger.AutoInjector;
import butterknife.BindView;
import butterknife.OnClick;
import com.google.android.material.bottomnavigation.BottomNavigationItemView;
import com.nextcloud.talk.R;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.components.filebrowser.adapters.items.BrowserFileItem;
import com.nextcloud.talk.components.filebrowser.interfaces.ListingInterface;
import com.nextcloud.talk.components.filebrowser.models.BrowserFile;
import com.nextcloud.talk.components.filebrowser.models.DavResponse;
import com.nextcloud.talk.components.filebrowser.operations.DavListing;
import com.nextcloud.talk.components.filebrowser.operations.ListingAbstractClass;
import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.interfaces.SelectionInterface;
import com.nextcloud.talk.jobs.ShareOperationWorker;
import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils;
import eu.davidea.fastscroller.FastScroller;
import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager;
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
import eu.davidea.flexibleadapter.items.IFlexible;
import okhttp3.OkHttpClient;
import org.parceler.Parcel;
import org.parceler.Parcels;
import javax.inject.Inject;
import java.io.File;
import java.util.*;
@AutoInjector(NextcloudTalkApplication.class)
public class BrowserController extends BaseController implements ListingInterface,
FlexibleAdapter.OnItemClickListener, SelectionInterface {
private final Set<String> selectedPaths;
@Inject
UserUtils userUtils;
@BindView(R.id.recycler_view)
RecyclerView recyclerView;
@BindView(R.id.fast_scroller)
FastScroller fastScroller;
@BindView(R.id.action_back)
BottomNavigationItemView backMenuItem;
@BindView(R.id.action_refresh)
BottomNavigationItemView actionRefreshMenuItem;
@Inject
Context context;
@Inject
OkHttpClient okHttpClient;
private MenuItem filesSelectionDoneMenuItem;
private RecyclerView.LayoutManager layoutManager;
private FlexibleAdapter<AbstractFlexibleItem> adapter;
private List<AbstractFlexibleItem> recyclerViewItems = new ArrayList<>();
private ListingAbstractClass listingAbstractClass;
private BrowserType browserType;
private String currentPath;
private UserEntity activeUser;
private String roomToken;
public BrowserController(Bundle args) {
super(args);
setHasOptionsMenu(true);
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
browserType = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_BROWSER_TYPE));
activeUser = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_USER_ENTITY));
roomToken = args.getString(BundleKeys.KEY_ROOM_TOKEN);
currentPath = "/";
if (BrowserType.DAV_BROWSER.equals(browserType)) {
listingAbstractClass = new DavListing(this);
} else {
//listingAbstractClass = new LocalListing(this);
}
selectedPaths = Collections.synchronizedSet(new TreeSet<>());
}
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_browser, container, false);
}
@Override
protected void onViewBound(@NonNull View view) {
super.onViewBound(view);
if (adapter == null) {
adapter = new FlexibleAdapter<>(recyclerViewItems, context, false);
}
changeEnabledStatusForBarItems(true);
prepareViews();
}
private void onFileSelectionDone() {
synchronized (selectedPaths) {
Iterator<String> iterator = selectedPaths.iterator();
List<String> paths = new ArrayList<>();
Data data;
OneTimeWorkRequest shareWorker;
while (iterator.hasNext()) {
String path = iterator.next();
paths.add(path);
iterator.remove();
if (paths.size() == 10 || !iterator.hasNext()) {
data = new Data.Builder()
.putLong(BundleKeys.KEY_INTERNAL_USER_ID, activeUser.getId())
.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken)
.putStringArray(BundleKeys.KEY_FILE_PATHS, paths.toArray(new String[0]))
.build();
shareWorker = new OneTimeWorkRequest.Builder(ShareOperationWorker.class)
.setInputData(data)
.build();
WorkManager.getInstance().enqueue(shareWorker);
paths = new ArrayList<>();
}
}
}
getRouter().popCurrentController();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_share_files, menu);
filesSelectionDoneMenuItem = menu.findItem(R.id.files_selection_done);
filesSelectionDoneMenuItem.setVisible(selectedPaths.size() > 0);
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.files_selection_done:
onFileSelectionDone();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
protected void onAttach(@NonNull View view) {
super.onAttach(view);
refreshCurrentPath();
}
@Override
public void onDestroy() {
super.onDestroy();
listingAbstractClass.tearDown();
}
@Override
protected String getTitle() {
return currentPath;
}
@OnClick(R.id.action_back)
void goBack() {
fetchPath(new File(currentPath).getParent());
}
@OnClick(R.id.action_refresh)
void refreshCurrentPath() {
fetchPath(currentPath);
}
@SuppressLint("RestrictedApi")
private void changeEnabledStatusForBarItems(boolean shouldBeEnabled) {
if (actionRefreshMenuItem != null) {
actionRefreshMenuItem.setEnabled(shouldBeEnabled);
}
if (backMenuItem != null) {
backMenuItem.setEnabled(shouldBeEnabled && !currentPath.equals("/"));
}
}
private void fetchPath(String path) {
listingAbstractClass.cancelAllJobs();
changeEnabledStatusForBarItems(false);
listingAbstractClass.getFiles(path, activeUser, BrowserType.DAV_BROWSER.equals(browserType) ? okHttpClient : null);
}
@Override
public void listingResult(DavResponse davResponse) {
adapter.clear();
List<AbstractFlexibleItem> fileBrowserItems = new ArrayList<>();
if (davResponse.getData() != null) {
final List<BrowserFile> objectList = (List<BrowserFile>) davResponse.getData();
currentPath = objectList.get(0).getPath();
Objects.requireNonNull(getActivity()).runOnUiThread(this::setTitle);
for (int i = 1; i < objectList.size(); i++) {
fileBrowserItems.add(new BrowserFileItem(objectList.get(i), activeUser, this));
}
}
adapter.addItems(0, fileBrowserItems);
Objects.requireNonNull(getActivity()).runOnUiThread(() -> {
adapter.notifyDataSetChanged();
changeEnabledStatusForBarItems(true);
});
}
private boolean shouldPathBeSelectedDueToParent(String currentPath) {
if (selectedPaths.size() > 0) {
File file = new File(currentPath);
if (!file.getParent().equals("/")) {
while (file.getParent() != null) {
String parent = file.getParent();
if (new File(file.getParent()).getParent() != null) {
parent += "/";
}
if (selectedPaths.contains(parent)) {
return true;
}
file = new File(file.getParent());
}
}
}
return false;
}
private void checkAndRemoveAnySelectedParents(String currentPath) {
File file = new File(currentPath);
selectedPaths.remove(currentPath);
while (file.getParent() != null) {
selectedPaths.remove(file.getParent() + "/");
file = new File(file.getParent());
}
adapter.notifyDataSetChanged();
}
@Override
public boolean onItemClick(View view, int position) {
BrowserFile browserFile = ((BrowserFileItem) adapter.getItem(position)).getModel();
if ("inode/directory".equals((browserFile.getMimeType()))) {
fetchPath(browserFile.getPath());
return true;
}
return false;
}
private void prepareViews() {
if (getActivity() != null) {
layoutManager = new SmoothScrollLinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
adapter.setFastScroller(fastScroller);
adapter.addListener(this);
fastScroller.setBubbleTextCreator(position -> {
IFlexible abstractFlexibleItem = adapter.getItem(position);
if (abstractFlexibleItem instanceof BrowserFileItem) {
return String.valueOf(((BrowserFileItem) adapter.getItem(position)).getModel().getDisplayName().charAt(0));
} else {
return "";
}
});
}
}
@SuppressLint("RestrictedApi")
@Override
public void toggleBrowserItemSelection(String path) {
if (selectedPaths.contains(path) || shouldPathBeSelectedDueToParent(path)) {
checkAndRemoveAnySelectedParents(path);
} else {
// TOOD: if it's a folder, remove all the children we added manually
selectedPaths.add(path);
}
filesSelectionDoneMenuItem.setVisible(selectedPaths.size() > 0);
}
@Override
public boolean isPathSelected(String path) {
return (selectedPaths.contains(path) || shouldPathBeSelectedDueToParent(path));
}
@Parcel
public enum BrowserType {
FILE_BROWSER,
DAV_BROWSER,
}
}

View File

@ -18,27 +18,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.utils;
package com.nextcloud.talk.components.filebrowser.interfaces;
import android.content.Context;
import android.util.AttributeSet;
import eu.davidea.flipview.FlipView;
import com.nextcloud.talk.components.filebrowser.models.DavResponse;
public class MagicFlipView extends FlipView {
public MagicFlipView(Context context) {
super(context);
}
public MagicFlipView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDetachedFromWindow() {
try {
super.onDetachedFromWindow();
} catch (IllegalArgumentException e) {
stopFlipping();
}
}
public interface ListingInterface {
void listingResult(DavResponse davResponse);
}

View File

@ -0,0 +1,106 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.components.filebrowser.models;
import android.net.Uri;
import android.text.TextUtils;
import at.bitfire.dav4android.Property;
import at.bitfire.dav4android.Response;
import at.bitfire.dav4android.property.DisplayName;
import at.bitfire.dav4android.property.GetContentType;
import at.bitfire.dav4android.property.GetLastModified;
import at.bitfire.dav4android.property.ResourceType;
import com.bluelinelabs.logansquare.annotation.JsonObject;
import com.nextcloud.talk.components.filebrowser.models.properties.*;
import lombok.Data;
import org.parceler.Parcel;
import java.io.File;
import java.util.List;
@Data
@JsonObject
@Parcel
public class BrowserFile {
public String path;
public String displayName;
public String mimeType;
public long modifiedTimestamp;
public long size;
public boolean isFile;
// Used for remote files
public String remoteId;
public boolean hasPreview;
public boolean favorite;
public boolean encrypted;
public static BrowserFile getModelFromResponse(Response response, String remotePath) {
BrowserFile browserFile = new BrowserFile();
browserFile.setPath(Uri.decode(remotePath));
browserFile.setDisplayName(Uri.decode(new File(remotePath).getName()));
final List<Property> properties = response.getProperties();
for (Property property : properties) {
if (property instanceof OCId) {
browserFile.setRemoteId(((OCId) property).getOcId());
}
if (property instanceof ResourceType) {
browserFile.isFile =
!(((ResourceType) property).getTypes().contains(ResourceType.Companion.getCOLLECTION()));
}
if (property instanceof GetLastModified) {
browserFile.setModifiedTimestamp(((GetLastModified) property).getLastModified());
}
if (property instanceof GetContentType) {
browserFile.setMimeType(((GetContentType) property).getType());
}
if (property instanceof OCSize) {
browserFile.setSize(((OCSize) property).getOcSize());
}
if (property instanceof NCPreview) {
browserFile.setHasPreview(((NCPreview) property).isNcPreview());
}
if (property instanceof OCFavorite) {
browserFile.setFavorite(((OCFavorite) property).isOcFavorite());
}
if (property instanceof DisplayName) {
browserFile.setDisplayName(((DisplayName) property).getDisplayName());
}
if (property instanceof NCEncrypted) {
browserFile.setEncrypted(((NCEncrypted) property).isNcEncrypted());
}
}
if (TextUtils.isEmpty(browserFile.getMimeType()) && !browserFile.isFile()) {
browserFile.setMimeType("inode/directory");
}
return browserFile;
}
}

View File

@ -0,0 +1,30 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.components.filebrowser.models;
import at.bitfire.dav4android.Response;
import lombok.Data;
@Data
public class DavResponse {
Response response;
Object data;
}

View File

@ -0,0 +1,73 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.components.filebrowser.models.properties;
import android.text.TextUtils;
import at.bitfire.dav4android.Property;
import at.bitfire.dav4android.PropertyFactory;
import at.bitfire.dav4android.XmlUtils;
import com.nextcloud.talk.components.filebrowser.webdav.DavUtils;
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
public class NCEncrypted implements Property {
public static final Name NAME = new Name(DavUtils.NC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_IS_ENCRYPTED);
@Getter
@Setter
private boolean ncEncrypted;
private NCEncrypted(boolean isEncrypted) {
ncEncrypted = isEncrypted;
}
public static class Factory implements PropertyFactory {
@Nullable
@Override
public Property create(@NotNull XmlPullParser xmlPullParser) {
try {
String text = XmlUtils.INSTANCE.readText(xmlPullParser);
if (!TextUtils.isEmpty(text)) {
return new NCEncrypted(Boolean.parseBoolean(text));
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return new NCEncrypted(false);
}
@NotNull
@Override
public Name getName() {
return NAME;
}
}
}

View File

@ -0,0 +1,73 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.components.filebrowser.models.properties;
import android.text.TextUtils;
import at.bitfire.dav4android.Property;
import at.bitfire.dav4android.PropertyFactory;
import at.bitfire.dav4android.XmlUtils;
import com.nextcloud.talk.components.filebrowser.webdav.DavUtils;
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
public class NCPreview implements Property {
public static final Property.Name NAME = new Property.Name(DavUtils.NC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_HAS_PREVIEW);
@Getter
@Setter
private boolean ncPreview;
private NCPreview(boolean hasPreview) {
ncPreview = hasPreview;
}
public static class Factory implements PropertyFactory {
@Nullable
@Override
public Property create(@NotNull XmlPullParser xmlPullParser) {
try {
String text = XmlUtils.INSTANCE.readText(xmlPullParser);
if (!TextUtils.isEmpty(text)) {
return new NCPreview(Boolean.parseBoolean(text));
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return new OCFavorite(false);
}
@NotNull
@Override
public Property.Name getName() {
return NAME;
}
}
}

View File

@ -0,0 +1,73 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.components.filebrowser.models.properties;
import android.text.TextUtils;
import at.bitfire.dav4android.Property;
import at.bitfire.dav4android.PropertyFactory;
import at.bitfire.dav4android.XmlUtils;
import com.nextcloud.talk.components.filebrowser.webdav.DavUtils;
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
public class OCFavorite implements Property {
public static final Property.Name NAME = new Property.Name(DavUtils.OC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_FAVORITE);
@Getter
@Setter
private boolean ocFavorite;
OCFavorite(boolean isFavorite) {
ocFavorite = isFavorite;
}
public static class Factory implements PropertyFactory {
@Nullable
@Override
public Property create(@NotNull XmlPullParser xmlPullParser) {
try {
String text = XmlUtils.INSTANCE.readText(xmlPullParser);
if (!TextUtils.isEmpty(text)) {
return new OCFavorite(Boolean.parseBoolean(text));
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return new OCFavorite(false);
}
@NotNull
@Override
public Property.Name getName() {
return NAME;
}
}
}

View File

@ -0,0 +1,73 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.components.filebrowser.models.properties;
import android.text.TextUtils;
import at.bitfire.dav4android.Property;
import at.bitfire.dav4android.PropertyFactory;
import at.bitfire.dav4android.XmlUtils;
import com.nextcloud.talk.components.filebrowser.webdav.DavUtils;
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
public class OCId implements Property {
public static final Name NAME = new Name(DavUtils.OC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_NAME_REMOTE_ID);
@Getter
@Setter
private String ocId;
private OCId(String id) {
ocId = id;
}
public static class Factory implements PropertyFactory {
@Nullable
@Override
public Property create(@NotNull XmlPullParser xmlPullParser) {
try {
String text = XmlUtils.INSTANCE.readText(xmlPullParser);
if (!TextUtils.isEmpty(text)) {
return new OCId(text);
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return new OCId("");
}
@NotNull
@Override
public Name getName() {
return NAME;
}
}
}

View File

@ -0,0 +1,73 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.components.filebrowser.models.properties;
import android.text.TextUtils;
import at.bitfire.dav4android.Property;
import at.bitfire.dav4android.PropertyFactory;
import at.bitfire.dav4android.XmlUtils;
import com.nextcloud.talk.components.filebrowser.webdav.DavUtils;
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
public class OCSize implements Property {
public static final Property.Name NAME = new Property.Name(DavUtils.OC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_NAME_SIZE);
@Getter
@Setter
private long ocSize;
private OCSize(long size) {
ocSize = size;
}
public static class Factory implements PropertyFactory {
@Nullable
@Override
public Property create(@NotNull XmlPullParser xmlPullParser) {
try {
String text = XmlUtils.INSTANCE.readText(xmlPullParser);
if (!TextUtils.isEmpty(text)) {
return new OCSize(Long.parseLong(text));
}
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return new OCSize(-1);
}
@NotNull
@Override
public Name getName() {
return NAME;
}
}
}

View File

@ -0,0 +1,69 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.components.filebrowser.operations;
import androidx.annotation.Nullable;
import com.nextcloud.talk.components.filebrowser.interfaces.ListingInterface;
import com.nextcloud.talk.components.filebrowser.models.DavResponse;
import com.nextcloud.talk.components.filebrowser.webdav.ReadFilesystemOperation;
import com.nextcloud.talk.models.database.UserEntity;
import io.reactivex.Single;
import io.reactivex.SingleObserver;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.OkHttpClient;
import java.util.concurrent.Callable;
public class DavListing extends ListingAbstractClass {
private DavResponse davResponse = new DavResponse();
public DavListing(ListingInterface listingInterface) {
super(listingInterface);
}
@Override
public void getFiles(String path, UserEntity currentUser, @Nullable OkHttpClient okHttpClient) {
Single.fromCallable(new Callable<ReadFilesystemOperation>() {
@Override
public ReadFilesystemOperation call() {
return new ReadFilesystemOperation(okHttpClient, currentUser, path, 1);
}
}).subscribeOn(Schedulers.newThread())
.subscribe(new SingleObserver<ReadFilesystemOperation>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onSuccess(ReadFilesystemOperation readFilesystemOperation) {
davResponse = readFilesystemOperation.readRemotePath();
listingInterface.listingResult(davResponse);
}
@Override
public void onError(Throwable e) {
listingInterface.listingResult(davResponse);
}
});
}
}

View File

@ -0,0 +1,48 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.components.filebrowser.operations;
import android.os.Handler;
import androidx.annotation.Nullable;
import com.nextcloud.talk.components.filebrowser.interfaces.ListingInterface;
import com.nextcloud.talk.models.database.UserEntity;
import okhttp3.OkHttpClient;
public abstract class ListingAbstractClass {
Handler handler;
ListingInterface listingInterface;
ListingAbstractClass(ListingInterface listingInterface) {
handler = new Handler();
this.listingInterface = listingInterface;
}
public abstract void getFiles(String path, UserEntity currentUser, @Nullable OkHttpClient okHttpClient);
public void cancelAllJobs() {
handler.removeCallbacksAndMessages(null);
}
public void tearDown() {
cancelAllJobs();
handler = null;
}
}

View File

@ -0,0 +1,110 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.components.filebrowser.webdav;
import at.bitfire.dav4android.Property;
import at.bitfire.dav4android.PropertyFactory;
import at.bitfire.dav4android.PropertyRegistry;
import at.bitfire.dav4android.property.*;
import com.nextcloud.talk.components.filebrowser.models.properties.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DavUtils {
public static final String OC_NAMESPACE = "http://owncloud.org/ns";
public static final String NC_NAMESPACE = "http://nextcloud.org/ns";
public static final String DAV_PATH = "/remote.php/dav/files/";
public static final String EXTENDED_PROPERTY_NAME_PERMISSIONS = "permissions";
public static final String EXTENDED_PROPERTY_NAME_REMOTE_ID = "id";
public static final String EXTENDED_PROPERTY_NAME_SIZE = "size";
public static final String EXTENDED_PROPERTY_FAVORITE = "favorite";
public static final String EXTENDED_PROPERTY_IS_ENCRYPTED = "is-encrypted";
public static final String EXTENDED_PROPERTY_MOUNT_TYPE = "mount-type";
public static final String EXTENDED_PROPERTY_OWNER_ID = "owner-id";
public static final String EXTENDED_PROPERTY_OWNER_DISPLAY_NAME = "owner-display-name";
public static final String EXTENDED_PROPERTY_UNREAD_COMMENTS = "comments-unread";
public static final String EXTENDED_PROPERTY_HAS_PREVIEW = "has-preview";
public static final String EXTENDED_PROPERTY_NOTE = "note";
public static final String TRASHBIN_FILENAME = "trashbin-filename";
public static final String TRASHBIN_ORIGINAL_LOCATION = "trashbin-original-location";
public static final String TRASHBIN_DELETION_TIME = "trashbin-deletion-time";
public static final String PROPERTY_QUOTA_USED_BYTES = "quota-used-bytes";
public static final String PROPERTY_QUOTA_AVAILABLE_BYTES = "quota-available-bytes";
static Property.Name[] getAllPropSet() {
List<Property.Name> propSet = new ArrayList<>();
propSet.add(DisplayName.NAME);
propSet.add(GetContentType.NAME);
propSet.add(GetContentLength.NAME);
propSet.add(GetContentType.NAME);
propSet.add(GetContentLength.NAME);
propSet.add(GetLastModified.NAME);
propSet.add(CreationDate.NAME);
propSet.add(GetETag.NAME);
propSet.add(ResourceType.NAME);
propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_NAME_PERMISSIONS));
propSet.add(OCId.NAME);
propSet.add(OCSize.NAME);
propSet.add(OCFavorite.NAME);
propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_OWNER_ID));
propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_OWNER_DISPLAY_NAME));
propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_UNREAD_COMMENTS));
propSet.add(NCEncrypted.NAME);
propSet.add(new Property.Name(NC_NAMESPACE, EXTENDED_PROPERTY_MOUNT_TYPE));
propSet.add(NCPreview.NAME);
propSet.add(new Property.Name(NC_NAMESPACE, EXTENDED_PROPERTY_NOTE));
return propSet.toArray(new Property.Name[0]);
}
public static void registerCustomFactories() {
PropertyRegistry propertyRegistry = PropertyRegistry.INSTANCE;
try {
Field factories = propertyRegistry.getClass().getDeclaredField("factories");
factories.setAccessible(true);
Map<Property.Name, PropertyFactory> reflectionMap = (HashMap<Property.Name,
PropertyFactory>) factories.get(propertyRegistry);
reflectionMap.put(OCId.NAME, new OCId.Factory());
reflectionMap.put(NCPreview.NAME, new NCPreview.Factory());
reflectionMap.put(NCEncrypted.NAME, new NCEncrypted.Factory());
reflectionMap.put(OCFavorite.NAME, new OCFavorite.Factory());
reflectionMap.put(OCSize.NAME, new OCSize.Factory());
factories.set(propertyRegistry, reflectionMap);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,100 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.components.filebrowser.webdav;
import at.bitfire.dav4android.DavResource;
import at.bitfire.dav4android.Response;
import at.bitfire.dav4android.exception.DavException;
import com.nextcloud.talk.components.filebrowser.models.BrowserFile;
import com.nextcloud.talk.components.filebrowser.models.DavResponse;
import com.nextcloud.talk.dagger.modules.RestModule;
import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.utils.ApiUtils;
import kotlin.Unit;
import kotlin.jvm.functions.Function2;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class ReadFilesystemOperation {
private final OkHttpClient okHttpClient;
private final String url;
private final String basePath;
private final int depth;
public ReadFilesystemOperation(OkHttpClient okHttpClient, UserEntity currentUser, String path, int depth) {
OkHttpClient.Builder okHttpClientBuilder = okHttpClient.newBuilder();
okHttpClientBuilder.followRedirects(false);
okHttpClientBuilder.followSslRedirects(false);
okHttpClientBuilder.authenticator(new RestModule.MagicAuthenticator(ApiUtils.getCredentials(currentUser.getUsername(), currentUser.getToken()), "Authorization"));
this.okHttpClient = okHttpClientBuilder.build();
basePath = currentUser.getBaseUrl() + DavUtils.DAV_PATH + currentUser.getUserId();
this.url = basePath + path;
this.depth = depth;
}
public DavResponse readRemotePath() {
DavResponse davResponse = new DavResponse();
final List<Response> memberElements = new ArrayList<>();
final Response[] rootElement = new Response[1];
final List<BrowserFile> remoteFiles = new ArrayList<>();
try {
new DavResource(okHttpClient, HttpUrl.parse(url)).propfind(depth, DavUtils.getAllPropSet(),
new Function2<Response, Response.HrefRelation, Unit>() {
@Override
public Unit invoke(Response response, Response.HrefRelation hrefRelation) {
davResponse.setResponse(response);
switch (hrefRelation) {
case MEMBER:
memberElements.add(response);
break;
case SELF:
rootElement[0] = response;
break;
case OTHER:
default:
}
return Unit.INSTANCE;
}
});
} catch (IOException e) {
e.printStackTrace();
} catch (DavException e) {
e.printStackTrace();
}
remoteFiles.add(BrowserFile.getModelFromResponse(rootElement[0],
rootElement[0].getHref().toString().substring(basePath.length())));
for (Response memberElement : memberElements) {
remoteFiles.add(BrowserFile.getModelFromResponse(memberElement,
memberElement.getHref().toString().substring(basePath.length())));
}
davResponse.setData(remoteFiles);
return davResponse;
}
}

View File

@ -44,9 +44,9 @@ import butterknife.BindView;
import butterknife.OnClick;
import butterknife.OnLongClick;
import com.bluelinelabs.logansquare.LoganSquare;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
import com.bumptech.glide.request.RequestOptions;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;
import com.nextcloud.talk.R;
import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication;
@ -65,18 +65,16 @@ import com.nextcloud.talk.models.json.signaling.*;
import com.nextcloud.talk.models.json.signaling.settings.IceServer;
import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.MagicFlipView;
import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.NotificationUtils;
import com.nextcloud.talk.utils.animations.PulseAnimation;
import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils;
import com.nextcloud.talk.utils.glide.GlideApp;
import com.nextcloud.talk.utils.power.PowerManagerUtils;
import com.nextcloud.talk.utils.preferences.AppPreferences;
import com.nextcloud.talk.utils.singletons.ApplicationWideCurrentRoomHolder;
import com.nextcloud.talk.webrtc.*;
import com.wooplr.spotlight.SpotlightView;
import eu.davidea.flipview.FlipView;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
@ -117,7 +115,7 @@ public class CallController extends BaseController {
};
@BindView(R.id.callControlEnableSpeaker)
MagicFlipView callControlEnableSpeaker;
SimpleDraweeView callControlEnableSpeaker;
@BindView(R.id.pip_video_view)
SurfaceViewRenderer pipVideoView;
@ -129,11 +127,11 @@ public class CallController extends BaseController {
@BindView(R.id.callControlsRelativeLayout)
RelativeLayout callControls;
@BindView(R.id.call_control_microphone)
FlipView microphoneControlButton;
SimpleDraweeView microphoneControlButton;
@BindView(R.id.call_control_camera)
FlipView cameraControlButton;
SimpleDraweeView cameraControlButton;
@BindView(R.id.call_control_switch_camera)
FlipView cameraSwitchButton;
SimpleDraweeView cameraSwitchButton;
@BindView(R.id.connectingTextView)
TextView connectingTextView;
@ -260,7 +258,7 @@ public class CallController extends BaseController {
microphoneControlButton.setOnTouchListener(new MicrophoneButtonTouchListener());
videoOnClickListener = new VideoClickListener();
pulseAnimation = PulseAnimation.create().with(microphoneControlButton.getFrontImageView())
pulseAnimation = PulseAnimation.create().with(microphoneControlButton)
.setDuration(310)
.setRepeatCount(PulseAnimation.INFINITE)
.setRepeatMode(PulseAnimation.REVERSE);
@ -454,7 +452,7 @@ public class CallController extends BaseController {
onCameraClick();
}
} else {
cameraControlButton.getFrontImageView().setImageResource(R.drawable.ic_videocam_off_white_24px);
cameraControlButton.setImageResource(R.drawable.ic_videocam_off_white_24px);
cameraControlButton.setAlpha(0.7f);
cameraSwitchButton.setVisibility(View.GONE);
}
@ -465,7 +463,7 @@ public class CallController extends BaseController {
onMicrophoneClick();
}
} else {
microphoneControlButton.getFrontImageView().setImageResource(R.drawable.ic_mic_off_white_24px);
microphoneControlButton.setImageResource(R.drawable.ic_mic_off_white_24px);
}
if (!inCall) {
@ -584,7 +582,7 @@ public class CallController extends BaseController {
public void onEnableSpeakerphoneClick() {
if (audioManager != null) {
audioManager.toggleUseSpeakerphone();
callControlEnableSpeaker.flipSilently(!callControlEnableSpeaker.isFlipped());
//callControlEnableSpeaker.flipSilently(!callControlEnableSpeaker.isFlipped());
}
}
@ -620,14 +618,14 @@ public class CallController extends BaseController {
audioOn = !audioOn;
if (audioOn) {
microphoneControlButton.getFrontImageView().setImageResource(R.drawable.ic_mic_white_24px);
microphoneControlButton.setActualImageResource(R.drawable.ic_mic_white_24px);
} else {
microphoneControlButton.getFrontImageView().setImageResource(R.drawable.ic_mic_off_white_24px);
microphoneControlButton.setActualImageResource(R.drawable.ic_mic_off_white_24px);
}
toggleMedia(audioOn, false);
} else {
microphoneControlButton.getFrontImageView().setImageResource(R.drawable.ic_mic_white_24px);
microphoneControlButton.setActualImageResource(R.drawable.ic_mic_white_24px);
pulseAnimation.start();
toggleMedia(true, false);
}
@ -663,12 +661,12 @@ public class CallController extends BaseController {
videoOn = !videoOn;
if (videoOn) {
cameraControlButton.getFrontImageView().setImageResource(R.drawable.ic_videocam_white_24px);
cameraControlButton.setActualImageResource(R.drawable.ic_videocam_white_24px);
if (cameraEnumerator.getDeviceNames().length > 1) {
cameraSwitchButton.setVisibility(View.VISIBLE);
}
} else {
cameraControlButton.getFrontImageView().setImageResource(R.drawable.ic_videocam_off_white_24px);
cameraControlButton.setActualImageResource(R.drawable.ic_videocam_off_white_24px);
cameraSwitchButton.setVisibility(View.GONE);
}
@ -1792,21 +1790,19 @@ public class CallController extends BaseController {
if (remoteRenderersLayout != null) {
RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(session + "+video");
if (relativeLayout != null) {
ImageView avatarImageView = relativeLayout.findViewById(R.id.avatarImageView);
SimpleDraweeView avatarImageView = relativeLayout.findViewById(R.id.avatarImageView);
if (participantMap.containsKey(session) && avatarImageView.getDrawable() == null) {
int size = Math.round(getResources().getDimension(R.dimen.avatar_size_big));
if (getActivity() != null) {
GlideApp.with(getActivity())
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.load(ApiUtils.getUrlForAvatarWithName(baseUrl, participantMap.get(session).getUserId(), R.dimen.avatar_size_big))
.centerInside()
.override(size, size)
.apply(RequestOptions.bitmapTransform(new CircleCrop()))
.into(avatarImageView);
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(avatarImageView.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(baseUrl,
participantMap.get(session).getUserId(),
R.dimen.avatar_size_big), null))
.build();
avatarImageView.setController(draweeController);
}
}
}
@ -1822,7 +1818,7 @@ public class CallController extends BaseController {
RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(session + "+" + videoStreamType);
SurfaceViewRenderer surfaceViewRenderer = relativeLayout.findViewById(R.id.surface_view);
ImageView imageView = relativeLayout.findViewById(R.id.avatarImageView);
SimpleDraweeView imageView = relativeLayout.findViewById(R.id.avatarImageView);
if (mediaStream != null && mediaStream.videoTracks != null && mediaStream.videoTracks.size() > 0 && enable) {
VideoTrack videoTrack = mediaStream.videoTracks.get(0);
@ -1847,7 +1843,7 @@ public class CallController extends BaseController {
RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(sessionId);
if (relativeLayout != null) {
ImageView imageView;
ImageView avatarImageView = relativeLayout.findViewById(R.id.avatarImageView);
SimpleDraweeView avatarImageView = relativeLayout.findViewById(R.id.avatarImageView);
SurfaceViewRenderer surfaceViewRenderer = relativeLayout.findViewById(R.id.surface_view);
if (video) {
@ -1942,7 +1938,7 @@ public class CallController extends BaseController {
v.onTouchEvent(event);
if (event.getAction() == MotionEvent.ACTION_UP && isPTTActive) {
isPTTActive = false;
microphoneControlButton.getFrontImageView().setImageResource(R.drawable.ic_mic_off_white_24px);
microphoneControlButton.setActualImageResource(R.drawable.ic_mic_off_white_24px);
pulseAnimation.stop();
toggleMedia(false, false);
animateCallControls(false, 5000);

View File

@ -30,10 +30,7 @@ import android.media.AudioAttributes;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.*;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
@ -50,14 +47,16 @@ import butterknife.OnClick;
import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.bluelinelabs.logansquare.LoganSquare;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.LazyHeaders;
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
import com.bumptech.glide.load.resource.bitmap.TransformationUtils;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
import com.facebook.common.executors.UiThreadImmediateExecutorService;
import com.facebook.common.references.CloseableReference;
import com.facebook.datasource.DataSource;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.view.SimpleDraweeView;
import com.facebook.imagepipeline.core.ImagePipeline;
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.postprocessors.BlurPostProcessor;
import com.facebook.imagepipeline.request.ImageRequest;
import com.nextcloud.talk.R;
import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication;
@ -70,10 +69,9 @@ import com.nextcloud.talk.models.json.participants.ParticipantsOverall;
import com.nextcloud.talk.models.json.rooms.Conversation;
import com.nextcloud.talk.models.json.rooms.RoomsOverall;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.DisplayUtils;
import com.nextcloud.talk.utils.DoNotDisturbUtils;
import com.nextcloud.talk.utils.MagicFlipView;
import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.glide.GlideApp;
import com.nextcloud.talk.utils.preferences.AppPreferences;
import com.nextcloud.talk.utils.singletons.AvatarStatusCodeHolder;
import io.reactivex.Observer;
@ -87,6 +85,7 @@ import org.greenrobot.eventbus.ThreadMode;
import org.michaelevans.colorart.library.ColorArt;
import org.parceler.Parcels;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.io.IOException;
import java.util.ArrayList;
@ -113,13 +112,13 @@ public class CallNotificationController extends BaseController {
TextView conversationNameTextView;
@BindView(R.id.avatarImageView)
ImageView avatarImageView;
SimpleDraweeView avatarImageView;
@BindView(R.id.callAnswerVoiceOnlyView)
MagicFlipView callAnswerVoiceOnlyView;
SimpleDraweeView callAnswerVoiceOnlyView;
@BindView(R.id.callAnswerCameraView)
MagicFlipView callAnswerCameraView;
SimpleDraweeView callAnswerCameraView;
@BindView(R.id.backgroundImageView)
ImageView backgroundImageView;
@ -148,7 +147,6 @@ public class CallNotificationController extends BaseController {
this.userBeingCalled = args.getParcelable(BundleKeys.KEY_USER_ENTITY);
this.originalBundle = args;
credentials = ApiUtils.getCredentials(userBeingCalled.getUsername(), userBeingCalled.getToken());
}
@ -384,7 +382,6 @@ public class CallNotificationController extends BaseController {
layoutParams.width = dimen;
layoutParams.height = dimen;
avatarImageView.setLayoutParams(layoutParams);
}
@ -402,54 +399,37 @@ public class CallNotificationController extends BaseController {
}
private void loadAvatar() {
int avatarSize = Math.round(NextcloudTalkApplication
.getSharedApplication().getResources().getDimension(R.dimen.avatar_fetching_size_very_big));
switch (currentConversation.getType()) {
case ROOM_TYPE_ONE_TO_ONE_CALL:
avatarImageView.setVisibility(View.VISIBLE);
GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userBeingCalled.getBaseUrl(),
currentConversation.getName(), R.dimen.avatar_size_very_big), new LazyHeaders.Builder()
.setHeader("Accept", "image/*")
.setHeader("User-Agent", ApiUtils.getUserAgent())
.build());
ImageRequest imageRequest =
DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userBeingCalled.getBaseUrl(),
currentConversation.getName(), R.dimen.avatar_size_very_big), null);
GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.load(glideUrl)
.centerInside()
.override(avatarSize, avatarSize)
.into(new SimpleTarget<Bitmap>() {
ImagePipeline imagePipeline = Fresco.getImagePipeline();
DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, null);
dataSource.subscribe(new BaseBitmapDataSubscriber() {
@Override
public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
if (getActivity() != null && avatarImageView != null) {
avatarImageView.setImageBitmap(TransformationUtils.circleCrop(GlideApp.get
(getActivity()).getBitmapPool(), resource, avatarSize, avatarSize));
}
protected void onNewResultImpl(@Nullable Bitmap bitmap) {
avatarImageView.getHierarchy().setImage(new BitmapDrawable(bitmap), 100,
true);
if (getResources() != null && incomingTextRelativeLayout != null) {
if (getResources() != null) {
incomingTextRelativeLayout.setBackground(getResources().getDrawable(R.drawable
.incoming_gradient));
}
if (AvatarStatusCodeHolder.getInstance().getStatusCode() == 200 &&
userBeingCalled.hasSpreedCapabilityWithName("no-ping")) {
final Allocation input = Allocation.createFromBitmap(renderScript, resource);
final Allocation output = Allocation.createTyped(renderScript, input.getType());
final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(renderScript, Element
.U8_4(renderScript));
script.setRadius(15f);
script.setInput(input);
script.forEach(output);
output.copyTo(resource);
if (backgroundImageView != null) {
backgroundImageView.setImageDrawable(new BitmapDrawable(resource));
if (getActivity() != null) {
Bitmap backgroundBitmap = bitmap.copy(bitmap.getConfig(), true);
new BlurPostProcessor(5, getActivity()).process(backgroundBitmap);
backgroundImageView.setImageDrawable(new BitmapDrawable(backgroundBitmap));
}
} else if (AvatarStatusCodeHolder.getInstance().getStatusCode() == 201) {
ColorArt colorArt = new ColorArt(resource);
ColorArt colorArt = new ColorArt(bitmap);
int color = colorArt.getBackgroundColor();
float[] hsv = new float[3];
@ -457,37 +437,21 @@ public class CallNotificationController extends BaseController {
hsv[2] *= 0.75f;
color = Color.HSVToColor(hsv);
if (backgroundImageView != null) {
backgroundImageView.setImageDrawable(new ColorDrawable(color));
}
}
}
});
@Override
protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
}
}, UiThreadImmediateExecutorService.getInstance());
break;
case ROOM_GROUP_CALL:
if (avatarImageView != null) {
GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.load(R.drawable.ic_people_group_white_24px)
.centerInside()
.override(avatarSize, avatarSize)
.apply(RequestOptions.bitmapTransform(new CircleCrop()))
.into(avatarImageView);
}
avatarImageView.setActualImageResource(R.drawable.ic_people_group_white_24px);
case ROOM_PUBLIC_CALL:
if (avatarImageView != null) {
GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.load(R.drawable.ic_link_white_24px)
.centerInside()
.override(avatarSize, avatarSize)
.apply(RequestOptions.bitmapTransform(new CircleCrop()))
.into(avatarImageView);
}
avatarImageView.setActualImageResource(R.drawable.ic_link_white_24px);
break;
default:
}

View File

@ -46,6 +46,7 @@ import butterknife.BindView;
import butterknife.OnClick;
import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;
@ -58,6 +59,7 @@ import com.nextcloud.talk.adapters.messages.MagicSystemMessageViewHolder;
import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.callbacks.MentionAutocompleteCallback;
import com.nextcloud.talk.components.filebrowser.controllers.BrowserController;
import com.nextcloud.talk.controllers.base.BaseController;
import com.nextcloud.talk.events.UserMentionClickEvent;
import com.nextcloud.talk.models.RetrofitBucket;
@ -318,7 +320,7 @@ public class ChatController extends BaseController implements MessagesListAdapte
@Override
public void loadImage(SimpleDraweeView imageView, String url) {
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setImageRequest(DisplayUtils.getImageRequestForUrl(url))
.setImageRequest(DisplayUtils.getImageRequestForUrl(url, conversationUser))
.setControllerListener(DisplayUtils.getImageControllerListener(imageView))
.setOldController(imageView.getController())
.setAutoPlayAnimations(true)
@ -415,6 +417,13 @@ public class ChatController extends BaseController implements MessagesListAdapte
}
});
messageInputView.setAttachmentsListener(new MessageInput.AttachmentsListener() {
@Override
public void onAddAttachments() {
showBrowserScreen(BrowserController.BrowserType.DAV_BROWSER);
}
});
messageInputView.getButton().setOnClickListener(v -> submitMessage());
messageInputView.getButton().setContentDescription(getResources()
.getString(R.string.nc_description_send_message_button));
@ -479,6 +488,16 @@ public class ChatController extends BaseController implements MessagesListAdapte
}
private void showBrowserScreen(BrowserController.BrowserType browserType) {
Bundle bundle = new Bundle();
bundle.putParcelable(BundleKeys.KEY_BROWSER_TYPE, Parcels.wrap(browserType));
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, Parcels.wrap(conversationUser));
bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken);
getRouter().pushController((RouterTransaction.with(new BrowserController(bundle))
.pushChangeHandler(new VerticalChangeHandler())
.popChangeHandler(new VerticalChangeHandler())));
}
private void showConversationInfoScreen() {
Bundle bundle = new Bundle();
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, conversationUser);
@ -486,7 +505,6 @@ public class ChatController extends BaseController implements MessagesListAdapte
getRouter().pushController((RouterTransaction.with(new ConversationInfoController(bundle))
.pushChangeHandler(new HorizontalChangeHandler())
.popChangeHandler(new HorizontalChangeHandler())));
}
private void setupMentionAutocomplete() {
@ -532,7 +550,8 @@ public class ChatController extends BaseController implements MessagesListAdapte
@Override
public void onEmojiPopupDismiss() {
if (smileyButton != null) {
smileyButton.clearColorFilter();
smileyButton.setColorFilter(getResources().getColor(R.color.emoji_icons),
PorterDuff.Mode.SRC_IN);
}
}
}).setOnEmojiClickListener(new OnEmojiClickListener() {
@ -950,8 +969,8 @@ public class ChatController extends BaseController implements MessagesListAdapte
ChatMessage chatMessage = chatMessageList.get(i);
chatMessage.setLinkPreviewAllowed(isLinkPreviewAllowed);
chatMessage.setBaseUrl(conversationUser.getBaseUrl());
chatMessage.setActiveUserId(conversationUser.getUserId());
chatMessage.setActiveUser(conversationUser);
if (globalLastKnownPastMessageId == -1 || chatMessageList.get(i).getJsonMessageId() <
globalLastKnownPastMessageId) {
globalLastKnownPastMessageId = chatMessageList.get(i).getJsonMessageId();
@ -975,8 +994,7 @@ public class ChatController extends BaseController implements MessagesListAdapte
for (int i = 0; i < chatMessageList.size(); i++) {
chatMessage = chatMessageList.get(i);
chatMessage.setBaseUrl(conversationUser.getBaseUrl());
chatMessage.setActiveUserId(conversationUser.getUserId());
chatMessage.setActiveUser(conversationUser);
chatMessage.setLinkPreviewAllowed(isLinkPreviewAllowed);
// if credentials are empty, we're acting as a guest

View File

@ -80,7 +80,6 @@ import eu.davidea.flexibleadapter.SelectableAdapter;
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager;
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
import eu.davidea.flexibleadapter.items.IFlexible;
import eu.davidea.flipview.FlipView;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
@ -190,7 +189,6 @@ public class ContactsController extends BaseController implements SearchView.OnQ
if (isNewConversationView) {
toggleNewCallHeaderVisibility(!isPublicCall);
}
}
@Override
@ -198,9 +196,6 @@ public class ContactsController extends BaseController implements SearchView.OnQ
super.onViewBound(view);
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
FlipView.resetLayoutAnimationDelay(true, 1000L);
FlipView.stopLayoutAnimation();
currentUser = userUtils.getCurrentUser();
if (currentUser != null) {
@ -208,7 +203,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ
}
if (adapter == null) {
adapter = new FlexibleAdapter<>(contactItems, getActivity(), false);
adapter = new FlexibleAdapter<>(contactItems, getActivity(), true);
if (currentUser != null) {
fetchData(true);
@ -598,6 +593,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ
});
adapter.clearSelection();
if (!shouldFilterManually) {
adapter.updateDataSet(newUserItemList, false);
} else {
@ -660,7 +656,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ
private void prepareViews() {
layoutManager = new SmoothScrollLinearLayoutManager(getActivity());
recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(getActivity()));
recyclerView.setLayoutManager(layoutManager);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
@ -911,7 +907,6 @@ public class ContactsController extends BaseController implements SearchView.OnQ
}
});
} else {
((UserItem) adapter.getItem(position)).flipItemSelection();
adapter.toggleSelection(position);
if (currentUser.hasSpreedCapabilityWithName("last-room-activity")
@ -921,13 +916,14 @@ public class ContactsController extends BaseController implements SearchView.OnQ
List<Integer> selectedPositions = adapter.getSelectedPositions();
for (int i = 0; i < selectedPositions.size(); i++) {
if (!selectedPositions.get(i).equals(position) && "groups".equals(((UserItem) adapter.getItem(selectedPositions.get(i))).getModel().getSource())) {
((UserItem) adapter.getItem(selectedPositions.get(i))).flipItemSelection();
adapter.toggleSelection(selectedPositions.get(i));
}
}
}
adapter.notifyDataSetChanged();
checkAndHandleDoneMenuItem();
}
}
@ -955,7 +951,6 @@ public class ContactsController extends BaseController implements SearchView.OnQ
if (adapter.getItem(selectedPosition) instanceof UserItem) {
UserItem userItem = (UserItem) adapter.getItem(selectedPosition);
if ("groups".equals(userItem.getModel().getSource())) {
((UserItem) adapter.getItem(selectedPosition)).flipItemSelection();
adapter.toggleSelection(selectedPosition);
}
}

View File

@ -473,7 +473,7 @@ public class ConversationInfoController extends BaseController {
.setOldController(conversationAvatarImageView.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(conversationUser.getBaseUrl(),
conversation.getName(), R.dimen.avatar_size_big)))
conversation.getName(), R.dimen.avatar_size_big), null))
.build();
conversationAvatarImageView.setController(draweeController);
}

View File

@ -38,7 +38,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SearchView;
import androidx.core.view.MenuItemCompat;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.work.Data;
@ -51,12 +50,15 @@ import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.bluelinelabs.conductor.changehandler.TransitionChangeHandlerCompat;
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
import com.bluelinelabs.conductor.internal.NoOpControllerChangeHandler;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.LazyHeaders;
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
import com.facebook.common.executors.UiThreadImmediateExecutorService;
import com.facebook.common.references.CloseableReference;
import com.facebook.datasource.DataSource;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.imagepipeline.core.ImagePipeline;
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.postprocessors.RoundPostprocessor;
import com.facebook.imagepipeline.request.ImageRequest;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.kennyc.bottomsheet.BottomSheet;
import com.nextcloud.talk.R;
@ -82,7 +84,6 @@ import com.nextcloud.talk.utils.KeyboardUtils;
import com.nextcloud.talk.utils.animations.SharedElementTransition;
import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils;
import com.nextcloud.talk.utils.glide.GlideApp;
import com.nextcloud.talk.utils.preferences.AppPreferences;
import com.yarolegovich.lovelydialog.LovelySaveStateHandler;
import com.yarolegovich.lovelydialog.LovelyStandardDialog;
@ -111,10 +112,8 @@ public class ConversationsListController extends BaseController implements Searc
.OnScrollStateChangeListener, ConversationMenuInterface {
public static final String TAG = "ConversationsListController";
private static final String KEY_SEARCH_QUERY = "ContactsController.searchQuery";
public static final int ID_DELETE_CONVERSATION_DIALOG = 0;
private static final String KEY_SEARCH_QUERY = "ContactsController.searchQuery";
@Inject
UserUtils userUtils;
@ -207,27 +206,25 @@ public class ConversationsListController extends BaseController implements Searc
private void loadUserAvatar(MenuItem menuItem) {
if (getActivity() != null) {
int avatarSize = (int) DisplayUtils.convertDpToPixel(menuItem.getIcon().getIntrinsicHeight(), getActivity());
ImageRequest imageRequest = DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithNameAndPixels(currentUser.getBaseUrl(),
currentUser.getUserId(), avatarSize), null);
if (currentUser != null) {
GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithNameAndPixels(currentUser.getBaseUrl(),
currentUser.getUserId(), avatarSize), new LazyHeaders.Builder()
.setHeader("Accept", "image/*")
.setHeader("User-Agent", ApiUtils.getUserAgent())
.build());
GlideApp.with(getActivity())
.asBitmap()
.centerInside()
.override(avatarSize, avatarSize)
.apply(RequestOptions.bitmapTransform(new CircleCrop()))
.load(glideUrl)
.into(new SimpleTarget<Bitmap>() {
ImagePipeline imagePipeline = Fresco.getImagePipeline();
DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, null);
dataSource.subscribe(new BaseBitmapDataSubscriber() {
@Override
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
menuItem.setIcon(new BitmapDrawable(resource));
protected void onNewResultImpl(Bitmap bitmap) {
if (bitmap != null) {
new RoundPostprocessor(true).process(bitmap);
menuItem.setIcon(new BitmapDrawable(bitmap));
}
});
}
@Override
protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
menuItem.setIcon(R.drawable.ic_settings_white_24dp);
}
}, UiThreadImmediateExecutorService.getInstance());
}
}
@ -434,11 +431,6 @@ public class ConversationsListController extends BaseController implements Searc
recyclerView.setAdapter(adapter);
recyclerView.addItemDecoration(new DividerItemDecoration(
recyclerView.getContext(),
layoutManager.getOrientation()
));
swipeRefreshLayout.setOnRefreshListener(() -> fetchData(false));
swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);

View File

@ -154,7 +154,7 @@ public class LockedController extends BaseController {
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS ) {
if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS) {
if (resultCode == Activity.RESULT_OK) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (SecurityUtils.checkIfWeAreAuthenticated(appPreferences.getScreenLockTimeout())) {

View File

@ -21,6 +21,7 @@
package com.nextcloud.talk.controllers;
import android.annotation.SuppressLint;
import android.content.Context;
import android.database.Cursor;
import android.media.MediaPlayer;
import android.media.RingtoneManager;
@ -70,10 +71,14 @@ public class RingtoneSelectionController extends BaseController implements Flexi
@Inject
AppPreferences appPreferences;
@Inject
Context context;
private FlexibleAdapter adapter;
private RecyclerView.AdapterDataObserver adapterDataObserver;
private List<AbstractFlexibleItem> abstractFlexibleItemList = new ArrayList<>();
private boolean callNotificationSounds = false;
private boolean callNotificationSounds;
private MediaPlayer mediaPlayer;
private Handler cancelMediaPlayerHandler;
@ -100,21 +105,20 @@ public class RingtoneSelectionController extends BaseController implements Flexi
.setMode(SelectableAdapter.Mode.SINGLE);
adapter.addListener(this);
fetchNotificationSounds();
cancelMediaPlayerHandler = new Handler();
}
adapter.addListener(this);
prepareViews();
fetchNotificationSounds();
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
getRouter().popCurrentController();
return true;
return getRouter().popCurrentController();
default:
return super.onOptionsItemSelected(item);
}
@ -126,38 +130,72 @@ public class RingtoneSelectionController extends BaseController implements Flexi
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
adapterDataObserver = new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
super.onChanged();
findSelectedSound();
}
};
adapter.registerAdapterDataObserver(adapterDataObserver);
swipeRefreshLayout.setEnabled(false);
}
@SuppressLint("LongLogTag")
private void fetchNotificationSounds() {
abstractFlexibleItemList = new ArrayList<>();
abstractFlexibleItemList.add(new NotificationSoundItem(getResources().getString(R.string.nc_settings_no_ringtone),
null));
String ringtoneString;
if (callNotificationSounds) {
ringtoneString = "android.resource://" + getApplicationContext().getPackageName() +
"/raw/librem_by_feandesign_call";
} else {
ringtoneString = "android.resource://" + getApplicationContext().getPackageName() +
"/raw/librem_by_feandesign_message";
}
abstractFlexibleItemList.add(new NotificationSoundItem(getResources()
.getString(R.string.nc_settings_default_ringtone), ringtoneString));
private void findSelectedSound() {
boolean foundDefault = false;
String preferencesString = null;
if ((callNotificationSounds && TextUtils.isEmpty((preferencesString = appPreferences.getCallRingtoneUri())))
|| (!callNotificationSounds && TextUtils.isEmpty((preferencesString = appPreferences
.getMessageRingtoneUri())))) {
((NotificationSoundItem) abstractFlexibleItemList.get(1)).setSelected(true);
adapter.toggleSelection(1);
foundDefault = true;
}
if (!TextUtils.isEmpty(preferencesString) && !foundDefault) {
try {
RingtoneSettings ringtoneSettings = LoganSquare.parse(preferencesString, RingtoneSettings.class);
if (ringtoneSettings.getRingtoneUri() == null) {
adapter.toggleSelection(0);
} else if (ringtoneSettings.getRingtoneUri().toString().equals(getRingtoneString())) {
adapter.toggleSelection(1);
} else {
NotificationSoundItem notificationSoundItem;
for (int i = 2; i < adapter.getItemCount(); i++) {
notificationSoundItem = (NotificationSoundItem) adapter.getItem(i);
if (notificationSoundItem.getNotificationSoundUri().equals(ringtoneSettings.getRingtoneUri().toString())) {
adapter.toggleSelection(i);
break;
}
}
}
} catch (IOException e) {
Log.e(TAG, "Failed to parse ringtone settings");
}
}
adapter.unregisterAdapterDataObserver(adapterDataObserver);
adapterDataObserver = null;
}
private String getRingtoneString() {
if (callNotificationSounds) {
return ("android.resource://" + context.getPackageName() +
"/raw/librem_by_feandesign_call");
} else {
return ("android.resource://" + context.getPackageName() + "/raw" +
"/librem_by_feandesign_message");
}
}
private void fetchNotificationSounds() {
abstractFlexibleItemList.add(new NotificationSoundItem(getResources().getString(R.string.nc_settings_no_ringtone), null));
abstractFlexibleItemList.add(new NotificationSoundItem(getResources()
.getString(R.string.nc_settings_default_ringtone), getRingtoneString()));
if (getActivity() != null) {
RingtoneManager manager = new RingtoneManager(getActivity());
@ -181,29 +219,10 @@ public class RingtoneSelectionController extends BaseController implements Flexi
notificationSoundItem = new NotificationSoundItem(notificationTitle, completeNotificationUri);
abstractFlexibleItemList.add(notificationSoundItem);
if (!TextUtils.isEmpty(preferencesString) && !foundDefault) {
try {
RingtoneSettings ringtoneSettings = LoganSquare.parse(preferencesString, RingtoneSettings.class);
if (ringtoneSettings.getRingtoneUri() == null) {
((NotificationSoundItem) abstractFlexibleItemList.get(0)).setSelected(true);
foundDefault = true;
} else if (completeNotificationUri.equals(ringtoneSettings.getRingtoneUri().toString())) {
notificationSoundItem.setSelected(true);
foundDefault = true;
} else if (ringtoneSettings.getRingtoneUri().toString().equals(ringtoneString)) {
((NotificationSoundItem) abstractFlexibleItemList.get(1)).setSelected(true);
foundDefault = true;
}
} catch (IOException e) {
Log.e(TAG, "Failed to parse ringtone settings");
}
}
}
}
adapter.updateDataSet(abstractFlexibleItemList, true);
adapter.updateDataSet(abstractFlexibleItemList, false);
}
@Override
@ -242,14 +261,16 @@ public class RingtoneSelectionController extends BaseController implements Flexi
if (callNotificationSounds) {
try {
appPreferences.setCallRingtoneUri(LoganSquare.serialize(ringtoneSettings));
toggleSelection(position);
adapter.toggleSelection(position);
adapter.notifyDataSetChanged();
} catch (IOException e) {
Log.e(TAG, "Failed to store selected ringtone for calls");
}
} else {
try {
appPreferences.setMessageRingtoneUri(LoganSquare.serialize(ringtoneSettings));
toggleSelection(position);
adapter.toggleSelection(position);
adapter.notifyDataSetChanged();
} catch (IOException e) {
Log.e(TAG, "Failed to store selected ringtone for calls");
}
@ -259,19 +280,6 @@ public class RingtoneSelectionController extends BaseController implements Flexi
return true;
}
private void toggleSelection(int position) {
adapter.toggleSelection(position);
((NotificationSoundItem) adapter.getItem(position)).flipItemSelection();
NotificationSoundItem notificationSoundItem;
for (int i = 0; i < adapter.getItemCount(); i++) {
if (i != position) {
notificationSoundItem = (NotificationSoundItem) adapter.getItem(i);
notificationSoundItem.flipToFront();
}
}
}
private void endMediaPlayer() {
if (cancelMediaPlayerHandler != null) {
cancelMediaPlayerHandler.removeCallbacksAndMessages(null);

View File

@ -36,7 +36,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Checkable;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -49,10 +48,9 @@ import com.bluelinelabs.conductor.RouterTransaction;
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
import com.bluelinelabs.logansquare.LoganSquare;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.LazyHeaders;
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
import com.bumptech.glide.request.RequestOptions;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;
import com.nextcloud.talk.BuildConfig;
import com.nextcloud.talk.R;
import com.nextcloud.talk.api.NcApi;
@ -67,7 +65,6 @@ import com.nextcloud.talk.utils.DoNotDisturbUtils;
import com.nextcloud.talk.utils.SecurityUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils;
import com.nextcloud.talk.utils.glide.GlideApp;
import com.nextcloud.talk.utils.preferences.AppPreferences;
import com.nextcloud.talk.utils.preferences.MagicUserInputModule;
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder;
@ -90,113 +87,78 @@ import java.util.*;
public class SettingsController extends BaseController {
public static final String TAG = "SettingsController";
private static final int ID_REMOVE_ACCOUNT_WARNING_DIALOG = 0;
@BindView(R.id.settings_screen)
MaterialPreferenceScreen settingsScreen;
@BindView(R.id.settings_proxy_choice)
MaterialChoicePreference proxyChoice;
@BindView(R.id.settings_proxy_port_edit)
MaterialEditTextPreference proxyPortEditText;
@BindView(R.id.settings_licence)
MaterialStandardPreference licenceButton;
@BindView(R.id.settings_privacy)
MaterialStandardPreference privacyButton;
@BindView(R.id.settings_source_code)
MaterialStandardPreference sourceCodeButton;
@BindView(R.id.settings_version)
MaterialStandardPreference versionInfo;
@BindView(R.id.avatar_image)
ImageView avatarImageView;
SimpleDraweeView avatarImageView;
@BindView(R.id.display_name_text)
TextView displayNameTextView;
@BindView(R.id.base_url_text)
TextView baseUrlTextView;
@BindView(R.id.settings_call_sound)
MaterialStandardPreference settingsCallSound;
@BindView(R.id.settings_message_sound)
MaterialStandardPreference settingsMessageSound;
@BindView(R.id.settings_remove_account)
MaterialStandardPreference removeAccountButton;
@BindView(R.id.settings_switch)
MaterialStandardPreference switchAccountButton;
@BindView(R.id.settings_reauthorize)
MaterialStandardPreference reauthorizeButton;
@BindView(R.id.settings_add_account)
MaterialStandardPreference addAccountButton;
@BindView(R.id.message_view)
MaterialPreferenceCategory messageView;
@BindView(R.id.settings_client_cert)
MaterialStandardPreference certificateSetup;
@BindView(R.id.settings_always_vibrate)
MaterialSwitchPreference shouldVibrateSwitchPreference;
@BindView(R.id.settings_incognito_keyboard)
MaterialSwitchPreference incognitoKeyboardSwitchPreference;
@BindView(R.id.settings_screen_security)
MaterialSwitchPreference screenSecuritySwitchPreference;
@BindView(R.id.settings_link_previews)
MaterialSwitchPreference linkPreviewsSwitchPreference;
@BindView(R.id.settings_screen_lock)
MaterialSwitchPreference screenLockSwitchPreference;
@BindView(R.id.settings_screen_lock_timeout)
MaterialChoicePreference screenLockTimeoutChoicePreference;
@BindView(R.id.message_text)
TextView messageText;
@Inject
EventBus eventBus;
@Inject
AppPreferences appPreferences;
@Inject
NcApi ncApi;
@Inject
UserUtils userUtils;
@Inject
Context context;
private LovelySaveStateHandler saveStateHandler;
private UserEntity currentUser;
private String credentials;
private OnPreferenceValueChangedListener<String> proxyTypeChangeListener;
private OnPreferenceValueChangedListener<Boolean> proxyCredentialsChangeListener;
private OnPreferenceValueChangedListener<Boolean> screenSecurityChangeListener;
private OnPreferenceValueChangedListener<Boolean> screenLockChangeListener;
private OnPreferenceValueChangedListener<String> screenLockTimeoutChangeListener;
private Disposable profileQueryDisposable;
private Disposable dbQueryDisposable;
private static final int ID_REMOVE_ACCOUNT_WARNING_DIALOG = 0;
@Override
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
return inflater.inflate(R.layout.controller_settings, container, false);
@ -636,17 +598,13 @@ public class SettingsController extends BaseController {
avatarId = currentUser.getUsername();
}
GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(currentUser.getBaseUrl(),
avatarId, R.dimen.avatar_size_big), new LazyHeaders.Builder()
.setHeader("Accept", "image/*")
.setHeader("User-Agent", ApiUtils.getUserAgent())
.build());
GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
.load(glideUrl)
.centerInside()
.apply(RequestOptions.bitmapTransform(new CircleCrop()))
.into(avatarImageView);
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
.setOldController(avatarImageView.getController())
.setAutoPlayAnimations(true)
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(currentUser.getBaseUrl(),
avatarId, R.dimen.avatar_size_big), null))
.build();
avatarImageView.setController(draweeController);
}
@Override

View File

@ -30,7 +30,6 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
@ -227,11 +226,6 @@ public class SwitchAccountController extends BaseController {
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
recyclerView.addItemDecoration(new DividerItemDecoration(
recyclerView.getContext(),
layoutManager.getOrientation()
));
swipeRefreshLayout.setEnabled(false);
}

View File

@ -291,11 +291,6 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
return true;
}
@Parcel
public enum MenuType {
REGULAR, SHARE
}
private Data getWorkerData() {
if (!TextUtils.isEmpty(conversation.getToken())) {
Data.Builder data = new Data.Builder();
@ -318,4 +313,9 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
return null;
}
@Parcel
public enum MenuType {
REGULAR, SHARE
}
}

View File

@ -197,9 +197,9 @@ public class RestModule {
if (appPreferences.getProxyCredentials() &&
!TextUtils.isEmpty(appPreferences.getProxyUsername()) &&
!TextUtils.isEmpty(appPreferences.getProxyPassword())) {
httpClient.proxyAuthenticator(new ProxyAuthenticator(Credentials.basic(
httpClient.proxyAuthenticator(new MagicAuthenticator(Credentials.basic(
appPreferences.getProxyUsername(),
appPreferences.getProxyPassword())));
appPreferences.getProxyPassword()), "Proxy-Authorization"));
}
}
@ -210,10 +210,10 @@ public class RestModule {
public static class HeadersInterceptor implements Interceptor {
@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("User-Agent", ApiUtils.getUserAgent())
.header("Accept", "application/json")
@ -231,24 +231,27 @@ public class RestModule {
}
}
private class ProxyAuthenticator implements Authenticator {
public static class MagicAuthenticator implements Authenticator {
private String credentials;
private String authenticatorType;
private ProxyAuthenticator(String credentials) {
public MagicAuthenticator(@NonNull String credentials, @NonNull String authenticatorType) {
this.credentials = credentials;
this.authenticatorType = authenticatorType;
}
@Nullable
@Override
public Request authenticate(@NonNull Route route, @NonNull Response response) throws IOException {
if (credentials.equals(response.request().header("Proxy-Authorization"))) {
public Request authenticate(@Nullable Route route, @NonNull Response response) {
if (response.request().header(authenticatorType) != null) {
return null;
}
int attemptsCount = 0;
Response countedResponse = response;
int attemptsCount = 0;
while ((countedResponse = countedResponse.priorResponse()) != null) {
attemptsCount++;
if (attemptsCount == 3) {
@ -257,7 +260,7 @@ public class RestModule {
}
return response.request().newBuilder()
.header("Proxy-Authorization", credentials)
.header(authenticatorType, credentials)
.build();
}
}

View File

@ -0,0 +1,27 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.interfaces;
public interface SelectionInterface {
void toggleBrowserItemSelection(String path);
boolean isPathSelected(String path);
}

View File

@ -86,6 +86,7 @@ public class DeleteConversationWorker extends Worker {
.subscribeOn(Schedulers.newThread())
.blockingSubscribe(new Observer<GenericOverall>() {
Disposable disposable;
@Override
public void onSubscribe(Disposable d) {
disposable = d;

View File

@ -86,6 +86,7 @@ public class LeaveConversationWorker extends Worker {
.subscribeOn(Schedulers.newThread())
.blockingSubscribe(new Observer<GenericOverall>() {
Disposable disposable;
@Override
public void onSubscribe(Disposable d) {
disposable = d;

View File

@ -0,0 +1,105 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.jobs;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.work.Data;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
import autodagger.AutoInjector;
import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.bundle.BundleKeys;
import com.nextcloud.talk.utils.database.user.UserUtils;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@AutoInjector(NextcloudTalkApplication.class)
public class ShareOperationWorker extends Worker {
@Inject
UserUtils userUtils;
@Inject
NcApi ncApi;
private long userId;
private UserEntity operationsUser;
private String roomToken;
private List<String> filesArray = new ArrayList<>();
private String credentials;
private String baseUrl;
public ShareOperationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
Data data = workerParams.getInputData();
userId = data.getLong(BundleKeys.KEY_INTERNAL_USER_ID, 0);
roomToken = data.getString(BundleKeys.KEY_ROOM_TOKEN);
Collections.addAll(filesArray, data.getStringArray(BundleKeys.KEY_FILE_PATHS));
operationsUser = userUtils.getUserWithId(userId);
credentials = ApiUtils.getCredentials(operationsUser.getUsername(), operationsUser.getToken());
baseUrl = operationsUser.getBaseUrl();
}
@NonNull
@Override
public Result doWork() {
for (int i = 0; i < filesArray.size(); i++) {
ncApi.createRemoteShare(credentials,
ApiUtils.getSharingUrl(baseUrl),
filesArray.get(i),
roomToken,
"10")
.subscribeOn(Schedulers.newThread())
.blockingSubscribe(new Observer<Void>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Void aVoid) {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
return Result.success();
}
}

View File

@ -75,6 +75,20 @@ public interface User extends Parcelable, Persistable, Serializable {
return false;
}
default boolean hasExternalCapability(String capabilityName) {
if (getCapabilities() != null) {
try {
Capabilities capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class);
if (capabilities.getExternalCapability() != null && capabilities.getExternalCapability().containsKey("v1")) {
return capabilities.getExternalCapability().get("v1").contains("capabilityName");
}
} catch (IOException e) {
Log.e(TAG, "Failed to get capabilities for the user");
}
}
return false;
}
default boolean hasSpreedCapabilityWithName(String capabilityName) {
if (getCapabilities() != null) {
try {

View File

@ -25,6 +25,9 @@ import com.bluelinelabs.logansquare.annotation.JsonObject;
import lombok.Data;
import org.parceler.Parcel;
import java.util.HashMap;
import java.util.List;
@Parcel
@Data
@JsonObject
@ -34,4 +37,10 @@ public class Capabilities {
@JsonField(name = "notifications")
NotificationsCapability notificationsCapability;
@JsonField(name = "theming")
ThemingCapability themingCapability;
@JsonField(name = "external")
HashMap<String, List<String>> externalCapability;
}

View File

@ -0,0 +1,61 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.models.json.capabilities;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
import lombok.Data;
import org.parceler.Parcel;
@Parcel
@Data
@JsonObject
class ThemingCapability {
@JsonField(name = "name")
String name;
@JsonField(name = "url")
String url;
@JsonField(name = "slogan")
String slogan;
@JsonField(name = "color")
String color;
@JsonField(name = "color-text")
String colorText;
@JsonField(name = "color-element")
String colorElement;
@JsonField(name = "logo")
String logo;
@JsonField(name = "background")
String background;
@JsonField(name = "background-plain")
boolean backgroundPlain;
@JsonField(name = "background-default")
boolean backgroundDefault;
}

View File

@ -26,6 +26,7 @@ import com.bluelinelabs.logansquare.annotation.JsonIgnore;
import com.bluelinelabs.logansquare.annotation.JsonObject;
import com.nextcloud.talk.R;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.models.database.UserEntity;
import com.nextcloud.talk.models.json.converters.EnumSystemMessageTypeConverter;
import com.nextcloud.talk.utils.ApiUtils;
import com.nextcloud.talk.utils.TextMatchers;
@ -44,7 +45,7 @@ public class ChatMessage implements IMessage, MessageContentType, MessageContent
@JsonIgnore
public boolean isGrouped;
@JsonIgnore
public String activeUserId;
public UserEntity activeUser;
@JsonIgnore
public Map<String, String> selectedIndividualHashMap;
@JsonIgnore
@ -52,7 +53,6 @@ public class ChatMessage implements IMessage, MessageContentType, MessageContent
List<MessageType> messageTypesToIgnore = Arrays.asList(MessageType.REGULAR_TEXT_MESSAGE,
MessageType.SYSTEM_MESSAGE, MessageType.SINGLE_LINK_VIDEO_MESSAGE,
MessageType.SINGLE_LINK_AUDIO_MESSAGE, MessageType.SINGLE_LINK_MESSAGE);
String baseUrl;
@JsonField(name = "id")
int jsonMessageId;
@JsonField(name = "token")
@ -96,9 +96,8 @@ public class ChatMessage implements IMessage, MessageContentType, MessageContent
Map<String, String> individualHashMap = messageParameters.get(key);
if (individualHashMap.get("type").equals("file")) {
selectedIndividualHashMap = individualHashMap;
return String.format(Locale.getDefault(),
"%s/index.php/core/preview?fileId=%s&x=%d&y=%d&forceIcon=1",
baseUrl, individualHashMap.get("id"), 480, 480);
return (ApiUtils.getUrlForFilePreviewWithFileId(getActiveUser().getBaseUrl(),
individualHashMap.get("id"), NextcloudTalkApplication.getSharedApplication().getResources().getDimensionPixelSize(R.dimen.maximum_file_preview_size)));
}
}
}
@ -130,14 +129,6 @@ public class ChatMessage implements IMessage, MessageContentType, MessageContent
this.selectedIndividualHashMap = selectedIndividualHashMap;
}
public String getBaseUrl() {
return baseUrl;
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
@Override
public String getId() {
return Integer.toString(jsonMessageId);
@ -155,42 +146,42 @@ public class ChatMessage implements IMessage, MessageContentType, MessageContent
if (getMessageType().equals(MessageType.SINGLE_LINK_GIPHY_MESSAGE)
|| getMessageType().equals(MessageType.SINGLE_LINK_TENOR_MESSAGE)
|| getMessageType().equals(MessageType.SINGLE_LINK_GIF_MESSAGE)) {
if (getActorId().equals(getActiveUserId())) {
if (getActorId().equals(getActiveUser().getUserId())) {
return (NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_sent_a_gif_you));
} else {
return (String.format(NextcloudTalkApplication.getSharedApplication().getResources().getString(R.string.nc_sent_a_gif),
!TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName() : NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_guest)));
}
} else if (getMessageType().equals(MessageType.SINGLE_NC_ATTACHMENT_MESSAGE)) {
if (getActorId().equals(getActiveUserId())) {
if (getActorId().equals(getActiveUser().getUserId())) {
return (NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_sent_an_attachment_you));
} else {
return (String.format(NextcloudTalkApplication.getSharedApplication().getResources().getString(R.string.nc_sent_an_attachment),
!TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName() : NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_guest)));
}
} else if (getMessageType().equals(MessageType.SINGLE_LINK_MESSAGE)) {
if (getActorId().equals(getActiveUserId())) {
if (getActorId().equals(getActiveUser().getUserId())) {
return (NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_sent_a_link_you));
} else {
return (String.format(NextcloudTalkApplication.getSharedApplication().getResources().getString(R.string.nc_sent_a_link),
!TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName() : NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_guest)));
}
} else if (getMessageType().equals(MessageType.SINGLE_LINK_AUDIO_MESSAGE)) {
if (getActorId().equals(getActiveUserId())) {
if (getActorId().equals(getActiveUser().getUserId())) {
return (NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_sent_an_audio_you));
} else {
return (String.format(NextcloudTalkApplication.getSharedApplication().getResources().getString(R.string.nc_sent_an_audio),
!TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName() : NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_guest)));
}
} else if (getMessageType().equals(MessageType.SINGLE_LINK_VIDEO_MESSAGE)) {
if (getActorId().equals(getActiveUserId())) {
if (getActorId().equals(getActiveUser().getUserId())) {
return (NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_sent_a_video_you));
} else {
return (String.format(NextcloudTalkApplication.getSharedApplication().getResources().getString(R.string.nc_sent_a_video),
!TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName() : NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_guest)));
}
} else if (getMessageType().equals(MessageType.SINGLE_LINK_IMAGE_MESSAGE)) {
if (getActorId().equals(getActiveUserId())) {
if (getActorId().equals(getActiveUser().getUserId())) {
return (NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_sent_an_image_you));
} else {
return (String.format(NextcloudTalkApplication.getSharedApplication().getResources().getString(R.string.nc_sent_an_image),
@ -218,7 +209,7 @@ public class ChatMessage implements IMessage, MessageContentType, MessageContent
@Override
public String getAvatar() {
if (getActorType().equals("users")) {
return ApiUtils.getUrlForAvatarWithName(getBaseUrl(), actorId, R.dimen.avatar_size);
return ApiUtils.getUrlForAvatarWithName(getActiveUser().getBaseUrl(), actorId, R.dimen.avatar_size);
} else {
return null;
}

View File

@ -20,7 +20,6 @@
package com.nextcloud.talk.models.json.mention;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonIgnore;
import com.bluelinelabs.logansquare.annotation.JsonObject;
import lombok.Data;
import org.parceler.Parcel;

View File

@ -26,6 +26,7 @@ package com.nextcloud.talk.utils;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.Log;
import com.nextcloud.talk.R;
@ -101,6 +102,26 @@ public class AccountUtils {
return appName;
}
public static boolean canWeOpenFilesApp(Context context, String accountName) {
PackageManager pm = context.getPackageManager();
try {
PackageInfo packageInfo =
pm.getPackageInfo(context.getString(R.string.nc_import_accounts_from), 0);
if (packageInfo.versionCode < 1) {
final AccountManager accMgr = AccountManager.get(context);
final Account[] accounts = accMgr.getAccountsByType(context.getString(R.string.nc_import_account_type));
for (Account account : accounts) {
if (account.name.equals(accountName)) {
return true;
}
}
}
} catch (PackageManager.NameNotFoundException appNotFoundException) {
}
return false;
}
public static ImportAccount getInformationFromAccount(Account account) {
int lastAtPos = account.name.lastIndexOf("@");
String urlString = account.name.substring(lastAtPos + 1);

View File

@ -60,6 +60,21 @@ public class ApiUtils {
return retrofitBucket;
}
public static String getUrlForFilePreviewWithRemotePath(String baseUrl, String remotePath, int px) {
return baseUrl + "/index.php/core/preview.png?file="
+ Uri.encode(remotePath, "UTF-8")
+ "&x=" + px + "&y=" + px + "&a=1&mode=cover&forceIcon=1";
}
public static String getUrlForFilePreviewWithFileId(String baseUrl, String fileId, int px) {
return baseUrl + "/index.php/core/preview?fileId="
+ fileId + "&x=" + px + "&y=" + px + "&a=1&mode=cover&forceIcon=1";
}
public static String getSharingUrl(String baseUrl) {
return baseUrl + ocsApiVersion + "/apps/files_sharing/api/v1/shares";
}
public static RetrofitBucket getRetrofitBucketForContactsSearchFor14(String baseUrl, @Nullable String searchQuery) {
RetrofitBucket retrofitBucket = getRetrofitBucketForContactsSearch(baseUrl, searchQuery);
retrofitBucket.setUrl(baseUrl + ocsApiVersion + "/core/autocomplete/get");

View File

@ -0,0 +1,43 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.utils;
import android.content.Context;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class DateUtils {
public static String getLocalDateTimeStringFromTimestamp(Context context, long timestamp) {
Calendar cal = Calendar.getInstance();
TimeZone tz = cal.getTimeZone();
/* date formatter in local timezone */
Locale currentLocale = context.getResources().getConfiguration().locale;
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss", currentLocale);
sdf.setTimeZone(tz);
return sdf.format(new Date(timestamp));
}
}

View File

@ -60,6 +60,7 @@ import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.image.ImageInfo;
import com.facebook.imagepipeline.postprocessors.RoundAsCirclePostprocessor;
import com.facebook.imagepipeline.postprocessors.RoundPostprocessor;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.google.android.material.chip.ChipDrawable;
@ -72,9 +73,13 @@ import com.vanniktech.emoji.EmojiEditText;
import com.vanniktech.emoji.EmojiTextView;
import org.greenrobot.eventbus.EventBus;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -86,14 +91,14 @@ public class DisplayUtils {
SpannableString spannableString = new SpannableString(string);
spannableString.setSpan(new ClickableSpan() {
@Override
public void onClick(@NonNull View widget) {
public void onClick(@Nonnull View widget) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
NextcloudTalkApplication.getSharedApplication().getApplicationContext().startActivity(browserIntent);
}
@Override
public void updateDrawState(TextPaint ds) {
public void updateDrawState(@NonNull TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
}
@ -104,7 +109,8 @@ public class DisplayUtils {
private static void updateViewSize(@Nullable ImageInfo imageInfo, SimpleDraweeView draweeView) {
if (imageInfo != null) {
draweeView.getLayoutParams().width = imageInfo.getWidth() > 480 ? 480 : imageInfo.getWidth();
int maxSize = draweeView.getContext().getResources().getDimensionPixelSize(R.dimen.maximum_file_preview_size);
draweeView.getLayoutParams().width = imageInfo.getWidth() > maxSize ? maxSize : imageInfo.getWidth();
draweeView.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
draweeView.setAspectRatio((float) imageInfo.getWidth() / imageInfo.getHeight());
draweeView.requestLayout();
@ -120,7 +126,7 @@ public class DisplayUtils {
public static Bitmap getRoundedBitmapFromVectorDrawableResource(Resources resources, int resource) {
VectorDrawable vectorDrawable = (VectorDrawable) resources.getDrawable(resource);
Bitmap bitmap = getBitmap(vectorDrawable);
new RoundAsCirclePostprocessor(true).process(bitmap);
new RoundPostprocessor(true).process(bitmap);
return bitmap;
}
@ -142,11 +148,18 @@ public class DisplayUtils {
return bitmap;
}
public static ImageRequest getImageRequestForUrl(String url) {
public static ImageRequest getImageRequestForUrl(String url, @Nullable UserEntity userEntity) {
Map<String, String> headers = new HashMap<>();
if (userEntity != null && url.startsWith(userEntity.getBaseUrl()) && url.contains("index.php/core/preview?fileId=")) {
headers.put("Authorization", ApiUtils.getCredentials(userEntity.getUsername(),
userEntity.getToken()));
}
return ImageRequestBuilder.newBuilderWithSource(Uri.parse(url))
.setProgressiveRenderingEnabled(true)
.setRotationOptions(RotationOptions.autoRotate())
.disableDiskCache()
.setHeaders(headers)
.build();
}
@ -252,7 +265,7 @@ public class DisplayUtils {
if (!isCall) {
ImageRequest imageRequest =
getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(conversationUser.getBaseUrl(), id, R.dimen.avatar_size_big));
getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(conversationUser.getBaseUrl(), id, R.dimen.avatar_size_big), null);
ImagePipeline imagePipeline = Fresco.getImagePipeline();
DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, context);

View File

@ -0,0 +1,161 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017/2018 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.utils;
import com.nextcloud.talk.R;
import java.util.HashMap;
import java.util.Map;
public class DrawableUtils {
public static int getDrawableResourceIdForMimeType(String mimetype) {
Map<String, Integer> drawableMap = new HashMap<>();
// Initial list of mimetypes was acquired from https://github.com/nextcloud/server/blob/694ba5435b2963e201f6a6d2c775836bde07aaef/core/js/mimetypelist.js
drawableMap.put("application/coreldraw", R.drawable.ic_mimetype_image);
drawableMap.put("application/epub+zip", R.drawable.ic_mimetype_text);
drawableMap.put("application/font-sfnt", R.drawable.ic_mimetype_image);
drawableMap.put("application/font-woff", R.drawable.ic_mimetype_image);
drawableMap.put("application/gpx+xml", R.drawable.ic_mimetype_location);
drawableMap.put("application/illustrator", R.drawable.ic_mimetype_image);
drawableMap.put("application/javascript", R.drawable.ic_mimetype_text_code);
drawableMap.put("application/json", R.drawable.ic_mimetype_text_code);
drawableMap.put("application/msaccess", R.drawable.ic_mimetype_file);
drawableMap.put("application/msexcel", R.drawable.ic_mimetype_x_office_spreadsheet);
drawableMap.put("application/msonenote", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/mspowerpoint", R.drawable.ic_mimetype_x_office_presentation);
drawableMap.put("application/msword", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/octet-stream", R.drawable.ic_mimetype_file);
drawableMap.put("application/postscript", R.drawable.ic_mimetype_image);
drawableMap.put("application/rss+xml", R.drawable.ic_mimetype_text_code);
drawableMap.put("application/vnd.android.package-archive", R.drawable.ic_mimetype_package_x_generic);
drawableMap.put("application/vnd.lotus-wordpro", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/vnd.garmin.tcx+xml", R.drawable.ic_mimetype_location);
drawableMap.put("application/vnd.google-earth.kml+xml", R.drawable.ic_mimetype_location);
drawableMap.put("application/vnd.google-earth.kmz", R.drawable.ic_mimetype_location);
drawableMap.put("application/vnd.ms-excel", R.drawable.ic_mimetype_x_office_spreadsheet);
drawableMap.put("application/vnd.ms-excel.addin.macroEnabled.12", R.drawable.ic_mimetype_x_office_spreadsheet);
drawableMap.put("application/vnd.ms-excel.sheet.binary.macroEnabled.12", R.drawable.ic_mimetype_x_office_spreadsheet);
drawableMap.put("application/vnd.ms-excel.sheet.macroEnabled.12", R.drawable.ic_mimetype_x_office_spreadsheet);
drawableMap.put("application/vnd.ms-excel.template.macroEnabled.12", R.drawable.ic_mimetype_x_office_spreadsheet);
drawableMap.put("application/vnd.ms-fontobject", R.drawable.ic_mimetype_image);
drawableMap.put("application/vnd.ms-powerpoint", R.drawable.ic_mimetype_x_office_presentation);
drawableMap.put("application/vnd.ms-powerpoint.addin.macroEnabled.12", R.drawable.ic_mimetype_x_office_presentation);
drawableMap.put("application/vnd.ms-powerpoint.presentation.macroEnabled.12", R.drawable.ic_mimetype_x_office_presentation);
drawableMap.put("application/vnd.ms-powerpoint.slideshow.macroEnabled.12", R.drawable.ic_mimetype_x_office_presentation);
drawableMap.put("application/vnd.ms-powerpoint.template.macroEnabled.12", R.drawable.ic_mimetype_x_office_presentation);
drawableMap.put("application/vnd.ms-visio.drawing.macroEnabled.12", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/vnd.ms-visio.drawing", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/vnd.ms-visio.stencil.macroEnabled.12", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/vnd.ms-visio.stencil", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/vnd.ms-visio.template.macroEnabled.12", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/vnd.ms-visio.template", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/vnd.ms-word.template.macroEnabled.12", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/vnd.oasis.opendocument.presentation", R.drawable.ic_mimetype_x_office_presentation);
drawableMap.put("application/vnd.oasis.opendocument.presentation-template", R.drawable.ic_mimetype_x_office_presentation);
drawableMap.put("application/vnd.oasis.opendocument.spreadsheet", R.drawable.ic_mimetype_x_office_spreadsheet);
drawableMap.put("application/vnd.oasis.opendocument.spreadsheet-template", R.drawable.ic_mimetype_x_office_spreadsheet);
drawableMap.put("application/vnd.oasis.opendocument.text", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/vnd.oasis.opendocument.text-master", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/vnd.oasis.opendocument.text-template", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/vnd.oasis.opendocument.text-web", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/vnd.openxmlformats-officedocument.presentationml.presentation", R.drawable.ic_mimetype_x_office_presentation);
drawableMap.put("application/vnd.openxmlformats-officedocument.presentationml.slideshow", R.drawable.ic_mimetype_x_office_presentation);
drawableMap.put("application/vnd.openxmlformats-officedocument.presentationml.template", R.drawable.ic_mimetype_x_office_presentation);
drawableMap.put("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", R.drawable.ic_mimetype_x_office_spreadsheet);
drawableMap.put("application/vnd.openxmlformats-officedocument.spreadsheetml.template", R.drawable.ic_mimetype_x_office_spreadsheet);
drawableMap.put("application/vnd.openxmlformats-officedocument.wordprocessingml.document", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/vnd.openxmlformats-officedocument.wordprocessingml.template", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/vnd.visio", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/vnd.wordperfect", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/x-7z-compressed", R.drawable.ic_mimetype_package_x_generic);
drawableMap.put("application/x-bzip2", R.drawable.ic_mimetype_package_x_generic);
drawableMap.put("application/x-cbr", R.drawable.ic_mimetype_text);
drawableMap.put("application/x-compressed", R.drawable.ic_mimetype_package_x_generic);
drawableMap.put("application/x-dcraw", R.drawable.ic_mimetype_image);
drawableMap.put("application/x-deb", R.drawable.ic_mimetype_package_x_generic);
drawableMap.put("application/x-fictionbook+xml", R.drawable.ic_mimetype_text);
drawableMap.put("application/x-font", R.drawable.ic_mimetype_image);
drawableMap.put("application/x-gimp", R.drawable.ic_mimetype_image);
drawableMap.put("application/x-gzip", R.drawable.ic_mimetype_package_x_generic);
drawableMap.put("application/x-iwork-keynote-sffkey", R.drawable.ic_mimetype_x_office_presentation);
drawableMap.put("application/x-iwork-numbers-sffnumbers", R.drawable.ic_mimetype_x_office_spreadsheet);
drawableMap.put("application/x-iwork-pages-sffpages", R.drawable.ic_mimetype_x_office_document);
drawableMap.put("application/x-mobipocket-ebook", R.drawable.ic_mimetype_text);
drawableMap.put("application/x-perl", R.drawable.ic_mimetype_text_code);
drawableMap.put("application/x-photoshop", R.drawable.ic_mimetype_image);
drawableMap.put("application/x-php", R.drawable.ic_mimetype_text_code);
drawableMap.put("application/x-rar-compressed", R.drawable.ic_mimetype_package_x_generic);
drawableMap.put("application/x-tar", R.drawable.ic_mimetype_package_x_generic);
drawableMap.put("application/x-tex", R.drawable.ic_mimetype_text);
drawableMap.put("application/xml", R.drawable.ic_mimetype_text_code);
drawableMap.put("application/yaml", R.drawable.ic_mimetype_text_code);
drawableMap.put("application/zip", R.drawable.ic_mimetype_package_x_generic);
drawableMap.put("database", R.drawable.ic_mimetype_file);
drawableMap.put("httpd/unix-directory", R.drawable.ic_mimetype_folder);
drawableMap.put("text/css", R.drawable.ic_mimetype_text_code);
drawableMap.put("text/csv", R.drawable.ic_mimetype_x_office_spreadsheet);
drawableMap.put("text/html", R.drawable.ic_mimetype_text_code);
drawableMap.put("text/x-c", R.drawable.ic_mimetype_text_code);
drawableMap.put("text/x-c++src", R.drawable.ic_mimetype_text_code);
drawableMap.put("text/x-h", R.drawable.ic_mimetype_text_code);
drawableMap.put("text/x-java-source", R.drawable.ic_mimetype_text_code);
drawableMap.put("text/x-ldif", R.drawable.ic_mimetype_text_code);
drawableMap.put("text/x-python", R.drawable.ic_mimetype_text_code);
drawableMap.put("text/x-shellscript", R.drawable.ic_mimetype_text_code);
drawableMap.put("web", R.drawable.ic_mimetype_text_code);
drawableMap.put("application/internet-shortcut", R.drawable.ic_mimetype_link);
drawableMap.put("inode/directory", R.drawable.ic_mimetype_folder);
drawableMap.put("unknown", R.drawable.ic_mimetype_file);
drawableMap.put("application/pdf", R.drawable.ic_mimetype_application_pdf);
if ("DIR".equals(mimetype)) {
mimetype = "inode/directory";
return drawableMap.get(mimetype);
}
if (drawableMap.containsKey(mimetype)) {
return drawableMap.get(mimetype);
}
if (mimetype.startsWith("image/")) {
return R.drawable.ic_mimetype_image;
}
if (mimetype.startsWith("video/")) {
return R.drawable.ic_mimetype_video;
}
if (mimetype.startsWith("text/")) {
return R.drawable.ic_mimetype_text;
}
if (mimetype.startsWith("audio")) {
return R.drawable.ic_mimetype_audio;
}
return drawableMap.get("unknown");
}
}

View File

@ -24,9 +24,7 @@ import android.content.Context;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import autodagger.AutoInjector;
import com.bluelinelabs.logansquare.LoganSquare;
import com.nextcloud.talk.R;
import com.nextcloud.talk.api.NcApi;
@ -38,15 +36,12 @@ import com.nextcloud.talk.models.json.push.PushConfigurationState;
import com.nextcloud.talk.models.json.push.PushRegistrationOverall;
import com.nextcloud.talk.utils.database.user.UserUtils;
import com.nextcloud.talk.utils.preferences.AppPreferences;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import org.greenrobot.eventbus.EventBus;
import javax.inject.Inject;
import java.io.*;
import java.security.*;
import java.security.spec.InvalidKeySpecException;

View File

@ -24,11 +24,10 @@ package com.nextcloud.talk.utils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.PatternsCompat;
import com.nextcloud.talk.models.json.chat.ChatMessage;
import com.vanniktech.emoji.EmojiInformation;
import com.vanniktech.emoji.EmojiUtils;
import androidx.core.util.PatternsCompat;
import eu.medsea.mimeutil.MimeUtil;
import eu.medsea.mimeutil.detector.ExtensionMimeDetector;
import eu.medsea.mimeutil.detector.MagicMimeMimeDetector;

View File

@ -51,4 +51,8 @@ public class BundleKeys {
public static final String KEY_FROM_NOTIFICATION_START_CALL = "KEY_FROM_NOTIFICATION_START_CALL";
public static final String KEY_ROOM_ID = "KEY_ROOM_ID";
public static final String KEY_ARE_CALL_SOUNDS = "KEY_ARE_CALL_SOUNDS";
public static final String KEY_BROWSER_TYPE = "KEY_BROWSER_TYPE";
public static final String KEY_FILE_PATHS = "KEY_FILE_PATHS";
public static final String KEY_ACCOUNT = "KEY_ACCOUNT";
public static final String KEY_FILE_PATH = "KEY_FILE_PATH";
}

View File

@ -1,54 +0,0 @@
/*
* Nextcloud Talk application
*
* @author Mario Danic
* Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.utils.glide;
import android.content.Context;
import autodagger.AutoInjector;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.Registry;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.module.AppGlideModule;
import com.nextcloud.talk.application.NextcloudTalkApplication;
import okhttp3.OkHttpClient;
import javax.inject.Inject;
import java.io.InputStream;
@AutoInjector(NextcloudTalkApplication.class)
@GlideModule
public class CachingGlideModule extends AppGlideModule {
@Inject
OkHttpClient okHttpClient;
@Override
public void registerComponents(Context context, Glide glide, Registry registry) {
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(okHttpClient));
}
@Override
public void applyOptions(Context context, GlideBuilder builder) {
}
}

View File

@ -39,40 +39,17 @@ import javax.inject.Inject;
public class PowerManagerUtils {
private static final String TAG = "PowerManagerUtils";
@Inject
Context context;
private final PowerManager.WakeLock fullLock;
private final PowerManager.WakeLock partialLock;
private final WifiManager.WifiLock wifiLock;
private ProximityLock proximityLock;
private final boolean wifiLockEnforced;
@Inject
Context context;
private ProximityLock proximityLock;
private boolean proximityDisabled = false;
private int orientation;
public enum PhoneState {
IDLE,
PROCESSING, //used when the phone is active but before the user should be alerted.
INTERACTIVE,
WITHOUT_PROXIMITY_SENSOR_LOCK,
WITH_PROXIMITY_SENSOR_LOCK
}
public enum WakeLockState {
FULL,
PARTIAL,
SLEEP,
PROXIMITY
}
public void setOrientation(int newOrientation) {
orientation = newOrientation;
updateInCallWakeLockState();
}
public PowerManagerUtils() {
NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
@ -95,8 +72,13 @@ public class PowerManagerUtils {
orientation = context.getResources().getConfiguration().orientation;
}
public void setOrientation(int newOrientation) {
orientation = newOrientation;
updateInCallWakeLockState();
}
public void updatePhoneState(PhoneState state) {
switch(state) {
switch (state) {
case IDLE:
setWakeLockState(WakeLockState.SLEEP);
break;
@ -132,7 +114,7 @@ public class PowerManagerUtils {
@SuppressLint("WakelockTimeout")
private synchronized void setWakeLockState(WakeLockState newState) {
switch(newState) {
switch (newState) {
case FULL:
if (!fullLock.isHeld()) {
fullLock.acquire();
@ -193,4 +175,19 @@ public class PowerManagerUtils {
// something went very very wrong
}
}
public enum PhoneState {
IDLE,
PROCESSING, //used when the phone is active but before the user should be alerted.
INTERACTIVE,
WITHOUT_PROXIMITY_SENSOR_LOCK,
WITH_PROXIMITY_SENSOR_LOCK
}
public enum WakeLockState {
FULL,
PARTIAL,
SLEEP,
PROXIMITY
}
}

View File

@ -0,0 +1,25 @@
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
</vector>

View File

@ -0,0 +1,25 @@
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
</vector>

View File

@ -1,3 +1,23 @@
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"

View File

@ -1,3 +1,23 @@
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"

View File

@ -0,0 +1,27 @@
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24"
android:width="20.57dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#000000" android:fillType="nonZero"
android:pathData="M0.8571,0C0.3771,0 0,0.3771 0,0.8571L0,23.1429C0,23.6229 0.3771,24 0.8571,24L19.7143,24C20.1943,24 20.5714,23.6229 20.5714,23.1429L20.5714,5.1429L15.4286,0L0.8571,0ZM3.4286,3.4286L13.7143,3.4286L13.7143,5.1429L3.4286,5.1429L3.4286,3.4286ZM3.4286,8.5714L12,8.5714L12,10.2857L3.4286,10.2857L3.4286,8.5714ZM3.4286,13.7143L17.1429,13.7143L17.1429,15.4286L3.4286,15.4286L3.4286,13.7143ZM3.4286,18.8571L10.2857,18.8571L10.2857,20.5714L3.4286,20.5714L3.4286,18.8571Z"
android:strokeColor="#00000000" android:strokeWidth="1"/>
</vector>

View File

@ -1,3 +1,23 @@
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector xmlns:tools="http://schemas.android.com/tools"
android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"

View File

@ -0,0 +1,25 @@
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM15.5,11c0.83,0 1.5,-0.67 1.5,-1.5S16.33,8 15.5,8 14,8.67 14,9.5s0.67,1.5 1.5,1.5zM8.5,11c0.83,0 1.5,-0.67 1.5,-1.5S9.33,8 8.5,8 7,8.67 7,9.5 7.67,11 8.5,11zM12,17.5c2.33,0 4.31,-1.46 5.11,-3.5L6.89,14c0.8,2.04 2.78,3.5 5.11,3.5z"/>
</vector>

View File

@ -1,3 +1,23 @@
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"

View File

@ -1,3 +1,23 @@
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"

View File

@ -1,3 +1,23 @@
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector xmlns:tools="http://schemas.android.com/tools"
android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"

View File

@ -1,3 +1,23 @@
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector xmlns:tools="http://schemas.android.com/tools"
android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"

View File

@ -1,3 +1,23 @@
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"

View File

@ -1,3 +1,23 @@
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"

View File

@ -1,3 +1,23 @@
<!--
~ Nextcloud Talk application
~
~ @author Mario Danic
~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="128" android:viewportWidth="128"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#969696"
android:pathData="M6.94,0.5 C6.7,0.5,6.5,0.7,6.5,0.94 L6.5,2.2 C6,2.34,5.45,2.55,4.97,2.85
L4.06,1.94 C3.9,1.76,3.6,1.75,3.44,1.94 L1.94,3.44 C1.76,3.61,1.76,3.9,1.94,4.06
L2.85,4.97 C2.566,5.45,2.35,5.97,2.2,6.5 L0.94,6.5 C0.7,6.5,0.5,6.7,0.5,6.94
L0.5,9.06 C0.5,9.31,0.69,9.5,0.94,9.5 L2.2,9.5 C2.34,10.04,2.56,10.55,2.85,11.03
L1.94,11.94 C1.76,12.11,1.76,12.39,1.94,12.56 L3.44,14.06
C3.62,14.24,3.9,14.24,4.06,14.06 L4.97,13.15 C5.45,13.435,5.97,13.65,6.5,13.8
L6.5,15.06 C6.5,15.31,6.7,15.5,6.94,15.5 L9.06,15.5
C9.3,15.5,9.51,15.3,9.5,15.06 L9.5,13.8 C10.04,13.66,10.55,13.44,11.03,13.15
L11.94,14.06 C12.11,14.24,12.39,14.24,12.56,14.06 L14.06,12.56
C14.24,12.39,14.24,12.11,14.06,11.94 L13.15,11.03
C13.44,10.55,13.65,10.03,13.8,9.5 L15.06,9.5 C15.3,9.5,15.51,9.3,15.5,9.06
L15.5,6.94 C15.5,6.7,15.3,6.5,15.06,6.5 L13.8,6.5
C13.66,5.96,13.44,5.45,13.15,4.97 L14.06,4.06 C14.24,3.89,14.24,3.61,14.06,3.44
L12.56,1.94 C12.39,1.76,12.11,1.76,11.94,1.94 L11.03,2.85
C10.55,2.56,10.03,2.35,9.5,2.2 L9.5,0.94 C9.5,0.7,9.3,0.5,9.06,0.5 L6.94,0.5 Z
M8,4.5 A3.5,3.5,0,0,1,11.5,8 A3.5,3.5,0,0,1,8,11.5 A3.5,3.5,0,0,1,4.5,8
A3.5,3.5,0,0,1,8,4.5 Z" />
</vector>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#dc5047"
android:pathData="M2.5,1 C2.22,1,2,1.22,2,1.5 L2,14.5 C2,14.78,2.22,15,2.5,15 L13.5,15
C13.78,15,14,14.78,14,14.5 L14,4 L11,1 Z M8.3,4.9 S8.37,5.85,8.15,7.2
C8.865,9.253,9.65,9.53,10,9.7 C10.74,9.64,11.565,9.6,12.3,10
C12.8,10.286,13.194,11.5,12,11.5 C11.46,11.466,10.463,11.154,9.75,10.8
C8.684,10.92,7.36,11.12,6.25,11.6 C5,13.7,4.44,14,4,14
C2.785,13.68,3.44,12.07,3.9,11.8 C4.45,11.33,5.095,11.06,5.3,11
C5.39,10.85,6.684,8.31,7,7.25 C6.7,6.226,6.63,5.144,6.8,4.5
C7.58,3.482,8.3,4.15,8.3,4.9 Z M7.6,8 C7.33,9.057,6.252,11.084,6.3,11
C7.405,10.515,8.4,10.37,9.5,10.2 C8.974,9.965,8.354,9.95,7.6,8 Z" />
</vector>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#969696"
android:pathData="M12.97,0.5 C12.71,0.5,8.175,1.5,5.8,2 C5.33,2.1,5,2.53,5,3 L5,11
C4.44,10.94,3.856,11.0625,3.35,11.34 C2.124,12.01,1.65,13.4,2.284,14.45
C2.924,15.5,4.434,15.8,5.654,15.13 C6.5,14.68,7,13.85,7,13 L7,5 L12,4 L12,10.016
C11.44,9.958,10.856,10.0785,10.35,10.356 C9.124,11.026,8.65,12.416,9.284,13.466
C9.924,14.512,11.434,14.816,12.654,14.146 C13.5,13.68,14,12.85,14,12 L14,1.475
C14,0.91,13.534,0.5,12.97,0.5 Z" />
</vector>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#969696"
android:pathData="M2.5,1 C2.22,1,2,1.22,2,1.5 L2,14.5 C2,14.78,2.22,15,2.5,15 L13.5,15
C13.78,15,14,14.78,14,14.5 L14,4 L11,1 Z" />
</vector>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#0082c9"
android:pathData="M1.5,2 C1.25,2,1,2.25,1,2.5 L1,13.5 C1,13.76,1.24,14,1.5,14 L14.5,14
C14.76,14,15,13.759,15,13.5 L15,4.5 C15,4.25,14.75,4,14.5,4 L8,4 L6,2 Z" />
</vector>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#0082c9"
android:pathData="M1.46,2 C1.21,2,1,2.21,1,2.46 L1,13.54 C1,13.798,1.202,14,1.46,14 L14.54,14
C14.798,14,15,13.798,15,13.54 L15,4.462 C15,4.212,14.79,3.999,14.54,3.999
L8,3.999 L6,2 L1.46,2 Z M2,5 L14,5 L14,13 L2,13 L2,5 Z" />
</vector>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#0082c9"
android:fillType="evenOdd"
android:pathData="M1.4609,2 C1.2109,2,1,2.2109,1,2.4609 L1,13.5389
C1,13.7969,1.2029,13.9999,1.4609,13.9999 L14.5389,13.9999
C14.7969,13.9999,14.9999,13.7969,14.9999,13.5389 L14.9999,4.4628
C14.9999,4.2128,14.7889,3.9979,14.5389,3.9979 L7.9999,3.9979 L5.9999,1.9999
L1.4608,1.9999 Z M8,5.8008 C8.8836,5.8008,9.5996,6.5167,9.5996,7.4004
L9.5996,8.1992 L10,8.1992 L10,11 L6,11 L6,8.1992 L6.4004,8.1992 L6.4004,7.4004
C6.4004,6.5167,7.1164,5.8008,8,5.8008 Z M8,6.5996
C7.5581,6.5996,7.1992,6.9585,7.1992,7.4004 L7.1992,8.1992 L8.8008,8.1992
L8.8008,7.4004 C8.8008,6.9585,8.4419,6.5996,8,6.5996 Z" />
</vector>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#0082c9"
android:fillType="evenOdd"
android:pathData="M1.46,2 C1.21,2,1,2.21,1,2.46 L1,13.54 C1,13.798,1.202,14,1.46,14 L14.54,14
C14.798,14,15,13.798,15,13.54 L15,4.462 C15,4.212,14.79,3.999,14.54,3.999
L8,3.999 L6,2 L1.46,2 Z M7.977,5.793 L11.547,5.793 L11.547,9.178 L10.355,8.05
L8.57,9.743 L7.38,8.613 L9.166,6.923 L7.976,5.793 Z M5.597,6.357 L7.38,6.357
L7.977,6.922 L5.597,6.922 L5.597,11.436 L10.355,11.436 L10.355,9.178
L10.951,9.742 L10.951,11.436 C10.951,11.748,10.686,12,10.356,12 L5.596,12
C5.266,12,5.001,11.748,5.001,11.436 L5.001,6.922
C5.001,6.609,5.267,6.357,5.597,6.357 Z" />
</vector>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#0082c9"
android:pathData="M1.5,2 C1.25,2,1,2.25,1,2.5 L1,13.5 C1,13.76,1.24,14,1.5,14 L14.5,14
C14.76,14,15,13.759,15,13.5 L15,4.5 C15,4.25,14.75,4,14.5,4 L8,4 L6,2 L1.5,2 Z
M9.834,5.5 C10.268,5.4981,10.7,5.6545,11.02,5.9746
C11.66,6.6153,11.66,7.7166,11.02,8.3574 L10.17,9.207
C10.197,8.7574,10.151,8.4573,9.8633,8.0508 L10.287,7.625
C10.562,7.3498,10.539,6.9967,10.289,6.709
C10.019,6.4391,9.645,6.4388,9.373,6.7109 L7.7266,8.3574
C7.4437,8.6404,7.431,8.9797,7.7246,9.2734 L6.9941,10.006
C6.7069,9.7186,6.5083,9.3329,6.4824,8.8984
C6.4568,8.464,6.6281,7.9913,6.9941,7.625 L8.6406,5.9766
C8.9651,5.6619,9.4004,5.5019,9.834,5.5 Z M9.0078,7.9902
C9.296,8.2773,9.4947,8.6645,9.5195,9.0996
C9.5449,9.5348,9.3746,10.006,9.0078,10.373 L7.3594,12.02
C6.7198,12.659,5.6199,12.659,4.9805,12.02
C4.3409,11.38,4.339,10.282,4.9805,9.6406 L5.8418,8.7773
C5.8155,9.2266,5.8645,9.5278,6.1523,9.9336 L5.7129,10.373
C5.4541,10.632,5.3887,10.963,5.7129,11.287
C5.9567,11.531,6.2686,11.594,6.6289,11.287 L8.2754,9.6406
C8.5401,9.3758,8.562,9.0075,8.2773,8.7227 L9.0078,7.9902 Z" />
</vector>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#0082c9"
android:pathData="M1.5,2 C1.25,2,1,2.25,1,2.5 L1,13.5 C1,13.76,1.24,14,1.5,14 L14.5,14
C14.76,14,15,13.759,15,13.5 L15,4.5 C15,4.25,14.75,4,14.5,4 L8,4 L6,2 L1.5,2 Z
M10.25,5.5 A1.25,1.25,0,0,1,11.5,6.75 A1.25,1.25,0,0,1,10.25,8
A1.25,1.25,0,0,1,9.4492,7.709 L6.998,8.9355 A1.25,1.25,0,0,1,7,9
A1.25,1.25,0,0,1,6.9961,9.0645 L9.4492,10.291 A1.25,1.25,0,0,1,10.25,10
A1.25,1.25,0,0,1,11.5,11.25 A1.25,1.25,0,0,1,10.25,12.5 A1.25,1.25,0,0,1,9,11.25
A1.25,1.25,0,0,1,9.0039,11.186 L6.5508,9.959 A1.25,1.25,0,0,1,5.75,10.25
A1.25,1.25,0,0,1,4.5,9 A1.25,1.25,0,0,1,5.75,7.75 A1.25,1.25,0,0,1,6.5508,8.041
L9.002,6.8145 A1.25,1.25,0,0,1,9,6.75 A1.25,1.25,0,0,1,10.25,5.5 Z" />
</vector>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#0082c9"
android:pathData="M1.5,2 C1.25,2,1,2.25,1,2.5 L1,13.5 C1,13.76,1.24,14,1.5,14 L14.5,14
C14.76,14,15,13.759,15,13.5 L15,4.5 C15,4.25,14.75,4,14.5,4 L8,4 L6,2 L1.5,2 Z
M8,5.25 L9.1,7.9004 L12,8.125 L9.75,10 L10.5,12.75 L8,11.199 L5.5,12.75 L6.25,10
L4,8.125 L6.9,7.9004 L8,5.25 Z" />
</vector>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#969696"
android:pathData="M1.5,2 C1.3,2,1,2.3,1,2.5 L1,13.5 C1,13.7,1.3,14,1.5,14 L14.5,14
C14.7,14,15,13.7,15,13.5 L15,2.5 C15,2.3,14.7,2,14.5,2 Z M2,3 L14,3 L14,8 L13,7
L10,11 L7,8 L3,12 L2,12 Z M4.5,4 C3.67,4,3,4.67,3,5.5 S3.67,7,4.5,7
S6,6.33,6,5.5 S5.33,4,4.5,4 Z" />
</vector>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#969696"
android:pathData="M7.95,0.65 C3.85,0.65,0.55,3.95,0.55,8.05 S3.85,15.45,7.95,15.45
S15.35,12.15,15.35,8.05 S12.05,0.65,7.95,0.65 Z M8.75,1.55
C10.05,1.55,11.15,2.35,12.25,2.85 L14.05,5.35 L13.75,6.45 L14.35,6.75
L14.35,9.15 C14.15,9.85,13.75,10.45,13.45,11.15
C13.25,11.25,13.45,10.35,13.35,10.15 C13.35,9.55,12.85,9.55,12.45,9.95
C12.05,10.25,11.05,10.25,10.95,9.55 C10.65,8.75,10.95,7.85,11.25,7.05
L10.65,6.35 L10.85,4.55 L10.05,3.65 L10.25,2.65 L9.25,2.05
C9.05,1.85,8.65,1.85,8.55,1.65 C8.65,1.65,8.75,1.55,8.75,1.55 Z M6.15,1.65
S6.25,1.65,6.25,1.75 C6.65,1.95,6.15,2.15,6.05,2.35
C5.55,2.65,6.35,3.05,6.55,3.35 C6.95,3.25,7.35,2.65,7.95,2.85
C8.65,2.65,8.55,3.45,9.05,3.85 C9.15,4.05,9.95,4.65,9.45,4.45
C8.95,4.05,8.45,4.05,8.15,4.55 C7.35,5.05,7.85,3.65,7.45,3.35
C6.85,2.65,7.05,3.85,7.05,4.25 C6.65,4.25,5.95,3.95,5.55,4.45 L5.95,5.05
L6.45,4.35 C6.45,4.05,6.55,4.55,6.75,4.65 C6.85,4.85,7.55,5.35,7.05,5.55
C6.25,5.95,5.65,6.65,4.95,7.25 C4.75,7.75,4.25,7.65,3.95,7.25
C3.25,6.85,3.25,7.95,3.35,8.35 L3.95,7.95 L3.95,9.05
C3.55,9.45,3.05,8.35,2.65,8.15 L2.65,6.55 C2.65,6.15,2.55,5.65,2.65,5.25
C3.45,4.35,4.35,3.35,4.85,2.25 L5.65,2.25 C6.25,2.45,5.95,1.55,6.15,1.65 Z
M4.95,9.85 C5.05,9.85,5.15,9.85,5.25,9.95 C6.05,10.05,6.65,10.65,7.25,11.05
C7.75,11.55,8.85,11.35,8.95,12.25 C8.75,13.15,7.85,13.65,7.15,13.95
C6.95,14.05,6.75,14.15,6.55,14.15 C5.85,14.35,5.55,13.55,5.35,13.05
C5.05,12.35,4.25,11.85,4.35,10.95 C4.35,10.55,4.55,9.95,4.95,9.85 Z" />
</vector>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:strokeColor="#969696"
android:strokeWidth="2"
android:pathData="M8,2 C10.2091,2,12,3.79086,12,6 C12,8.20914,10.2091,10,8,10
C5.79086,10,4,8.20914,4,6 C4,3.79086,5.79086,2,8,2 Z" />
<path
android:fillColor="#969696"
android:pathData="M4,9 L12,9 L8,15 Z" />
</vector>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#0082c9"
android:pathData="M4,3 L2,5 L2,12.5 C2,12.76,2.24,13,2.5,13 L13.5,13 C13.76,13,14,12.76,14,12.5
L14,5 L12,3 Z M5,4 L11,4 L12,5 L4,5 Z" />
</vector>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#969696"
android:pathData="M2.5,1 C2.22,1,2,1.22,2,1.5 L2,14.5 C2,14.78,2.22,15,2.5,15 L13.5,15
C13.78,15,14,14.78,14,14.5 L14,4 L11,1 L2.5,1 Z M4,3 L10,3 L10,4 L4,4 L4,3 Z
M4,6 L9,6 L9,7 L4,7 L4,6 Z M4,9 L12,9 L12,10 L4,10 L4,9 Z M4,12 L8,12 L8,13
L4,13 L4,12 Z" />
</vector>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#969696"
android:pathData="M4,1 C3.5,1,3,1.5,3,2 L3,4 C3,4.5,3.5,5,4,5 S5,4.5,5,4 L5,2 C5,1.5,4.5,1,4,1 Z
M12,1 C11.5,1,11,1.5,11,2 L11,4 C11,4.5,11.5,5,12,5 S13,4.5,13,4 L13,2
C13,1.5,12.5,1,12,1 Z M5.5,3 L5.5,4 C5.5,4.831,5,5.5,4,5.5 S2.5,5,2.5,4
L2.5,3.0625 C1.6159,3.2895,1,4.0872,1,5 L1,13 C1,14.108,1.892,15,3,15 L13,15
C14.108,15,15,14.108,15,13 L15,5 C15,4.0872,14.3841,3.2895,13.5,3.0625 L13.5,4
C13.5,4.831,13,5.5,12,5.5 S10.5,5,10.5,4 L10.5,3 Z M13,8 L13,13 L3,13 L3,8 Z" />
</vector>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:strokeColor="#969696"
android:strokeWidth="2"
android:pathData="M6.3,3.714 L1.9284,8 L6.3,12.286" />
<path
android:strokeColor="#969696"
android:strokeWidth="2"
android:pathData="M9.7,12.286 L14.072,8 L9.7,3.714" />
</vector>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#969696"
android:pathData="M10,1 C8.25,1,7,2.43,7,3.8 C7,5.2,7.1,6.2,7.8,7.3 C8,7.59,8.3,7.65,8.5,7.9
C8.635,8.4,8.74,8.9,8.6,9.4 C8.32,9.5,8.075,9.62,7.8,9.73
C7.715,9.58,7.57,9.53,7.33,9.33 C6.6,8.89,5.77,8.58,5,8.29
C4.9,7.92,4.9,7.64,5,7.29 C5.156,7.124,5.37,7.02,5.5,6.86
C5.96,6.26,6,5.206,6,4.49 C6,3.43,5.046,2.59,4,2.59 C2.83,2.59,2,3.59,2,4.49
C2,5.42,2.034,6.13,2.5,6.86 C2.63,7.06,2.867,7.12,3,7.29
C3.1,7.62,3.1,7.944,3,8.29 C2.15,8.59,1.4,8.93,0.66,9.33
C0.09,9.73,0.14,9.535,0,10.86 C-0.11,11.92,2.335,11.99,4,11.99
C4.06,11.99,4.11,11.99,4.17,11.99 C4.116,12.264,4.07,12.62,4,13.29
C3.84,14.88,7.5,14.99,10,14.99 S16.16,14.89,16,13.29
C15.785,11.29,15.77,11.58,15,10.99 C13.9,10.336,12.55,9.82,11.4,9.39
C11.25,8.83,11.36,8.42,11.5,7.89 C11.735,7.64,12,7.53,12.2,7.29
C12.9,6.405,13,4.865,13,3.79 C13,2.19,11.57,0.99,10,0.99 Z" />
</vector>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#969696"
android:pathData="M1.5,2 C1.3,2.05,1,2.29,1,2.5 L1,13.5 C1,13.73,1.274,14,1.5,14 L14.5,14
C14.84,14,15,13.74,15,13.5 L15,2.5 C15,2.16,14.751,2,14.5,2 Z M2,3 L14,3 L14,13
L2,13 Z M5,5 L5,11 L11,8 Z" />
</vector>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#49abea"
android:pathData="M2.5,1 C2.22,1,2,1.22,2,1.5 L2,14.5 C2,14.78,2.22,15,2.5,15 L13.5,15
C13.78,15,14,14.78,14,14.5 L14,4 L11,1 L2.5,1 Z M4,3 L10,3 L10,4 L4,4 L4,3 Z
M4,6 L9,6 L9,7 L4,7 L4,6 Z M4,9 L12,9 L12,10 L4,10 L4,9 Z M4,12 L8,12 L8,13
L4,13 L4,12 Z" />
</vector>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#f0965f"
android:pathData="M1.5,2 C1.25,2,1,2.25,1,2.5 L1,13.5 C1,13.75,1.25,14,1.5,14 L14.5,14
C14.75,14,15,13.75,15,13.5 L15,2.5 C15,2.25,14.75,2,14.5,2 Z M2,5 L14,5 L14,11
L2,11 Z" />
</vector>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#9abd4e"
android:pathData="M2.5,1 C2.22,1,2,1.22,2,1.5 L2,14.5 C2,14.78,2.22,15,2.5,15 L13.5,15
C13.78,15,14,14.78,14,14.5 L14,4 L11,1 L2.5,1 Z M4,4 L6,4 L6,6 L4,6 L4,4 Z M7,4
L12,4 L12,6 L7,6 L7,4 Z M4,7 L6,7 L6,9 L4,9 L4,7 Z M7,7 L12,7 L12,9 L7,9 L7,7 Z
M4,10 L6,10 L6,12 L4,12 L4,10 Z M7,10 L12,10 L12,12 L7,12 L7,10 Z" />
</vector>

Some files were not shown because too many files have changed in this diff Show More