@codebymanan/react-native-photo-editor 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/PhotoEditor.podspec +23 -0
- package/README.md +200 -0
- package/android/build.gradle +65 -0
- package/android/src/main/AndroidManifest.xml +14 -0
- package/android/src/main/assets/beyond_wonderland.ttf +0 -0
- package/android/src/main/assets/emojione-android.ttf +0 -0
- package/android/src/main/assets/filters/auto_fix.png +0 -0
- package/android/src/main/assets/filters/b_n_w.png +0 -0
- package/android/src/main/assets/filters/brightness.png +0 -0
- package/android/src/main/assets/filters/contrast.png +0 -0
- package/android/src/main/assets/filters/cross_process.png +0 -0
- package/android/src/main/assets/filters/documentary.png +0 -0
- package/android/src/main/assets/filters/dual_tone.png +0 -0
- package/android/src/main/assets/filters/fill_light.png +0 -0
- package/android/src/main/assets/filters/fish_eye.png +0 -0
- package/android/src/main/assets/filters/flip_horizental.png +0 -0
- package/android/src/main/assets/filters/flip_vertical.png +0 -0
- package/android/src/main/assets/filters/grain.png +0 -0
- package/android/src/main/assets/filters/gray_scale.png +0 -0
- package/android/src/main/assets/filters/lomish.png +0 -0
- package/android/src/main/assets/filters/negative.png +0 -0
- package/android/src/main/assets/filters/original.jpg +0 -0
- package/android/src/main/assets/filters/posterize.png +0 -0
- package/android/src/main/assets/filters/rotate.png +0 -0
- package/android/src/main/assets/filters/saturate.png +0 -0
- package/android/src/main/assets/filters/sepia.png +0 -0
- package/android/src/main/assets/filters/sharpen.png +0 -0
- package/android/src/main/assets/filters/temprature.png +0 -0
- package/android/src/main/assets/filters/tint.png +0 -0
- package/android/src/main/assets/filters/vignette.png +0 -0
- package/android/src/main/java/com/photoeditor/PhotoEditorModule.kt +130 -0
- package/android/src/main/java/com/photoeditor/PhotoEditorPackage.kt +31 -0
- package/android/src/main/java/com/photoeditor/editor/ColorPickerAdapter.kt +100 -0
- package/android/src/main/java/com/photoeditor/editor/EditImageActivity.kt +407 -0
- package/android/src/main/java/com/photoeditor/editor/EditorLocale.kt +41 -0
- package/android/src/main/java/com/photoeditor/editor/EditorStrings.kt +46 -0
- package/android/src/main/java/com/photoeditor/editor/EmojiBSFragment.kt +121 -0
- package/android/src/main/java/com/photoeditor/editor/PropertiesBSFragment.kt +76 -0
- package/android/src/main/java/com/photoeditor/editor/ShapeBSFragment.kt +112 -0
- package/android/src/main/java/com/photoeditor/editor/StickerBSFragment.kt +130 -0
- package/android/src/main/java/com/photoeditor/editor/TextEditorDialogFragment.kt +133 -0
- package/android/src/main/java/com/photoeditor/editor/base/BaseActivity.kt +67 -0
- package/android/src/main/java/com/photoeditor/editor/base/BaseFragment.kt +10 -0
- package/android/src/main/java/com/photoeditor/editor/filters/FilterListener.kt +7 -0
- package/android/src/main/java/com/photoeditor/editor/filters/FilterViewAdapter.kt +105 -0
- package/android/src/main/java/com/photoeditor/editor/tools/EditingToolsAdapter.kt +70 -0
- package/android/src/main/java/com/photoeditor/editor/tools/ToolType.kt +10 -0
- package/android/src/main/res/drawable/pe_blank_image.jpg +0 -0
- package/android/src/main/res/drawable/pe_ic_brush.xml +9 -0
- package/android/src/main/res/drawable/pe_ic_close.xml +9 -0
- package/android/src/main/res/drawable/pe_ic_eraser.xml +4 -0
- package/android/src/main/res/drawable/pe_ic_insert_emoticon.xml +9 -0
- package/android/src/main/res/drawable/pe_ic_oval.xml +9 -0
- package/android/src/main/res/drawable/pe_ic_photo_filter.xml +5 -0
- package/android/src/main/res/drawable/pe_ic_rectangle.xml +9 -0
- package/android/src/main/res/drawable/pe_ic_redo.xml +10 -0
- package/android/src/main/res/drawable/pe_ic_redo_disabled.xml +10 -0
- package/android/src/main/res/drawable/pe_ic_save.xml +9 -0
- package/android/src/main/res/drawable/pe_ic_sticker.xml +9 -0
- package/android/src/main/res/drawable/pe_ic_text.xml +9 -0
- package/android/src/main/res/drawable/pe_ic_undo.xml +10 -0
- package/android/src/main/res/drawable/pe_ic_undo_disabled.xml +10 -0
- package/android/src/main/res/drawable/pe_original.jpg +0 -0
- package/android/src/main/res/drawable/pe_redo.xml +6 -0
- package/android/src/main/res/drawable/pe_rounded_border_text_view.xml +14 -0
- package/android/src/main/res/drawable/pe_undo.xml +6 -0
- package/android/src/main/res/font/pe_roboto_medium.xml +7 -0
- package/android/src/main/res/layout/pe_activity_edit_image.xml +111 -0
- package/android/src/main/res/layout/pe_add_text_dialog.xml +56 -0
- package/android/src/main/res/layout/pe_color_picker_item_list.xml +15 -0
- package/android/src/main/res/layout/pe_fragment_bottom_properties_dialog.xml +77 -0
- package/android/src/main/res/layout/pe_fragment_bottom_shapes_dialog.xml +135 -0
- package/android/src/main/res/layout/pe_fragment_bottom_sticker_emoji_dialog.xml +62 -0
- package/android/src/main/res/layout/pe_row_editing_tools.xml +34 -0
- package/android/src/main/res/layout/pe_row_emoji.xml +17 -0
- package/android/src/main/res/layout/pe_row_filter_view.xml +35 -0
- package/android/src/main/res/layout/pe_row_sticker.xml +23 -0
- package/android/src/main/res/values/colors.xml +22 -0
- package/android/src/main/res/values/dimens.xml +7 -0
- package/android/src/main/res/values/font_certs.xml +17 -0
- package/android/src/main/res/values/preloaded_fonts.xml +6 -0
- package/android/src/main/res/values/strings.xml +462 -0
- package/android/src/main/res/values/styles.xml +28 -0
- package/ios/PhotoEditor.h +5 -0
- package/ios/PhotoEditor.mm +58 -0
- package/ios/PhotoEditorManager.swift +164 -0
- package/lib/module/NativePhotoEditor.js +5 -0
- package/lib/module/NativePhotoEditor.js.map +1 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/open.js +6 -0
- package/lib/module/open.js.map +1 -0
- package/lib/module/open.native.js +7 -0
- package/lib/module/open.native.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativePhotoEditor.d.ts +14 -0
- package/lib/typescript/src/NativePhotoEditor.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +3 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/open.d.ts +3 -0
- package/lib/typescript/src/open.d.ts.map +1 -0
- package/lib/typescript/src/open.native.d.ts +3 -0
- package/lib/typescript/src/open.native.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +39 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +128 -0
- package/src/NativePhotoEditor.ts +12 -0
- package/src/index.tsx +2 -0
- package/src/open.native.tsx +6 -0
- package/src/open.tsx +7 -0
- package/src/types.ts +36 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
package com.photoeditor.editor
|
|
2
|
+
|
|
3
|
+
import com.photoeditor.R
|
|
4
|
+
|
|
5
|
+
import android.os.Bundle
|
|
6
|
+
import android.view.LayoutInflater
|
|
7
|
+
import android.view.View
|
|
8
|
+
import android.view.ViewGroup
|
|
9
|
+
import android.widget.RadioGroup
|
|
10
|
+
import android.widget.SeekBar
|
|
11
|
+
import androidx.recyclerview.widget.LinearLayoutManager
|
|
12
|
+
import androidx.recyclerview.widget.RecyclerView
|
|
13
|
+
import com.photoeditor.editor.ColorPickerAdapter.OnColorPickerClickListener
|
|
14
|
+
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
|
15
|
+
import ja.burhanrashid52.photoeditor.shape.ShapeType
|
|
16
|
+
import android.widget.RadioButton
|
|
17
|
+
import android.widget.TextView
|
|
18
|
+
|
|
19
|
+
class ShapeBSFragment : BottomSheetDialogFragment(), SeekBar.OnSeekBarChangeListener {
|
|
20
|
+
private var mProperties: Properties? = null
|
|
21
|
+
|
|
22
|
+
interface Properties {
|
|
23
|
+
fun onColorChanged(colorCode: Int)
|
|
24
|
+
fun onOpacityChanged(opacity: Int)
|
|
25
|
+
fun onShapeSizeChanged(shapeSize: Int)
|
|
26
|
+
fun onShapePicked(shapeType: ShapeType)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
override fun onCreateView(
|
|
30
|
+
inflater: LayoutInflater,
|
|
31
|
+
container: ViewGroup?,
|
|
32
|
+
savedInstanceState: Bundle?
|
|
33
|
+
): View? {
|
|
34
|
+
return inflater.inflate(R.layout.pe_fragment_bottom_shapes_dialog, container, false)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
38
|
+
super.onViewCreated(view, savedInstanceState)
|
|
39
|
+
val rvColor: RecyclerView = view.findViewById(R.id.shapeColors)
|
|
40
|
+
val sbOpacity = view.findViewById<SeekBar>(R.id.shapeOpacity)
|
|
41
|
+
val sbBrushSize = view.findViewById<SeekBar>(R.id.shapeSize)
|
|
42
|
+
val shapeGroup = view.findViewById<RadioGroup>(R.id.shapeRadioGroup)
|
|
43
|
+
|
|
44
|
+
view.findViewById<RadioButton>(R.id.brushRadioButton).setEditorText(R.string.pe_label_brush)
|
|
45
|
+
view.findViewById<RadioButton>(R.id.lineRadioButton).setEditorText(R.string.pe_label_line)
|
|
46
|
+
view.findViewById<RadioButton>(R.id.arrowRadioButton).setEditorText(R.string.pe_label_arrow)
|
|
47
|
+
view.findViewById<RadioButton>(R.id.ovalRadioButton).setEditorText(R.string.pe_label_oval)
|
|
48
|
+
view.findViewById<RadioButton>(R.id.rectRadioButton).setEditorText(R.string.pe_label_rectangle)
|
|
49
|
+
view.findViewById<TextView>(R.id.txtShapeSize).setEditorText(R.string.pe_label_brush)
|
|
50
|
+
view.findViewById<TextView>(R.id.txtOpacity).setEditorText(R.string.pe_label_opacity)
|
|
51
|
+
view.findViewById<TextView>(R.id.shapeType).setEditorText(R.string.pe_label_shape)
|
|
52
|
+
|
|
53
|
+
// shape picker
|
|
54
|
+
shapeGroup.setOnCheckedChangeListener { _: RadioGroup?, checkedId: Int ->
|
|
55
|
+
when (checkedId) {
|
|
56
|
+
R.id.lineRadioButton -> {
|
|
57
|
+
mProperties!!.onShapePicked(ShapeType.Line)
|
|
58
|
+
}
|
|
59
|
+
R.id.arrowRadioButton -> {
|
|
60
|
+
mProperties!!.onShapePicked(ShapeType.Arrow())
|
|
61
|
+
}
|
|
62
|
+
R.id.ovalRadioButton -> {
|
|
63
|
+
mProperties!!.onShapePicked(ShapeType.Oval)
|
|
64
|
+
}
|
|
65
|
+
R.id.rectRadioButton -> {
|
|
66
|
+
mProperties!!.onShapePicked(ShapeType.Rectangle)
|
|
67
|
+
}
|
|
68
|
+
else -> {
|
|
69
|
+
mProperties!!.onShapePicked(ShapeType.Brush)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
sbOpacity.setOnSeekBarChangeListener(this)
|
|
74
|
+
sbBrushSize.setOnSeekBarChangeListener(this)
|
|
75
|
+
|
|
76
|
+
val activity = requireActivity()
|
|
77
|
+
|
|
78
|
+
// TODO(lucianocheng): Move layoutManager to a xml file.
|
|
79
|
+
val layoutManager = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
|
|
80
|
+
rvColor.layoutManager = layoutManager
|
|
81
|
+
rvColor.setHasFixedSize(true)
|
|
82
|
+
val colorPickerAdapter = ColorPickerAdapter(activity)
|
|
83
|
+
colorPickerAdapter.setOnColorPickerClickListener(object : OnColorPickerClickListener {
|
|
84
|
+
override fun onColorPickerClickListener(colorCode: Int) {
|
|
85
|
+
if (mProperties != null) {
|
|
86
|
+
dismiss()
|
|
87
|
+
mProperties!!.onColorChanged(colorCode)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
rvColor.adapter = colorPickerAdapter
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
fun setPropertiesChangeListener(properties: Properties?) {
|
|
95
|
+
mProperties = properties
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) {
|
|
99
|
+
when (seekBar.id) {
|
|
100
|
+
R.id.shapeOpacity -> if (mProperties != null) {
|
|
101
|
+
mProperties!!.onOpacityChanged(i)
|
|
102
|
+
}
|
|
103
|
+
R.id.shapeSize -> if (mProperties != null) {
|
|
104
|
+
mProperties!!.onShapeSizeChanged(i)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
override fun onStartTrackingTouch(seekBar: SeekBar) = Unit
|
|
110
|
+
|
|
111
|
+
override fun onStopTrackingTouch(seekBar: SeekBar) = Unit
|
|
112
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
package com.photoeditor.editor
|
|
2
|
+
|
|
3
|
+
import com.photoeditor.R
|
|
4
|
+
|
|
5
|
+
import android.annotation.SuppressLint
|
|
6
|
+
import android.app.Dialog
|
|
7
|
+
import android.graphics.Bitmap
|
|
8
|
+
import android.graphics.drawable.Drawable
|
|
9
|
+
import android.view.LayoutInflater
|
|
10
|
+
import android.view.View
|
|
11
|
+
import android.view.ViewGroup
|
|
12
|
+
import android.widget.ImageView
|
|
13
|
+
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
|
14
|
+
import androidx.recyclerview.widget.GridLayoutManager
|
|
15
|
+
import androidx.recyclerview.widget.RecyclerView
|
|
16
|
+
import com.bumptech.glide.Glide
|
|
17
|
+
import com.bumptech.glide.request.target.CustomTarget
|
|
18
|
+
import com.bumptech.glide.request.transition.Transition
|
|
19
|
+
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
|
20
|
+
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
|
|
21
|
+
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
|
22
|
+
import android.widget.TextView
|
|
23
|
+
|
|
24
|
+
class StickerBSFragment : BottomSheetDialogFragment() {
|
|
25
|
+
private var mStickerListener: StickerListener? = null
|
|
26
|
+
private var stickerPathList: List<String> = DEFAULT_STICKERS
|
|
27
|
+
|
|
28
|
+
fun setStickerListener(stickerListener: StickerListener?) {
|
|
29
|
+
mStickerListener = stickerListener
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
fun setStickers(stickers: List<String>) {
|
|
33
|
+
if (stickers.isNotEmpty()) {
|
|
34
|
+
stickerPathList = stickers
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface StickerListener {
|
|
39
|
+
fun onStickerClick(bitmap: Bitmap)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private val mBottomSheetBehaviorCallback: BottomSheetCallback = object : BottomSheetCallback() {
|
|
43
|
+
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
|
44
|
+
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
|
|
45
|
+
dismiss()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
override fun onSlide(bottomSheet: View, slideOffset: Float) {}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@SuppressLint("RestrictedApi")
|
|
53
|
+
override fun setupDialog(dialog: Dialog, style: Int) {
|
|
54
|
+
super.setupDialog(dialog, style)
|
|
55
|
+
val contentView = View.inflate(context, R.layout.pe_fragment_bottom_sticker_emoji_dialog, null)
|
|
56
|
+
dialog.setContentView(contentView)
|
|
57
|
+
val params = (contentView.parent as View).layoutParams as CoordinatorLayout.LayoutParams
|
|
58
|
+
val behavior = params.behavior
|
|
59
|
+
if (behavior != null && behavior is BottomSheetBehavior<*>) {
|
|
60
|
+
behavior.setBottomSheetCallback(mBottomSheetBehaviorCallback)
|
|
61
|
+
}
|
|
62
|
+
(contentView.parent as View).setBackgroundColor(resources.getColor(android.R.color.transparent))
|
|
63
|
+
val rvEmoji: RecyclerView = contentView.findViewById(R.id.rvEmoji)
|
|
64
|
+
|
|
65
|
+
contentView.findViewById<TextView>(R.id.txtClose).setEditorText(R.string.pe_label_close)
|
|
66
|
+
contentView.findViewById<TextView>(R.id.txtDone).setEditorText(R.string.pe_label_done)
|
|
67
|
+
val gridLayoutManager = GridLayoutManager(activity, 3)
|
|
68
|
+
rvEmoji.layoutManager = gridLayoutManager
|
|
69
|
+
val stickerAdapter = StickerAdapter()
|
|
70
|
+
rvEmoji.adapter = stickerAdapter
|
|
71
|
+
rvEmoji.setHasFixedSize(true)
|
|
72
|
+
rvEmoji.setItemViewCacheSize(stickerPathList.size)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
inner class StickerAdapter : RecyclerView.Adapter<StickerAdapter.ViewHolder>() {
|
|
76
|
+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
|
77
|
+
val view = LayoutInflater.from(parent.context).inflate(R.layout.pe_row_sticker, parent, false)
|
|
78
|
+
return ViewHolder(view)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
|
82
|
+
// Load sticker image from remote url
|
|
83
|
+
Glide.with(requireContext())
|
|
84
|
+
.asBitmap()
|
|
85
|
+
.load(stickerPathList[position])
|
|
86
|
+
.into(holder.imgSticker)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
override fun getItemCount(): Int {
|
|
90
|
+
return stickerPathList.size
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
|
94
|
+
val imgSticker: ImageView = itemView.findViewById(R.id.imgSticker)
|
|
95
|
+
|
|
96
|
+
init {
|
|
97
|
+
itemView.setOnClickListener {
|
|
98
|
+
if (mStickerListener != null) {
|
|
99
|
+
Glide.with(requireContext())
|
|
100
|
+
.asBitmap()
|
|
101
|
+
.load(stickerPathList[layoutPosition])
|
|
102
|
+
.into(object : CustomTarget<Bitmap?>(256, 256) {
|
|
103
|
+
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap?>?) {
|
|
104
|
+
mStickerListener!!.onStickerClick(resource)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
override fun onLoadCleared(placeholder: Drawable?) {}
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
dismiss()
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
companion object {
|
|
117
|
+
// Image Urls from flaticon(https://www.flaticon.com/stickers-pack/food-289)
|
|
118
|
+
private val DEFAULT_STICKERS = listOf(
|
|
119
|
+
"https://cdn-icons-png.flaticon.com/256/4392/4392452.png",
|
|
120
|
+
"https://cdn-icons-png.flaticon.com/256/4392/4392455.png",
|
|
121
|
+
"https://cdn-icons-png.flaticon.com/256/4392/4392459.png",
|
|
122
|
+
"https://cdn-icons-png.flaticon.com/256/4392/4392462.png",
|
|
123
|
+
"https://cdn-icons-png.flaticon.com/256/4392/4392465.png",
|
|
124
|
+
"https://cdn-icons-png.flaticon.com/256/4392/4392467.png",
|
|
125
|
+
"https://cdn-icons-png.flaticon.com/256/4392/4392469.png",
|
|
126
|
+
"https://cdn-icons-png.flaticon.com/256/4392/4392471.png",
|
|
127
|
+
"https://cdn-icons-png.flaticon.com/256/4392/4392522.png",
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
package com.photoeditor.editor
|
|
2
|
+
|
|
3
|
+
import com.photoeditor.R
|
|
4
|
+
|
|
5
|
+
import android.content.Context
|
|
6
|
+
import android.graphics.Color
|
|
7
|
+
import android.graphics.drawable.ColorDrawable
|
|
8
|
+
import android.os.Bundle
|
|
9
|
+
import android.view.LayoutInflater
|
|
10
|
+
import android.view.View
|
|
11
|
+
import android.view.ViewGroup
|
|
12
|
+
import android.view.inputmethod.InputMethodManager
|
|
13
|
+
import android.widget.EditText
|
|
14
|
+
import android.widget.TextView
|
|
15
|
+
import androidx.annotation.ColorInt
|
|
16
|
+
import androidx.appcompat.app.AppCompatActivity
|
|
17
|
+
import androidx.core.content.ContextCompat
|
|
18
|
+
import androidx.fragment.app.DialogFragment
|
|
19
|
+
import androidx.recyclerview.widget.LinearLayoutManager
|
|
20
|
+
import androidx.recyclerview.widget.RecyclerView
|
|
21
|
+
import com.photoeditor.editor.ColorPickerAdapter.OnColorPickerClickListener
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Created by Burhanuddin Rashid on 1/16/2018.
|
|
25
|
+
*/
|
|
26
|
+
class TextEditorDialogFragment : DialogFragment() {
|
|
27
|
+
|
|
28
|
+
private lateinit var mAddTextEditText: EditText
|
|
29
|
+
private lateinit var mAddTextDoneTextView: TextView
|
|
30
|
+
private lateinit var mInputMethodManager: InputMethodManager
|
|
31
|
+
private var mColorCode = 0
|
|
32
|
+
private var mTextEditorListener: TextEditorListener? = null
|
|
33
|
+
|
|
34
|
+
interface TextEditorListener {
|
|
35
|
+
fun onDone(inputText: String, colorCode: Int)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
override fun onStart() {
|
|
39
|
+
super.onStart()
|
|
40
|
+
val dialog = dialog
|
|
41
|
+
//Make dialog full screen with transparent background
|
|
42
|
+
if (dialog != null) {
|
|
43
|
+
val width = ViewGroup.LayoutParams.MATCH_PARENT
|
|
44
|
+
val height = ViewGroup.LayoutParams.MATCH_PARENT
|
|
45
|
+
dialog.window!!.setLayout(width, height)
|
|
46
|
+
dialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
override fun onCreateView(
|
|
51
|
+
inflater: LayoutInflater,
|
|
52
|
+
container: ViewGroup?,
|
|
53
|
+
savedInstanceState: Bundle?
|
|
54
|
+
): View? {
|
|
55
|
+
return inflater.inflate(R.layout.pe_add_text_dialog, container, false)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
59
|
+
super.onViewCreated(view, savedInstanceState)
|
|
60
|
+
|
|
61
|
+
val activity = requireActivity()
|
|
62
|
+
|
|
63
|
+
mAddTextEditText = view.findViewById(R.id.add_text_edit_text)
|
|
64
|
+
mInputMethodManager =
|
|
65
|
+
activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
|
66
|
+
mAddTextDoneTextView = view.findViewById(R.id.add_text_done_tv)
|
|
67
|
+
mAddTextDoneTextView.setEditorText(R.string.pe_label_done)
|
|
68
|
+
|
|
69
|
+
//Setup the color picker for text color
|
|
70
|
+
val addTextColorPickerRecyclerView: RecyclerView =
|
|
71
|
+
view.findViewById(R.id.add_text_color_picker_recycler_view)
|
|
72
|
+
val layoutManager = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
|
|
73
|
+
addTextColorPickerRecyclerView.layoutManager = layoutManager
|
|
74
|
+
addTextColorPickerRecyclerView.setHasFixedSize(true)
|
|
75
|
+
val colorPickerAdapter = ColorPickerAdapter(activity)
|
|
76
|
+
|
|
77
|
+
//This listener will change the text color when clicked on any color from picker
|
|
78
|
+
colorPickerAdapter.setOnColorPickerClickListener(object : OnColorPickerClickListener {
|
|
79
|
+
override fun onColorPickerClickListener(colorCode: Int) {
|
|
80
|
+
mColorCode = colorCode
|
|
81
|
+
mAddTextEditText.setTextColor(colorCode)
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
addTextColorPickerRecyclerView.adapter = colorPickerAdapter
|
|
86
|
+
|
|
87
|
+
val arguments = requireArguments()
|
|
88
|
+
|
|
89
|
+
mAddTextEditText.setText(arguments.getString(EXTRA_INPUT_TEXT))
|
|
90
|
+
mColorCode = arguments.getInt(EXTRA_COLOR_CODE)
|
|
91
|
+
mAddTextEditText.setTextColor(mColorCode)
|
|
92
|
+
mInputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0)
|
|
93
|
+
|
|
94
|
+
//Make a callback on activity when user is done with text editing
|
|
95
|
+
mAddTextDoneTextView.setOnClickListener { onClickListenerView ->
|
|
96
|
+
mInputMethodManager.hideSoftInputFromWindow(onClickListenerView.windowToken, 0)
|
|
97
|
+
dismiss()
|
|
98
|
+
val inputText = mAddTextEditText.text.toString()
|
|
99
|
+
val textEditorListener = mTextEditorListener
|
|
100
|
+
if (inputText.isNotEmpty() && textEditorListener != null) {
|
|
101
|
+
textEditorListener.onDone(inputText, mColorCode)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
//Callback to listener if user is done with text editing
|
|
107
|
+
fun setOnTextEditorListener(textEditorListener: TextEditorListener) {
|
|
108
|
+
mTextEditorListener = textEditorListener
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
companion object {
|
|
112
|
+
private val TAG: String = TextEditorDialogFragment::class.java.simpleName
|
|
113
|
+
const val EXTRA_INPUT_TEXT = "extra_input_text"
|
|
114
|
+
const val EXTRA_COLOR_CODE = "extra_color_code"
|
|
115
|
+
|
|
116
|
+
//Show dialog with provide text and text color
|
|
117
|
+
//Show dialog with default text input as empty and text color white
|
|
118
|
+
@JvmOverloads
|
|
119
|
+
fun show(
|
|
120
|
+
appCompatActivity: AppCompatActivity,
|
|
121
|
+
inputText: String = "",
|
|
122
|
+
@ColorInt colorCode: Int = ContextCompat.getColor(appCompatActivity, R.color.pe_white)
|
|
123
|
+
): TextEditorDialogFragment {
|
|
124
|
+
val args = Bundle()
|
|
125
|
+
args.putString(EXTRA_INPUT_TEXT, inputText)
|
|
126
|
+
args.putInt(EXTRA_COLOR_CODE, colorCode)
|
|
127
|
+
val fragment = TextEditorDialogFragment()
|
|
128
|
+
fragment.arguments = args
|
|
129
|
+
fragment.show(appCompatActivity.supportFragmentManager, TAG)
|
|
130
|
+
return fragment
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
package com.photoeditor.editor.base
|
|
2
|
+
|
|
3
|
+
import android.R
|
|
4
|
+
import android.app.ProgressDialog
|
|
5
|
+
import android.content.pm.PackageManager
|
|
6
|
+
import android.view.View
|
|
7
|
+
import android.view.Window
|
|
8
|
+
import android.view.WindowManager
|
|
9
|
+
import android.widget.Toast
|
|
10
|
+
import androidx.activity.result.contract.ActivityResultContracts
|
|
11
|
+
import androidx.appcompat.app.AppCompatActivity
|
|
12
|
+
import androidx.core.content.ContextCompat
|
|
13
|
+
import com.google.android.material.snackbar.Snackbar
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Created by Burhanuddin Rashid on 1/17/2018.
|
|
17
|
+
*/
|
|
18
|
+
open class BaseActivity : AppCompatActivity() {
|
|
19
|
+
private var mProgressDialog: ProgressDialog? = null
|
|
20
|
+
private var mPermission: String? = null
|
|
21
|
+
|
|
22
|
+
private val permissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) {
|
|
23
|
+
isPermissionGranted(it, mPermission)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
fun requestPermission(permission: String): Boolean {
|
|
27
|
+
val isGranted = ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
|
|
28
|
+
if (!isGranted) {
|
|
29
|
+
mPermission = permission
|
|
30
|
+
permissionLauncher.launch(permission)
|
|
31
|
+
}
|
|
32
|
+
return isGranted
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
open fun isPermissionGranted(isGranted: Boolean, permission: String?) {}
|
|
36
|
+
|
|
37
|
+
fun makeFullScreen() {
|
|
38
|
+
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
|
39
|
+
window.setFlags(
|
|
40
|
+
WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
|
41
|
+
WindowManager.LayoutParams.FLAG_FULLSCREEN
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
protected fun showLoading(message: String) {
|
|
46
|
+
mProgressDialog = ProgressDialog(this)
|
|
47
|
+
mProgressDialog?.run {
|
|
48
|
+
setMessage(message)
|
|
49
|
+
setProgressStyle(ProgressDialog.STYLE_SPINNER)
|
|
50
|
+
setCancelable(false)
|
|
51
|
+
show()
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
protected fun hideLoading() {
|
|
56
|
+
mProgressDialog?.dismiss()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
protected fun showSnackbar(message: String) {
|
|
60
|
+
val view = findViewById<View>(R.id.content)
|
|
61
|
+
if (view != null) {
|
|
62
|
+
Snackbar.make(view, message, Snackbar.LENGTH_SHORT).show()
|
|
63
|
+
} else {
|
|
64
|
+
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
package com.photoeditor.editor.base
|
|
2
|
+
|
|
3
|
+
import androidx.fragment.app.Fragment
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @author [Burhanuddin Rashid](https://github.com/burhanrashid52)
|
|
7
|
+
* @version 0.1.2
|
|
8
|
+
* @since 5/25/2018
|
|
9
|
+
*/
|
|
10
|
+
abstract class BaseFragment(layoutId: Int) : Fragment(layoutId)
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
package com.photoeditor.editor.filters
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.graphics.Bitmap
|
|
5
|
+
import android.graphics.BitmapFactory
|
|
6
|
+
import android.view.LayoutInflater
|
|
7
|
+
import android.view.View
|
|
8
|
+
import android.view.ViewGroup
|
|
9
|
+
import android.widget.ImageView
|
|
10
|
+
import android.widget.TextView
|
|
11
|
+
import androidx.annotation.StringRes
|
|
12
|
+
import androidx.recyclerview.widget.RecyclerView
|
|
13
|
+
import com.photoeditor.R
|
|
14
|
+
import ja.burhanrashid52.photoeditor.PhotoFilter
|
|
15
|
+
import java.io.IOException
|
|
16
|
+
import java.util.ArrayList
|
|
17
|
+
import com.photoeditor.editor.setEditorText
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @author [Burhanuddin Rashid](https://github.com/burhanrashid52)
|
|
21
|
+
* @version 0.1.2
|
|
22
|
+
* @since 5/23/2018
|
|
23
|
+
*/
|
|
24
|
+
class FilterViewAdapter(private val mFilterListener: FilterListener) :
|
|
25
|
+
RecyclerView.Adapter<FilterViewAdapter.ViewHolder>() {
|
|
26
|
+
private val mFilterList: MutableList<FilterModel> = ArrayList()
|
|
27
|
+
|
|
28
|
+
private class FilterModel(
|
|
29
|
+
val mAssetPath: String,
|
|
30
|
+
val mFilter: PhotoFilter,
|
|
31
|
+
@StringRes val mFilterName: Int
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
|
35
|
+
val view =
|
|
36
|
+
LayoutInflater.from(parent.context).inflate(R.layout.pe_row_filter_view, parent, false)
|
|
37
|
+
return ViewHolder(view)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
|
41
|
+
val filter = mFilterList[position]
|
|
42
|
+
val fromAsset = getBitmapFromAsset(holder.itemView.context, filter.mAssetPath)
|
|
43
|
+
holder.mImageFilterView.setImageBitmap(fromAsset)
|
|
44
|
+
holder.mTxtFilterName.setEditorText(filter.mFilterName)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
override fun getItemCount(): Int {
|
|
48
|
+
return mFilterList.size
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
|
52
|
+
val mImageFilterView: ImageView = itemView.findViewById(R.id.imgFilterView)
|
|
53
|
+
val mTxtFilterName: TextView = itemView.findViewById(R.id.txtFilterName)
|
|
54
|
+
|
|
55
|
+
init {
|
|
56
|
+
itemView.setOnClickListener{
|
|
57
|
+
mFilterListener.onFilterSelected(
|
|
58
|
+
mFilterList[layoutPosition].mFilter
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private fun getBitmapFromAsset(context: Context, strName: String): Bitmap? {
|
|
65
|
+
val assetManager = context.assets
|
|
66
|
+
return try {
|
|
67
|
+
val istr = assetManager.open(strName)
|
|
68
|
+
BitmapFactory.decodeStream(istr)
|
|
69
|
+
} catch (e: IOException) {
|
|
70
|
+
e.printStackTrace()
|
|
71
|
+
null
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private fun setupFilters() {
|
|
76
|
+
mFilterList.add(FilterModel("filters/original.jpg", PhotoFilter.NONE, R.string.pe_filter_none))
|
|
77
|
+
mFilterList.add(FilterModel("filters/auto_fix.png", PhotoFilter.AUTO_FIX, R.string.pe_filter_auto_fix))
|
|
78
|
+
mFilterList.add(FilterModel("filters/brightness.png", PhotoFilter.BRIGHTNESS, R.string.pe_filter_brightness))
|
|
79
|
+
mFilterList.add(FilterModel("filters/contrast.png", PhotoFilter.CONTRAST, R.string.pe_filter_contrast))
|
|
80
|
+
mFilterList.add(FilterModel("filters/documentary.png", PhotoFilter.DOCUMENTARY, R.string.pe_filter_documentary))
|
|
81
|
+
mFilterList.add(FilterModel("filters/dual_tone.png", PhotoFilter.DUE_TONE, R.string.pe_filter_duo_tone))
|
|
82
|
+
mFilterList.add(FilterModel("filters/fill_light.png", PhotoFilter.FILL_LIGHT, R.string.pe_filter_fill_light))
|
|
83
|
+
mFilterList.add(FilterModel("filters/fish_eye.png", PhotoFilter.FISH_EYE, R.string.pe_filter_fish_eye))
|
|
84
|
+
mFilterList.add(FilterModel("filters/grain.png", PhotoFilter.GRAIN, R.string.pe_filter_grain))
|
|
85
|
+
mFilterList.add(FilterModel("filters/gray_scale.png", PhotoFilter.GRAY_SCALE, R.string.pe_filter_gray_scale))
|
|
86
|
+
mFilterList.add(FilterModel("filters/lomish.png", PhotoFilter.LOMISH, R.string.pe_filter_lomish))
|
|
87
|
+
mFilterList.add(FilterModel("filters/negative.png", PhotoFilter.NEGATIVE, R.string.pe_filter_negative))
|
|
88
|
+
mFilterList.add(FilterModel("filters/posterize.png", PhotoFilter.POSTERIZE, R.string.pe_filter_posterize))
|
|
89
|
+
mFilterList.add(FilterModel("filters/saturate.png", PhotoFilter.SATURATE, R.string.pe_filter_saturate))
|
|
90
|
+
mFilterList.add(FilterModel("filters/sepia.png", PhotoFilter.SEPIA, R.string.pe_filter_sepia))
|
|
91
|
+
mFilterList.add(FilterModel("filters/sharpen.png", PhotoFilter.SHARPEN, R.string.pe_filter_sharpen))
|
|
92
|
+
mFilterList.add(FilterModel("filters/temprature.png", PhotoFilter.TEMPERATURE, R.string.pe_filter_temperature))
|
|
93
|
+
mFilterList.add(FilterModel("filters/tint.png", PhotoFilter.TINT, R.string.pe_filter_tint))
|
|
94
|
+
mFilterList.add(FilterModel("filters/vignette.png", PhotoFilter.VIGNETTE, R.string.pe_filter_vignette))
|
|
95
|
+
mFilterList.add(FilterModel("filters/cross_process.png", PhotoFilter.CROSS_PROCESS, R.string.pe_filter_cross_process))
|
|
96
|
+
mFilterList.add(FilterModel("filters/b_n_w.png", PhotoFilter.BLACK_WHITE, R.string.pe_filter_black_white))
|
|
97
|
+
mFilterList.add(FilterModel("filters/flip_horizental.png", PhotoFilter.FLIP_HORIZONTAL, R.string.pe_filter_flip_horizontal))
|
|
98
|
+
mFilterList.add(FilterModel("filters/flip_vertical.png", PhotoFilter.FLIP_VERTICAL, R.string.pe_filter_flip_vertical))
|
|
99
|
+
mFilterList.add(FilterModel("filters/rotate.png", PhotoFilter.ROTATE, R.string.pe_filter_rotate))
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
init {
|
|
103
|
+
setupFilters()
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
package com.photoeditor.editor.tools
|
|
2
|
+
|
|
3
|
+
import android.view.LayoutInflater
|
|
4
|
+
import android.view.View
|
|
5
|
+
import android.view.ViewGroup
|
|
6
|
+
import android.widget.ImageView
|
|
7
|
+
import android.widget.TextView
|
|
8
|
+
import androidx.annotation.StringRes
|
|
9
|
+
import androidx.recyclerview.widget.RecyclerView
|
|
10
|
+
import com.photoeditor.R
|
|
11
|
+
import java.util.ArrayList
|
|
12
|
+
import com.photoeditor.editor.setEditorText
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @author [Burhanuddin Rashid](https://github.com/burhanrashid52)
|
|
16
|
+
* @version 0.1.2
|
|
17
|
+
* @since 5/23/2018
|
|
18
|
+
*/
|
|
19
|
+
class EditingToolsAdapter(private val mOnItemSelected: OnItemSelected) :
|
|
20
|
+
RecyclerView.Adapter<EditingToolsAdapter.ViewHolder>() {
|
|
21
|
+
private val mToolList: MutableList<ToolModel> = ArrayList()
|
|
22
|
+
|
|
23
|
+
interface OnItemSelected {
|
|
24
|
+
fun onToolSelected(toolType: ToolType)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
internal inner class ToolModel(
|
|
28
|
+
@StringRes val mToolName: Int,
|
|
29
|
+
val mToolIcon: Int,
|
|
30
|
+
val mToolType: ToolType
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
|
34
|
+
val view = LayoutInflater.from(parent.context)
|
|
35
|
+
.inflate(R.layout.pe_row_editing_tools, parent, false)
|
|
36
|
+
return ViewHolder(view)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
|
40
|
+
val item = mToolList[position]
|
|
41
|
+
holder.txtTool.setEditorText(item.mToolName)
|
|
42
|
+
holder.imgToolIcon.setImageResource(item.mToolIcon)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override fun getItemCount(): Int {
|
|
46
|
+
return mToolList.size
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
|
50
|
+
val imgToolIcon: ImageView = itemView.findViewById(R.id.imgToolIcon)
|
|
51
|
+
val txtTool: TextView = itemView.findViewById(R.id.txtTool)
|
|
52
|
+
|
|
53
|
+
init {
|
|
54
|
+
itemView.setOnClickListener { _: View? ->
|
|
55
|
+
mOnItemSelected.onToolSelected(
|
|
56
|
+
mToolList[layoutPosition].mToolType
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
init {
|
|
63
|
+
mToolList.add(ToolModel(R.string.pe_label_shape, R.drawable.pe_ic_oval, ToolType.SHAPE))
|
|
64
|
+
mToolList.add(ToolModel(R.string.pe_label_text, R.drawable.pe_ic_text, ToolType.TEXT))
|
|
65
|
+
mToolList.add(ToolModel(R.string.pe_label_eraser, R.drawable.pe_ic_eraser, ToolType.ERASER))
|
|
66
|
+
mToolList.add(ToolModel(R.string.pe_label_filter, R.drawable.pe_ic_photo_filter, ToolType.FILTER))
|
|
67
|
+
mToolList.add(ToolModel(R.string.pe_label_emoji, R.drawable.pe_ic_insert_emoticon, ToolType.EMOJI))
|
|
68
|
+
mToolList.add(ToolModel(R.string.pe_label_sticker, R.drawable.pe_ic_sticker, ToolType.STICKER))
|
|
69
|
+
}
|
|
70
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
android:width="24dp"
|
|
3
|
+
android:height="24dp"
|
|
4
|
+
android:viewportWidth="24.0"
|
|
5
|
+
android:viewportHeight="24.0">
|
|
6
|
+
<path
|
|
7
|
+
android:fillColor="#FFFFFF"
|
|
8
|
+
android:pathData="M7,14c-1.66,0 -3,1.34 -3,3 0,1.31 -1.16,2 -2,2 0.92,1.22 2.49,2 4,2 2.21,0 4,-1.79 4,-4 0,-1.66 -1.34,-3 -3,-3zM20.71,4.63l-1.34,-1.34c-0.39,-0.39 -1.02,-0.39 -1.41,0L9,12.25 11.75,15l8.96,-8.96c0.39,-0.39 0.39,-1.02 0,-1.41z"/>
|
|
9
|
+
</vector>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
android:width="24dp"
|
|
3
|
+
android:height="24dp"
|
|
4
|
+
android:viewportWidth="24.0"
|
|
5
|
+
android:viewportHeight="24.0">
|
|
6
|
+
<path
|
|
7
|
+
android:fillColor="#FFFFFF"
|
|
8
|
+
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
|
9
|
+
</vector>
|