Skip to content

Commit 3006674

Browse files
committed
refactor: converted projects classes to Kotlin, ui fixes and improvements
1 parent 4155038 commit 3006674

24 files changed

+515
-177
lines changed

app/src/main/AndroidManifest.xml

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools"
34
package="com.kinvey.sample.statusshare" >
45

6+
<uses-permission android:name="android.permission.INTERNET"/>
7+
8+
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
9+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
10+
11+
<uses-permission android:name="android.permission.CAMERA" />
12+
513
<application
14+
android:name=".App"
615
android:allowBackup="true"
716
android:icon="@mipmap/ic_launcher"
817
android:label="@string/app_name"
9-
android:theme="@style/AppTheme" >
18+
android:theme="@style/AppTheme"
19+
tools:ignore="GoogleAppIndexingWarning">
1020
<activity
1121
android:name=".ui.MainActivity"
22+
android:theme="@style/AppTheme"
1223
android:label="@string/app_name" >
1324
<intent-filter>
1425
<action android:name="android.intent.action.MAIN" />

app/src/main/assets/kinvey.properties

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Required settings
2-
app.key=your_app_key
3-
app.secret=your_app_secret
2+
app.key=kid_BJZQvUh8-
3+
app.secret=829e910da4b54577bb97fe8105722f3c
44
# Optional settings, only required for push
55
debug = true

app/src/main/java/com/kinvey/sample/statusshare/App.kt

+11-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
package com.kinvey.sample.statusshare
1515

1616
import android.app.Application
17+
import android.content.Context
18+
import androidx.multidex.MultiDex
1719
import com.google.api.client.http.HttpTransport
1820
import com.kinvey.android.Client
1921
import com.kinvey.android.Client.Builder
@@ -26,24 +28,31 @@ import java.util.logging.Logger
2628
* @since 2.0
2729
*/
2830
class App : Application() {
29-
31+
3032
var client: Client<User>? = null
3133
get() {
3234
if (field == null) {
33-
field = Builder<User>(applicationContext).build()
35+
field = Builder<User>(this).build()
3436
}
3537
return field
3638
}
3739
private set
3840

3941
override fun onCreate() {
4042
super.onCreate()
43+
instance = this
4144
// run the following comamnd to turn on verbose logging:
4245
// adb shell setprop log.tag.HttpTransport DEBUG
4346
Logger.getLogger(HttpTransport::class.java.name).level = LOGGING_LEVEL
4447
}
4548

49+
override fun attachBaseContext(base: Context?) {
50+
super.attachBaseContext(base)
51+
MultiDex.install(base)
52+
}
53+
4654
companion object {
55+
var instance: App? = null
4756
private val LOGGING_LEVEL: Level? = Level.FINEST
4857
}
4958
}

app/src/main/java/com/kinvey/sample/statusshare/model/CommentEntity.kt

+18-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import com.kinvey.java.linkedResources.LinkedGenericJson
1818
import com.kinvey.java.model.KinveyMetaData
1919
import com.kinvey.java.model.KinveyMetaData.AccessControlList
2020
import com.kinvey.sample.statusshare.utils.Constants
21+
import com.kinvey.sample.statusshare.utils.Constants.ECT_FIELD_NAME
22+
import com.kinvey.sample.statusshare.utils.Constants.KMD_FIELD_NAME
2123

