Change lib
This commit is contained in:
parent
9a06f5660b
commit
3ea012f62e
|
@ -118,8 +118,8 @@ dependencies {
|
|||
implementation "com.github.bumptech.glide:glide:4.11.0"
|
||||
annotationProcessor "com.github.bumptech.glide:compiler:4.11.0"
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||
implementation "net.gotev:uploadservice:3.5.2"
|
||||
implementation "net.gotev:uploadservice-okhttp:3.5.2"
|
||||
implementation "net.gotev:uploadservice:4.5.0"
|
||||
implementation "net.gotev:uploadservice-okhttp:4.5.0"
|
||||
implementation "com.google.code.gson:gson:2.8.6"
|
||||
implementation 'androidx.media:media:1.2.0'
|
||||
implementation 'com.github.ybq:Android-SpinKit:1.4.0'
|
||||
|
|
|
@ -157,13 +157,6 @@
|
|||
<service
|
||||
android:name=".services.RetrieveInfoService"
|
||||
android:exported="false" />
|
||||
<receiver
|
||||
android:name=".services.PeertubeUploadReceiver"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="app.fedilab.fedilabtube.uploadservice.broadcast.status" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<provider
|
||||
android:name="androidx.work.impl.WorkManagerInitializer"
|
||||
|
|
|
@ -14,22 +14,30 @@ package app.fedilab.fedilabtube;
|
|||
* You should have received a copy of the GNU General Public License along with TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.multidex.MultiDex;
|
||||
import androidx.multidex.MultiDexApplication;
|
||||
import androidx.work.Configuration;
|
||||
import androidx.work.WorkManager;
|
||||
|
||||
import net.gotev.uploadservice.UploadService;
|
||||
import net.gotev.uploadservice.UploadServiceConfig;
|
||||
import net.gotev.uploadservice.observer.request.GlobalRequestObserver;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import app.fedilab.fedilabtube.helper.Helper;
|
||||
import app.fedilab.fedilabtube.helper.ThemeHelper;
|
||||
import app.fedilab.fedilabtube.services.GlobalUploadObserver;
|
||||
import app.fedilab.fedilabtube.worker.WorkHelper;
|
||||
|
||||
public class FedilabTube extends MultiDexApplication {
|
||||
|
||||
static String UPLOAD_CHANNEL_ID = "upload_info_peertube";
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
|
@ -44,6 +52,10 @@ public class FedilabTube extends MultiDexApplication {
|
|||
if (interval >= 15) {
|
||||
WorkHelper.fetchNotifications(this, interval);
|
||||
}
|
||||
createNotificationChannel();
|
||||
UploadServiceConfig.initialize(FedilabTube.this, UPLOAD_CHANNEL_ID, true);
|
||||
|
||||
new GlobalRequestObserver(this, new GlobalUploadObserver());
|
||||
}
|
||||
|
||||
|
||||
|
@ -52,8 +64,6 @@ public class FedilabTube extends MultiDexApplication {
|
|||
super.attachBaseContext(base);
|
||||
|
||||
MultiDex.install(FedilabTube.this);
|
||||
|
||||
UploadService.NAMESPACE = BuildConfig.APPLICATION_ID;
|
||||
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
|
||||
int themePref = sharedpreferences.getInt(Helper.SET_THEME, Helper.DEFAULT_MODE);
|
||||
ThemeHelper.switchTo(themePref);
|
||||
|
@ -61,5 +71,13 @@ public class FedilabTube extends MultiDexApplication {
|
|||
|
||||
}
|
||||
|
||||
|
||||
private void createNotificationChannel() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel(UPLOAD_CHANNEL_ID,
|
||||
getString(R.string.notification_channel_name),
|
||||
NotificationManager.IMPORTANCE_LOW);
|
||||
channel.setSound(null, null);
|
||||
((NotificationManager) Objects.requireNonNull(getSystemService(Context.NOTIFICATION_SERVICE))).createNotificationChannel(channel);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,10 +21,10 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
|
@ -38,20 +38,23 @@ import android.widget.Toast;
|
|||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import net.gotev.uploadservice.MultipartUploadRequest;
|
||||
import net.gotev.uploadservice.UploadNotificationAction;
|
||||
import net.gotev.uploadservice.UploadNotificationConfig;
|
||||
|
||||
import java.io.File;
|
||||
import net.gotev.uploadservice.data.UploadNotificationAction;
|
||||
import net.gotev.uploadservice.data.UploadNotificationConfig;
|
||||
import net.gotev.uploadservice.data.UploadNotificationStatusConfig;
|
||||
import net.gotev.uploadservice.extensions.ContextExtensionsKt;
|
||||
import net.gotev.uploadservice.protocols.multipart.MultipartUploadRequest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import app.fedilab.fedilabtube.client.APIResponse;
|
||||
import app.fedilab.fedilabtube.client.data.ChannelData;
|
||||
|
@ -110,32 +113,17 @@ public class PeertubeUploadActivity extends AppCompatActivity {
|
|||
return;
|
||||
}
|
||||
set_upload_submit.setEnabled(true);
|
||||
|
||||
uri = data.getData();
|
||||
|
||||
String uriString = uri.toString();
|
||||
File myFile = new File(uriString);
|
||||
filename = null;
|
||||
if (uriString.startsWith("content://")) {
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = getContentResolver().query(uri, null, null, null, null);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
|
||||
}
|
||||
} finally {
|
||||
assert cursor != null;
|
||||
cursor.close();
|
||||
}
|
||||
} else if (uriString.startsWith("file://")) {
|
||||
filename = myFile.getName();
|
||||
DocumentFile documentFile = DocumentFile.fromSingleUri(this, uri);
|
||||
if (documentFile != null) {
|
||||
filename = documentFile.getName();
|
||||
}
|
||||
if (filename == null) {
|
||||
filename = new Date().toString();
|
||||
}
|
||||
set_upload_file_name.setVisibility(View.VISIBLE);
|
||||
set_upload_file_name.setText(filename);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -245,7 +233,7 @@ public class PeertubeUploadActivity extends AppCompatActivity {
|
|||
MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
|
||||
return;
|
||||
}
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType("*/*");
|
||||
String[] mimetypes = {"video/*"};
|
||||
|
@ -289,34 +277,19 @@ public class PeertubeUploadActivity extends AppCompatActivity {
|
|||
try {
|
||||
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
|
||||
String token = sharedpreferences.getString(Helper.PREF_KEY_OAUTH_TOKEN, null);
|
||||
UploadNotificationConfig uploadConfig = new UploadNotificationConfig();
|
||||
Intent in = new Intent(PeertubeUploadActivity.this, PeertubeEditUploadActivity.class);
|
||||
PendingIntent clickIntent = PendingIntent.getActivity(PeertubeUploadActivity.this, 1, in, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
uploadConfig
|
||||
.setClearOnActionForAllStatuses(true);
|
||||
|
||||
|
||||
uploadConfig.getProgress().message = getString(R.string.uploading);
|
||||
uploadConfig.getCompleted().message = getString(R.string.upload_video_success);
|
||||
uploadConfig.getError().message = getString(R.string.toast_error);
|
||||
uploadConfig.getCancelled().message = getString(R.string.toast_cancelled);
|
||||
uploadConfig.getCompleted().actions.add(new UploadNotificationAction(R.drawable.ic_baseline_check_24, getString(R.string.video_uploaded_action), clickIntent));
|
||||
|
||||
if (video_title != null && video_title.getText() != null && video_title.getText().toString().trim().length() > 0) {
|
||||
filename = video_title.getText().toString().trim();
|
||||
}
|
||||
String uploadId = UUID.randomUUID().toString();
|
||||
new MultipartUploadRequest(PeertubeUploadActivity.this, uploadId, "https://" + Helper.getLiveInstance(PeertubeUploadActivity.this) + "/api/v1/videos/upload")
|
||||
.addFileToUpload(uri.toString().replace("file://", ""), "videofile")
|
||||
.addHeader("Authorization", "Bearer " + token)
|
||||
.setNotificationConfig(uploadConfig)
|
||||
.addParameter("name", filename)
|
||||
.addParameter("channelId", idChannel)
|
||||
new MultipartUploadRequest(PeertubeUploadActivity.this, "https://" + Helper.getLiveInstance(PeertubeUploadActivity.this) + "/api/v1/videos/upload")
|
||||
.setMethod("POST")
|
||||
.setBearerAuth(token)
|
||||
.addHeader("User-Agent", getString(R.string.app_name) + "/" + BuildConfig.VERSION_NAME)
|
||||
.addParameter("privacy", String.valueOf(idPrivacy))
|
||||
.addParameter("nsfw", "false")
|
||||
.addParameter("commentsEnabled", "true")
|
||||
.addParameter("downloadEnabled", "true")
|
||||
.addParameter("waitTranscoding", "true")
|
||||
.setMaxRetries(3)
|
||||
.addParameter("channelId", idChannel)
|
||||
.addFileToUpload(uri.toString(), "videofile", filename)
|
||||
.setNotificationConfig((context, uploadId) -> getNotificationConfig(uploadId))
|
||||
.setMaxRetries(2)
|
||||
.startUpload();
|
||||
finish();
|
||||
} catch (Exception exc) {
|
||||
|
@ -325,4 +298,83 @@ public class PeertubeUploadActivity extends AppCompatActivity {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
UploadNotificationConfig getNotificationConfig(String uploadId) {
|
||||
PendingIntent clickIntent = PendingIntent.getActivity(
|
||||
PeertubeUploadActivity.this, 1, new Intent(this, PeertubeUploadActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
final boolean autoClear = false;
|
||||
final Bitmap largeIcon = null;
|
||||
final boolean clearOnAction = true;
|
||||
final boolean ringToneEnabled = true;
|
||||
final ArrayList<UploadNotificationAction> noActions = new ArrayList<>(1);
|
||||
|
||||
final UploadNotificationAction cancelAction = new UploadNotificationAction(
|
||||
R.drawable.ic_baseline_cancel_24,
|
||||
getString(R.string.cancel),
|
||||
ContextExtensionsKt.getCancelUploadIntent(this, uploadId)
|
||||
);
|
||||
|
||||
final UploadNotificationAction successAction = new UploadNotificationAction(
|
||||
R.drawable.ic_baseline_cancel_24,
|
||||
getString(R.string.video_uploaded_action),
|
||||
clickIntent
|
||||
);
|
||||
|
||||
final ArrayList<UploadNotificationAction> progressActions = new ArrayList<>(1);
|
||||
progressActions.add(cancelAction);
|
||||
|
||||
UploadNotificationStatusConfig progress = new UploadNotificationStatusConfig(
|
||||
getString(R.string.app_name),
|
||||
getString(R.string.uploading),
|
||||
R.drawable.ic_baseline_cloud_upload_24,
|
||||
Color.BLUE,
|
||||
largeIcon,
|
||||
clickIntent,
|
||||
progressActions,
|
||||
clearOnAction,
|
||||
autoClear
|
||||
);
|
||||
|
||||
final ArrayList<UploadNotificationAction> successActions = new ArrayList<>(1);
|
||||
progressActions.add(successAction);
|
||||
|
||||
UploadNotificationStatusConfig success = new UploadNotificationStatusConfig(
|
||||
getString(R.string.app_name),
|
||||
getString(R.string.upload_video_success),
|
||||
R.drawable.ic_baseline_check_24,
|
||||
Color.GREEN,
|
||||
largeIcon,
|
||||
clickIntent,
|
||||
successActions,
|
||||
clearOnAction,
|
||||
autoClear
|
||||
);
|
||||
|
||||
|
||||
UploadNotificationStatusConfig error = new UploadNotificationStatusConfig(
|
||||
getString(R.string.app_name),
|
||||
getString(R.string.toast_error),
|
||||
R.drawable.ic_baseline_error_24,
|
||||
Color.RED,
|
||||
largeIcon,
|
||||
clickIntent,
|
||||
noActions,
|
||||
clearOnAction,
|
||||
autoClear
|
||||
);
|
||||
|
||||
UploadNotificationStatusConfig cancelled = new UploadNotificationStatusConfig(
|
||||
getString(R.string.app_name),
|
||||
getString(R.string.toast_cancelled),
|
||||
R.drawable.ic_baseline_cancel_24,
|
||||
Color.YELLOW,
|
||||
largeIcon,
|
||||
clickIntent,
|
||||
noActions,
|
||||
clearOnAction
|
||||
);
|
||||
|
||||
return new UploadNotificationConfig(FedilabTube.UPLOAD_CHANNEL_ID, ringToneEnabled, progress, success, error, cancelled);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,7 +130,6 @@ public class Helper {
|
|||
public static final String APP_PREFS = "app_prefs";
|
||||
|
||||
public static final int VIDEOS_PER_PAGE = 10;
|
||||
public static final String INTENT_ADD_UPLOADED_MEDIA = "intent_add_uploaded_media";
|
||||
public static final String RECEIVE_ACTION = "receive_action";
|
||||
public static final String SET_UNFOLLOW_VALIDATION = "set_unfollow_validation";
|
||||
//List of available academies
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
package app.fedilab.fedilabtube.services;
|
||||
/* Copyright 2020 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* TubeLab 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 TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import net.gotev.uploadservice.data.UploadInfo;
|
||||
import net.gotev.uploadservice.network.ServerResponse;
|
||||
import net.gotev.uploadservice.observer.request.RequestObserverDelegate;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import app.fedilab.fedilabtube.helper.Helper;
|
||||
|
||||
public class GlobalUploadObserver implements RequestObserverDelegate {
|
||||
|
||||
@Override
|
||||
public void onCompleted(@NotNull Context context, @NotNull UploadInfo uploadInfo) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompletedWhileNotObserving() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NotNull Context context, @NotNull UploadInfo uploadInfo, @NotNull Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgress(@NotNull Context context, @NotNull UploadInfo uploadInfo) {
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
@Override
|
||||
public void onSuccess(@NotNull Context context, @NotNull UploadInfo uploadInfo, @NotNull ServerResponse serverResponse) {
|
||||
try {
|
||||
JSONObject response = new JSONObject(serverResponse.getBodyString());
|
||||
|
||||
if (response.has("video")) {
|
||||
String videoUuid = response.getJSONObject("video").getString("uuid");
|
||||
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = sharedpreferences.edit();
|
||||
editor.putString(Helper.VIDEO_ID, videoUuid);
|
||||
editor.commit();
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
package app.fedilab.fedilabtube.services;
|
||||
/* Copyright 2020 Thomas Schneider
|
||||
*
|
||||
* This file is a part of TubeLab
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* TubeLab 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 TubeLab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import net.gotev.uploadservice.ServerResponse;
|
||||
import net.gotev.uploadservice.UploadInfo;
|
||||
import net.gotev.uploadservice.UploadServiceBroadcastReceiver;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import app.fedilab.fedilabtube.helper.Helper;
|
||||
|
||||
|
||||
public class PeertubeUploadReceiver extends UploadServiceBroadcastReceiver {
|
||||
|
||||
|
||||
@Override
|
||||
public void onProgress(Context context, UploadInfo uploadInfo) {
|
||||
// your code here
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Context context, UploadInfo uploadInfo, ServerResponse serverResponse,
|
||||
Exception exception) {
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
@Override
|
||||
public void onCompleted(Context context, UploadInfo uploadInfo, ServerResponse serverResponse) {
|
||||
try {
|
||||
JSONObject response = new JSONObject(serverResponse.getBodyAsString());
|
||||
|
||||
if (!response.has("video")) { //IT's not from Peertube
|
||||
ArrayList<String> file = uploadInfo.getSuccessfullyUploadedFiles();
|
||||
Intent addMedia = new Intent(Helper.INTENT_ADD_UPLOADED_MEDIA);
|
||||
addMedia.putExtra("response", serverResponse.getBodyAsString());
|
||||
addMedia.putStringArrayListExtra("uploadInfo", file);
|
||||
LocalBroadcastManager.getInstance(context).sendBroadcast(addMedia);
|
||||
} else {
|
||||
String videoID = response.getJSONObject("video").get("id").toString();
|
||||
SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = sharedpreferences.edit();
|
||||
editor.putString(Helper.VIDEO_ID, videoID);
|
||||
editor.apply();
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancelled(Context context, UploadInfo uploadInfo) {
|
||||
// your code here
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM17,15.59L15.59,17 12,13.41 8.41,17 7,15.59 10.59,12 7,8.41 8.41,7 12,10.59 15.59,7 17,8.41 13.41,12 17,15.59z" />
|
||||
</vector>
|
|
@ -1,8 +1,8 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-2h2v2zM13,13h-2L11,7h2v6z" />
|
||||
</vector>
|
Loading…
Reference in New Issue