Skip to content

Commit

Permalink
Merge pull request #142 from TheCodeMonks/Share-As-Image
Browse files Browse the repository at this point in the history
Share as image
  • Loading branch information
Spikeysanju committed Apr 8, 2021
2 parents acfceee + eeb3c98 commit db2888f
Show file tree
Hide file tree
Showing 21 changed files with 4,033 additions and 35 deletions.
18 changes: 18 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ dependencies {
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.1"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"

// activity & fragment ktx
implementation "androidx.fragment:fragment-ktx:1.3.2"
implementation "androidx.activity:activity-ktx:1.3.0-alpha05"
implementation 'androidx.appcompat:appcompat:1.3.0-rc01'

// Navigation Components
implementation "androidx.navigation:navigation-fragment-ktx:2.3.4"
Expand All @@ -118,6 +122,9 @@ dependencies {
// Preference DataStore
implementation "androidx.datastore:datastore-preferences:1.0.0-alpha06"

// Lottie Animation Library
implementation "com.airbnb.android:lottie:3.6.0"

// Hilt
implementation "com.google.dagger:hilt-android:2.30.1-alpha"
kapt "com.google.dagger:hilt-android-compiler:2.30.1-alpha"
Expand Down
32 changes: 31 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ /*
~ *
~ * * MIT License
~ * *
~ * * Copyright (c) 2020 Spikey Sanju
~ * *
~ * * Permission is hereby granted, free of charge, to any person obtaining a copy
~ * * of this software and associated documentation files (the "Software"), to deal
~ * * in the Software without restriction, including without limitation the rights
~ * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ * * copies of the Software, and to permit persons to whom the Software is
~ * * furnished to do so, subject to the following conditions:
~ * *
~ * * The above copyright notice and this permission notice shall be included in all
~ * * copies or substantial portions of the Software.
~ * *
~ * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
~ * * SOFTWARE.
~ *
~ */
~
-->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="thecodemonks.org.nottzapp">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<application
android:name=".app.NotzzApp"
Expand All @@ -25,4 +55,4 @@
android:resource="@array/preloaded_fonts" />
</application>

</manifest>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,22 @@

package thecodemonks.org.nottzapp.ui.details

import android.Manifest
import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.*
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.ShareCompat
import androidx.core.content.ContextCompat
import androidx.core.view.drawToBitmap
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
Expand All @@ -42,6 +53,8 @@ import dagger.hilt.android.AndroidEntryPoint
import thecodemonks.org.nottzapp.R
import thecodemonks.org.nottzapp.databinding.FragmentNotesDetailsBinding
import thecodemonks.org.nottzapp.ui.notes.NotesViewModel
import thecodemonks.org.nottzapp.utils.saveBitmap
import thecodemonks.org.nottzapp.utils.showOrHide

@AndroidEntryPoint
class NotesDetailsFragment : Fragment(R.layout.fragment_notes_details) {
Expand All @@ -52,11 +65,59 @@ class NotesDetailsFragment : Fragment(R.layout.fragment_notes_details) {
private lateinit var _binding: FragmentNotesDetailsBinding
private val binding get() = _binding

// handle permission dialog
private val requestLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
if (isGranted) shareImage() else showErrorDialog()
}

private fun showErrorDialog() = findNavController().navigate(
NotesDetailsFragmentDirections.actionNotesDetailsFragmentToErrorDialog(
"Image share failed!",
"You have to enable storage permission to share transaction as Image"
)
)

private fun shareImage() {

if (!isStoragePermissionGranted()) {
requestLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
return
}

// unHide watermark
showLogo(true)
val imageURI = binding.noteLayout.noteDetailLayout.drawToBitmap().let { bitmap ->
// hide watermark
showLogo(false)
saveBitmap(requireActivity(), bitmap)
} ?: run {
Toast.makeText(requireContext(), "Error Occured", Toast.LENGTH_SHORT).show()
return
}

val intent = ShareCompat.IntentBuilder(requireActivity())
.setType("image/jpeg")
.setStream(imageURI)
.intent

startActivity(Intent.createChooser(intent, null))
}

private fun showLogo(isVisible: Boolean) = with(binding) {
noteLayout.logo.showOrHide(isVisible)
}

private fun isStoragePermissionGranted(): Boolean = ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.WRITE_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
): View {
_binding = FragmentNotesDetailsBinding.inflate(inflater, container, false)
return binding.root
}
Expand Down Expand Up @@ -107,21 +168,13 @@ class NotesDetailsFragment : Fragment(R.layout.fragment_notes_details) {
true
}

R.id.action_share -> {
val shareMsg = getString(
R.string.share_message,
args.notes.title,
args.notes.description
)

val intent = ShareCompat.IntentBuilder.from(requireActivity())
.setType("text/plain")
.setText(shareMsg)
.intent
R.id.action_share_text -> {
shareText()
true
}

if (intent.resolveActivity(requireActivity().packageManager) != null) {
startActivity(intent)
}
R.id.action_share_image -> {
shareImage()
true
}

Expand All @@ -135,4 +188,20 @@ class NotesDetailsFragment : Fragment(R.layout.fragment_notes_details) {
it.noteET.text.toString()
)
}

@SuppressLint("StringFormatMatches")
private fun shareText() = with(binding) {
val shareMsg = getString(
R.string.share_message,
args.notes.title,
args.notes.description
)

val intent = ShareCompat.IntentBuilder(requireActivity())
.setType("text/plain")
.setText(shareMsg)
.intent

startActivity(Intent.createChooser(intent, null))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
*
* *
* * * MIT License
* * *
* * * Copyright (c) 2020 Spikey Sanju
* * *
* * * Permission is hereby granted, free of charge, to any person obtaining a copy
* * * of this software and associated documentation files (the "Software"), to deal
* * * in the Software without restriction, including without limitation the rights
* * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* * * copies of the Software, and to permit persons to whom the Software is
* * * furnished to do so, subject to the following conditions:
* * *
* * * The above copyright notice and this permission notice shall be included in all
* * * copies or substantial portions of the Software.
* * *
* * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* * * SOFTWARE.
* *
*
*
*/

package thecodemonks.org.nottzapp.ui.dialog

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import androidx.navigation.fragment.navArgs
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import thecodemonks.org.nottzapp.databinding.ErrorDialogLayoutBinding

class ErrorDialog : BottomSheetDialogFragment() {
private var _binding: ErrorDialogLayoutBinding? = null
private val binding get() = _binding!!
private val args: ErrorDialogArgs by navArgs()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = ErrorDialogLayoutBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

binding.run {
dialogTitle.text = args.title
dialogMessage.text = args.message
dialogButtonOk.setOnClickListener { dialog?.dismiss() }
}
}

override fun onStart() {
super.onStart()
dialog?.window?.setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT
)
}

override fun onDestroy() {
super.onDestroy()
_binding = null
}
}
65 changes: 65 additions & 0 deletions app/src/main/java/thecodemonks/org/nottzapp/utils/SaveBitmap.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
*
* *
* * * MIT License
* * *
* * * Copyright (c) 2020 Spikey Sanju
* * *
* * * Permission is hereby granted, free of charge, to any person obtaining a copy
* * * of this software and associated documentation files (the "Software"), to deal
* * * in the Software without restriction, including without limitation the rights
* * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* * * copies of the Software, and to permit persons to whom the Software is
* * * furnished to do so, subject to the following conditions:
* * *
* * * The above copyright notice and this permission notice shall be included in all
* * * copies or substantial portions of the Software.
* * *
* * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* * * SOFTWARE.
* *
*
*
*/

package thecodemonks.org.nottzapp.utils

import android.app.Activity
import android.content.ContentValues
import android.graphics.Bitmap
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore

@JvmField
val DEFAULT_FILENAME = "${"Notzz" + System.currentTimeMillis()}.png"

fun saveBitmap(activity: Activity, bitmap: Bitmap, filename: String = DEFAULT_FILENAME): Uri? {
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
}
}

val contentResolver = activity.contentResolver

val imageUri: Uri? = contentResolver.insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues
)

return imageUri.also {
val fileOutputStream = imageUri?.let { contentResolver.openOutputStream(it) }
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream)
fileOutputStream?.close()
}
}
2 changes: 2 additions & 0 deletions app/src/main/java/thecodemonks/org/nottzapp/utils/ViewExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,5 @@ fun View.show() {
fun View.hide() {
visibility = View.GONE
}

fun View.showOrHide(isVisible: Boolean) = if (isVisible) show() else hide()
4 changes: 2 additions & 2 deletions app/src/main/res/drawable/ic_baseline_add.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:tint="@color/white"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:fillColor="@color/white"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
</vector>
Loading

0 comments on commit db2888f

Please sign in to comment.