2224
/**
2325
* This class maintains a Comment which can be persisted with Kinvey.
@@ -38,4 +40,19 @@ data class CommentEntity(
3840
var author: String? = null,
3941
@Key("updateId")
4042
var updateId: String? = null
41-
) : LinkedGenericJson()
43+
) : LinkedGenericJson() {
44+
45+
var ect: String? = null
46+
get() {
47+
if (field.isNullOrEmpty()) {
48+
val kmd = get(KMD_FIELD_NAME)
49+
field = if (kmd is Map<*, *>) {
50+
val ect = kmd[ECT_FIELD_NAME]
51+
ect?.toString() ?: ""
52+
} else {
53+
null
54+
}
55+
}
56+
return field
57+
}
58+
}

app/src/main/java/com/kinvey/sample/statusshare/model/UpdateEntity.kt

+35-15
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ import com.kinvey.java.model.KinveyMetaData
2121
import com.kinvey.java.model.KinveyMetaData.AccessControlList
2222
import com.kinvey.java.model.KinveyReference
2323
import com.kinvey.sample.statusshare.utils.Constants
24+
import com.kinvey.sample.statusshare.utils.Constants.KMD_FIELD_NAME
25+
import com.kinvey.sample.statusshare.utils.Constants.USERNAME_FIELD_NAME
2426
import com.kinvey.sample.statusshare.utils.TimeUtil.getSince
2527
import timber.log.Timber
26-
import java.text.ParsePosition
2728
import java.text.SimpleDateFormat
2829
import java.util.*
2930

@@ -33,7 +34,7 @@ import java.util.*
3334
* @author edwardf
3435
* @since 2.0
3536
*/
36-
data class UpdateEntity(var userId: String? = "",
37+
data class UpdateEntity(
3738
//----persisted fields
3839
@Key("_id")
3940
var id: String? = null,
@@ -46,10 +47,14 @@ data class UpdateEntity(var userId: String? = "",
4647
@Key("author")
4748
var author: KinveyReference? = null,
4849
@Key("comments")
49-
var comments: ArrayList<KinveyReference>? = null
50+
var comments: ArrayList<KinveyReference>? = null,
51+
var userId: String? = ""
5052
) : LinkedGenericJson() {
5153

54+
private var dateFormat: SimpleDateFormat? = null
55+
5256
init {
57+
dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US)
5358
putFile(Constants.ATTACHMENT_NAME)
5459
author = KinveyReference()
5560
author?.collection = Constants.USER_COLLECTION_NAME
@@ -59,32 +64,49 @@ data class UpdateEntity(var userId: String? = "",
5964
//-----displayed inferred fields
6065
var authorName: String? = null
6166
get() {
62-
if (author?.resolvedObject != null) {
63-
field = author?.resolvedObject!!["username"] as String
67+
if (author != null) {
68+
field = author!![USERNAME_FIELD_NAME] as String?
6469
}
6570
return if (field == null) "--" else field
6671
}
67-
private set
72+
set (value) {
73+
if (author != null) {
74+
author!![USERNAME_FIELD_NAME] = value
75+
}
76+
}
6877

6978
var authorID: String? = null
7079
get() {
71-
if (author?.resolvedObject != null) {
72-
field = author?.resolvedObject!!["_id"] as String
73-
}
80+
field = author?.id
7481
return if (field == null) "" else field
7582
}
7683
private set
7784

7885
var since: String? = null
7986
get() {
80-
val pp = ParsePosition(0)
81-
val date = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US).parse(meta?.entityCreationTime, pp)
82-
field = getSince(date, Calendar.getInstance())
83-
Timber.i("getting since -> ${field != null}")
87+
if (field == null) {
88+
val date = dateFormat?.parse(ect ?: "")
89+
field = if (date != null) getSince(date, Calendar.getInstance()) else null
90+
Timber.i("getting since -> ${field != null}")
91+
}
8492
return field
8593
}
8694
private set//close the output stream//Then decode from the output stream and get the image.//and there is an actual LinkedFile behind the Key//If it hasn't been resolved...
8795

96+
var ect: String? = null
97+
get() {
98+
if (field.isNullOrEmpty()) {
99+
val kmd = get(KMD_FIELD_NAME)
100+
field = if (kmd is Map<*, *>) {
101+
val ect = kmd[Constants.ECT_FIELD_NAME]
102+
ect?.toString() ?: ""
103+
} else {
104+
null
105+
}
106+
}
107+
return field
108+
}
109+
88110
/**
89111
* Get the thumbnail from the LinkedResource
90112
*
@@ -114,8 +136,6 @@ data class UpdateEntity(var userId: String? = "",
114136
}
115137
private set
116138

117-
118-
119139
fun addComment(newComment: CommentEntity) {
120140
if (comments == null) {
121141
comments = ArrayList()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.kinvey.sample.statusshare.ui
2+
3+
import android.os.Bundle
4+
import androidx.appcompat.app.AppCompatActivity
5+
import androidx.fragment.app.Fragment
6+
import com.kinvey.sample.statusshare.R
7+
8+
abstract class BaseCompatActivity : AppCompatActivity() {
9+
10+
override fun onCreate(savedInstanceState: Bundle?) {
11+
super.onCreate(savedInstanceState)
12+
setContentView(layoutId)
13+
}
14+
15+
open val layoutId = 0
16+
17+
open val contentId = R.id.fragmentBox
18+
19+
fun replaceFragment(frag: Fragment, addToBackStack: Boolean) {
20+
val ft = supportFragmentManager.beginTransaction()
21+
ft.replace(contentId, frag)
22+
if (addToBackStack) {
23+
ft.addToBackStack(frag.toString())
24+
}
25+
ft.commit()
26+
}
27+
}

app/src/main/java/com/kinvey/sample/statusshare/ui/MainActivity.kt

+68-16
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,43 @@
11
package com.kinvey.sample.statusshare.ui
22

3+
import android.Manifest
34
import android.app.Activity
45
import android.content.Intent
6+
import android.content.pm.PackageManager
57
import android.graphics.Bitmap
68
import android.net.Uri
79
import android.os.Bundle
810
import android.provider.MediaStore
9-
import androidx.appcompat.app.AppCompatActivity
10-
import androidx.fragment.app.Fragment
11+
import androidx.core.app.ActivityCompat
1112
import com.google.api.client.http.HttpTransport
12-
import com.kinvey.sample.statusshare.R.id
13-
import com.kinvey.sample.statusshare.R.layout
13+
import com.kinvey.sample.statusshare.R
1414
import com.kinvey.sample.statusshare.model.UpdateEntity
1515
import com.kinvey.sample.statusshare.ui.fragments.LoginFragment
1616
import com.kinvey.sample.statusshare.utils.BitmapTools.decodeFromCameraUri
1717
import com.kinvey.sample.statusshare.utils.BitmapTools.decodeFromFile
1818
import com.kinvey.sample.statusshare.utils.Constants
1919
import com.kinvey.sample.statusshare.utils.FileUtil.getCaptureFilePath
20+
import kotlinx.android.synthetic.main.activity_fragment_holder.*
2021
import timber.log.Timber
2122
import java.util.logging.Level
2223
import java.util.logging.Logger
2324

24-
class MainActivity : AppCompatActivity() {
25+
open class MainActivity : BaseCompatActivity() {
2526

2627
private var mImageCaptureUri: Uri? = null
2728
var bitmap: Bitmap? = null
2829
var shareList: List<UpdateEntity>? = null
2930

3031
public override fun onCreate(savedInstanceState: Bundle?) {
3132
super.onCreate(savedInstanceState)
32-
setContentView(layout.activity_fragment_holder)
33+
setSupportActionBar(myToolbar)
3334
Logger.getLogger(HttpTransport::class.java.name).level = LOGGING_LEVEL
3435
replaceFragment(LoginFragment(), false)
3536
}
3637

37-
fun replaceFragment(frag: Fragment, addToBackStack: Boolean) {
38-
val ft = supportFragmentManager.beginTransaction()
39-
ft.replace(id.fragmentBox, frag)
40-
if (addToBackStack) {
41-
ft.addToBackStack(frag.toString())
42-
}
43-
ft.commit()
44-
}
38+
override val layoutId = R.layout.activity_fragment_holder
39+
40+
override val contentId = R.id.fragmentBox
4541

4642
/**
4743
* This method will be called after the user either selects a photo from their gallery or takes a picture with their camera
@@ -64,7 +60,11 @@ class MainActivity : AppCompatActivity() {
6460
}
6561
}
6662

67-
fun startCamera() {
63+
fun startCamera(requestPermissions: Boolean = true) {
64+
if (!verifyCameraPermissions(this)) {
65+
if (requestPermissions) { requestCameraPermissions(this) }
66+
return
67+
}
6868
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
6969
mImageCaptureUri = getCaptureFilePath()
7070
try {
@@ -79,14 +79,66 @@ class MainActivity : AppCompatActivity() {
7979
/**
8080
* This method wraps the code to kick off the "chooser" intent, which allows user to select where to select image from
8181
*/
82-
fun startFilePicker() {
82+
fun startFilePicker(requestPermissions: Boolean = true) {
83+
if (!verifyStoragePermissions(this)) {
84+
if (requestPermissions) { requestStoragePermissions(this) }
85+
return
86+
}
8387
val intent = Intent()
8488
intent.type = "image/*"
8589
intent.action = Intent.ACTION_GET_CONTENT
8690
startActivityForResult(Intent.createChooser(intent, "Complete action using"), Constants.PICK_FROM_FILE)
8791
}
8892

93+
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
94+
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
95+
when (requestCode) {
96+
REQUEST_EXTERNAL_STORAGE -> startFilePicker(false)
97+
REQUEST_CAMERA -> startCamera(false)
98+
}
99+
}
100+
89101
companion object {
90102
private val LOGGING_LEVEL: Level? = Level.FINEST
103+
104+
private const val REQUEST_EXTERNAL_STORAGE = 1
105+
private const val REQUEST_CAMERA = 2
106+
107+
private val PERMISSIONS_STORAGE = arrayOf(
108+
Manifest.permission.READ_EXTERNAL_STORAGE,
109+
Manifest.permission.WRITE_EXTERNAL_STORAGE
110+
)
111+
112+
private val PERMISSIONS_CAMERA = arrayOf(Manifest.permission.CAMERA)
113+
114+
/**
115+
* Checks if the app has permission to write to device storage
116+
*
117+
* If the app does not has permission then the user will be prompted to grant permissions
118+
*
119+
* @param activity
120+
*/
121+
fun verifyStoragePermissions(activity: Activity): Boolean {
122+
// Check if we have write permission
123+
val permissionWrite = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)
124+
val permissionRead = ActivityCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE)
125+
return permissionWrite == PackageManager.PERMISSION_GRANTED && permissionRead == PackageManager.PERMISSION_GRANTED
126+
}
127+
128+
fun requestStoragePermissions(activity: Activity) {
129+
// We don't have permission so prompt the user
130+
ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE)
131+
}
132+
133+
fun verifyCameraPermissions(activity: Activity): Boolean {
134+
// Check if we have permission
135+
val permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.CAMERA)
136+
return permission == PackageManager.PERMISSION_GRANTED
137+
}
138+
139+
fun requestCameraPermissions(activity: Activity) {
140+
// We don't have permission so prompt the user
141+
ActivityCompat.requestPermissions(activity, PERMISSIONS_CAMERA, REQUEST_CAMERA)
142+
}
91143
}
92144
}

0 commit comments

Comments
 (0)