Merge branch 'development' into 'master'
Development See merge request Cloud_Solution/diplomatic-quarter!303master
@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CLIENT_ID</key>
|
||||||
|
<string>864393916058-ekeb4s8tgfo58dutv0l54399t7ivr06r.apps.googleusercontent.com</string>
|
||||||
|
<key>REVERSED_CLIENT_ID</key>
|
||||||
|
<string>com.googleusercontent.apps.864393916058-ekeb4s8tgfo58dutv0l54399t7ivr06r</string>
|
||||||
|
<key>API_KEY</key>
|
||||||
|
<string>AIzaSyA_6ayGCk4fly7o7eTVBrj9kuHBYHMAOfs</string>
|
||||||
|
<key>GCM_SENDER_ID</key>
|
||||||
|
<string>864393916058</string>
|
||||||
|
<key>PLIST_VERSION</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>BUNDLE_ID</key>
|
||||||
|
<string>com.cloud.diplomaticquarterapp</string>
|
||||||
|
<key>PROJECT_ID</key>
|
||||||
|
<string>diplomaticquarter-d2385</string>
|
||||||
|
<key>STORAGE_BUCKET</key>
|
||||||
|
<string>diplomaticquarter-d2385.appspot.com</string>
|
||||||
|
<key>IS_ADS_ENABLED</key>
|
||||||
|
<false></false>
|
||||||
|
<key>IS_ANALYTICS_ENABLED</key>
|
||||||
|
<false></false>
|
||||||
|
<key>IS_APPINVITE_ENABLED</key>
|
||||||
|
<true></true>
|
||||||
|
<key>IS_GCM_ENABLED</key>
|
||||||
|
<true></true>
|
||||||
|
<key>IS_SIGNIN_ENABLED</key>
|
||||||
|
<true></true>
|
||||||
|
<key>GOOGLE_APP_ID</key>
|
||||||
|
<string>1:864393916058:ios:13f787bbfe6051f8b97923</string>
|
||||||
|
<key>DATABASE_URL</key>
|
||||||
|
<string>https://diplomaticquarter-d2385.firebaseio.com</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CLIENT_ID</key>
|
||||||
|
<string>815750722565-da8p56le8bd6apsbm9eft0jjl1rtpgkt.apps.googleusercontent.com</string>
|
||||||
|
<key>REVERSED_CLIENT_ID</key>
|
||||||
|
<string>com.googleusercontent.apps.815750722565-da8p56le8bd6apsbm9eft0jjl1rtpgkt</string>
|
||||||
|
<key>ANDROID_CLIENT_ID</key>
|
||||||
|
<string>815750722565-m14h8mkosm7cnq6uh6rhqr54dn02d705.apps.googleusercontent.com</string>
|
||||||
|
<key>API_KEY</key>
|
||||||
|
<string>AIzaSyDiXnCO00li4V7Ioa2YZ_M4ECxRsu_P9tA</string>
|
||||||
|
<key>GCM_SENDER_ID</key>
|
||||||
|
<string>815750722565</string>
|
||||||
|
<key>PLIST_VERSION</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>BUNDLE_ID</key>
|
||||||
|
<string>com.HMG.Smartphone</string>
|
||||||
|
<key>PROJECT_ID</key>
|
||||||
|
<string>api-project-815750722565</string>
|
||||||
|
<key>STORAGE_BUCKET</key>
|
||||||
|
<string>api-project-815750722565.appspot.com</string>
|
||||||
|
<key>IS_ADS_ENABLED</key>
|
||||||
|
<false></false>
|
||||||
|
<key>IS_ANALYTICS_ENABLED</key>
|
||||||
|
<false></false>
|
||||||
|
<key>IS_APPINVITE_ENABLED</key>
|
||||||
|
<true></true>
|
||||||
|
<key>IS_GCM_ENABLED</key>
|
||||||
|
<true></true>
|
||||||
|
<key>IS_SIGNIN_ENABLED</key>
|
||||||
|
<true></true>
|
||||||
|
<key>GOOGLE_APP_ID</key>
|
||||||
|
<string>1:815750722565:ios:328ec247a81a2ca23c186c</string>
|
||||||
|
<key>DATABASE_URL</key>
|
||||||
|
<string>https://api-project-815750722565.firebaseio.com</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"client":{
|
||||||
|
"appType":"1",
|
||||||
|
"cp_id":"2640966000002322881",
|
||||||
|
"product_id":"736430079244816576",
|
||||||
|
"client_id":"563737844552565952",
|
||||||
|
"client_secret":"9C9A2C272576B8AE6E886C78AF944E8354B91F0AF3381129BB8369FB35E41C47",
|
||||||
|
"project_id":"736430079244816576",
|
||||||
|
"app_id":"103856487",
|
||||||
|
"api_key":"CgB6e3x90XxBrOCMun809w+DOzcFEettcBDUF3fqaLry1ViqTeJqoPwpfaOq/uGw//x0oYwucu9aWazs+Rdj0GUF",
|
||||||
|
"package_name":"com.cloud.diplomaticquarterapp"
|
||||||
|
},
|
||||||
|
"configuration_version":"1.0"
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"client":{
|
||||||
|
"appType":"1",
|
||||||
|
"cp_id":"2640966000002322881",
|
||||||
|
"product_id":"736430079244816567",
|
||||||
|
"client_id":"563735388191982656",
|
||||||
|
"client_secret":"650C7C799812AFFD53A10C7756CF05FB9F215A7E49032ABA8EBF3E14B77535CF",
|
||||||
|
"project_id":"736430079244816567",
|
||||||
|
"app_id":"102857389",
|
||||||
|
"api_key":"CgB6e3x9DJzMgRCmnT6dyUEkp6UsIfddb6l3w0ZEXzeiRMHEFi3400Z5fJ5qaHneU0OrAI/JRpk+DMGVs3QpUxlI",
|
||||||
|
"package_name":"com.ejada.hmg"
|
||||||
|
},
|
||||||
|
"configuration_version":"1.0"
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
-keep class tvi.webrtc.** { *; }
|
||||||
|
-keep class com.twilio.video.** { *; }
|
||||||
|
-keep class com.twilio.common.** { *; }
|
||||||
|
-keepattributes InnerClasses
|
||||||
@ -1,13 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
package com.cloud.diplomaticquarterapp.geofence
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
|
|
||||||
class GeofenceBroadcastReceiver : BroadcastReceiver() {
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
|
||||||
GeofenceTransitionsJobIntentService.enqueueWork(context, intent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
|
||||||
|
package com.cloud.diplomaticquarterapp.geofence.intent_receivers
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.util.Log
|
||||||
|
import com.cloud.diplomaticquarterapp.geofence.GeofenceTransition
|
||||||
|
import com.cloud.diplomaticquarterapp.geofence.HMG_Geofence
|
||||||
|
import com.cloud.diplomaticquarterapp.utils.Logs
|
||||||
|
import com.google.android.gms.location.GeofenceStatusCodes
|
||||||
|
import com.google.android.gms.location.GeofencingEvent
|
||||||
|
|
||||||
|
class GeofenceBroadcastReceiver : BroadcastReceiver() {
|
||||||
|
private val LOG_TAG = "GeofenceBroadcastReceiver"
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
|
||||||
|
val geofencingEvent = GeofencingEvent.fromIntent(intent)
|
||||||
|
if (geofencingEvent.hasError()) {
|
||||||
|
val errorMessage = GeofenceErrorMessages.getErrorString(context, geofencingEvent.errorCode)
|
||||||
|
Log.e(LOG_TAG, errorMessage)
|
||||||
|
|
||||||
|
Logs.GeofenceEvent.save(context,LOG_TAG,"Error while triggering geofence event",Logs.STATUS.ERROR)
|
||||||
|
doReRegisterIfRequired(context,geofencingEvent.errorCode)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Logs.GeofenceEvent.save(context,LOG_TAG,"Geofence event triggered: ${GeofenceTransition.fromInt(geofencingEvent.geofenceTransition).value} for ${geofencingEvent.triggeringGeofences.map {it.requestId}}",Logs.STATUS.SUCCESS)
|
||||||
|
HMG_Geofence.shared(context).handleEvent(geofencingEvent.triggeringGeofences,geofencingEvent.triggeringLocation, GeofenceTransition.fromInt(geofencingEvent.geofenceTransition));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun doReRegisterIfRequired(context: Context, errorCode: Int){
|
||||||
|
val errorRequiredReregister = listOf(
|
||||||
|
GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE,
|
||||||
|
GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES,
|
||||||
|
GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS,
|
||||||
|
GeofenceStatusCodes.GEOFENCE_REQUEST_TOO_FREQUENT
|
||||||
|
)
|
||||||
|
|
||||||
|
if(errorRequiredReregister.contains(errorCode))
|
||||||
|
HMG_Geofence.shared(context).register(){ status, error ->
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
package com.cloud.diplomaticquarterapp.geofence.intent_receivers
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import com.cloud.diplomaticquarterapp.geofence.HMG_Geofence
|
||||||
|
import com.google.android.gms.location.GeofenceStatusCodes
|
||||||
|
|
||||||
|
class GeofenceBroadcastReceiverWithJobService : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
GeofenceTransitionsJobIntentService.enqueueWork(context, intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,26 +1,22 @@
|
|||||||
|
|
||||||
|
|
||||||
package com.cloud.diplomaticquarterapp.geofence
|
package com.cloud.diplomaticquarterapp.geofence.intent_receivers
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Message
|
|
||||||
import com.cloud.diplomaticquarterapp.geofence.HMG_Geofence
|
import com.cloud.diplomaticquarterapp.geofence.HMG_Geofence
|
||||||
import com.cloud.diplomaticquarterapp.utils.HMGUtils
|
import com.cloud.diplomaticquarterapp.utils.PREFS_STORAGE
|
||||||
|
|
||||||
class GeofencingRebootBroadcastReceiver : BroadcastReceiver(){
|
class GeofencingRebootBroadcastReceiver : BroadcastReceiver(){
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
|
||||||
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.action)) {
|
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.action)) {
|
||||||
|
// if (intent.action.equals("android.intent.action.BOOT_COMPLETE")) {
|
||||||
val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
|
val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
|
||||||
pref.edit().putString("REBOOT_DETECTED","YES").apply()
|
pref.edit().putString("REBOOT_DETECTED","YES").apply()
|
||||||
|
|
||||||
HMG_Geofence.shared(context).unRegisterAll { status, exception ->
|
HMG_Geofence.shared(context).register(){ status, error -> }
|
||||||
val geoZones = HMGUtils.getGeoZonesFromPreference(context)
|
|
||||||
HMG_Geofence.shared(context).register(geoZones)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
|
||||||
|
package com.cloud.diplomaticquarterapp.geofence.intent_receivers
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.location.LocationManager
|
||||||
|
import com.cloud.diplomaticquarterapp.geofence.HMG_Geofence
|
||||||
|
import com.cloud.diplomaticquarterapp.utils.HMGUtils
|
||||||
|
import com.cloud.diplomaticquarterapp.utils.PREFS_STORAGE
|
||||||
|
|
||||||
|
class LocationProviderChangeReceiver : BroadcastReceiver() {
|
||||||
|
private val LOG_TAG = "LocationProviderChangeReceiver"
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
|
||||||
|
if (LocationManager.PROVIDERS_CHANGED_ACTION.equals(intent.action)) {
|
||||||
|
val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
|
||||||
|
pref.edit().putString("LOCATION_PROVIDER_CHANGE","YES").apply()
|
||||||
|
|
||||||
|
HMG_Geofence.shared(context).register(){ s, e -> }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package com.cloud.diplomaticquarterapp.geofence.intent_receivers
|
||||||
|
|
||||||
|
import android.app.job.JobParameters
|
||||||
|
import android.app.job.JobService
|
||||||
|
import com.cloud.diplomaticquarterapp.geofence.HMG_Geofence
|
||||||
|
import com.cloud.diplomaticquarterapp.utils.Logs
|
||||||
|
|
||||||
|
class ReregisterGeofenceJobService : JobService(){
|
||||||
|
companion object{
|
||||||
|
val TriggerIntervalDuration:String = "06:00:00"
|
||||||
|
val JobID = 918273
|
||||||
|
}
|
||||||
|
override fun onStartJob(params: JobParameters?): Boolean {
|
||||||
|
Logs.save(applicationContext,"ReregisterGeofenceJobService.onStartJob", "triggered to re-register the geofences after $TriggerIntervalDuration >> [HH:mm:ss]")
|
||||||
|
HMG_Geofence.shared(applicationContext).register(){ status, error ->
|
||||||
|
jobFinished(params, true)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStopJob(params: JobParameters?): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package com.cloud.diplomaticquarterapp.utils
|
||||||
|
|
||||||
|
|
||||||
|
const val PREFS_STORAGE = "FlutterSharedPreferences"
|
||||||
|
const val PREF_KEY_SUCCESS = "HMG_GEOFENCE_SUCCESS"
|
||||||
|
const val PREF_KEY_FAILED = "HMG_GEOFENCE_FAILED"
|
||||||
|
const val PREF_KEY_HMG_ZONES = "flutter.hmg-geo-fences"
|
||||||
|
const val PREF_KEY_LANGUAGE = "flutter.language"
|
||||||
@ -0,0 +1,145 @@
|
|||||||
|
package com.cloud.diplomaticquarterapp.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.os.Build
|
||||||
|
import com.cloud.diplomaticquarterapp.BuildConfig
|
||||||
|
import com.google.gson.Gson
|
||||||
|
|
||||||
|
class Logs {
|
||||||
|
|
||||||
|
enum class STATUS{
|
||||||
|
SUCCESS,
|
||||||
|
ERROR;
|
||||||
|
}
|
||||||
|
class GeofenceEvent{
|
||||||
|
companion object{
|
||||||
|
fun save(context: Context, tag:String, message:String, status:Logs.STATUS = STATUS.SUCCESS){
|
||||||
|
Logs.Common.save(context,"GeofenceEvent", tag, message, status)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun list(context: Context, tag:String? = null, status:Logs.STATUS? = null):List<LogModel>{
|
||||||
|
return Logs.Common.list(context,"GeofenceEvent", tag, status)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun raw(context: Context):String{
|
||||||
|
return Logs.Common.raw(context,"GeofenceEvent")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RegisterGeofence{
|
||||||
|
companion object{
|
||||||
|
fun save(context: Context, tag:String, message:String, status:Logs.STATUS = STATUS.SUCCESS){
|
||||||
|
Logs.Common.save(context,"RegisterGeofence", tag, message, status)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun list(context: Context, tag:String? = null, status:Logs.STATUS? = null):List<LogModel>{
|
||||||
|
return Logs.Common.list(context,"RegisterGeofence", tag, status)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun raw(context: Context):String{
|
||||||
|
return Logs.Common.raw(context,"RegisterGeofence");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object{
|
||||||
|
private var pref:SharedPreferences? = null
|
||||||
|
fun save(context: Context, tag:String, message:String, status:Logs.STATUS = STATUS.SUCCESS){
|
||||||
|
Logs.Common.save(context,"Logs", tag, message, status)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun list(context: Context, tag:String? = null, status:Logs.STATUS? = null):List<LogModel>{
|
||||||
|
return Logs.Common.list(context,"Logs", tag, status)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun raw(context: Context):String{
|
||||||
|
return Logs.Common.raw(context,"Logs");
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun storage(context: Context):SharedPreferences{
|
||||||
|
if(pref == null) {
|
||||||
|
pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
|
||||||
|
}
|
||||||
|
return pref!!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Common{
|
||||||
|
companion object{
|
||||||
|
private val gson = Gson()
|
||||||
|
|
||||||
|
fun save(context: Context, key:String, tag:String, message:String, status:Logs.STATUS = STATUS.SUCCESS){
|
||||||
|
if(!BuildConfig.DEBUG)
|
||||||
|
return
|
||||||
|
|
||||||
|
val pref = Logs.storage(context)
|
||||||
|
|
||||||
|
val string = pref.getString(key,"{}")
|
||||||
|
val json = gson.fromJson<LogsContainerModel>(string,LogsContainerModel::class.java)
|
||||||
|
json.add(
|
||||||
|
LogModel().apply {
|
||||||
|
this.TAG = tag
|
||||||
|
this.MESSAGE = message
|
||||||
|
this.STATUS = status.name
|
||||||
|
this.DATE = DateUtils.dateTimeNow()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
pref.edit().putString(key,gson.toJson(json)).apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun list(context: Context, key:String, tag:String? = null, status:Logs.STATUS? = null):List<LogModel>{
|
||||||
|
val pref = Logs.storage(context)
|
||||||
|
val string = pref.getString(key,"{}")
|
||||||
|
val json = gson.fromJson<LogsContainerModel>(string,LogsContainerModel::class.java)
|
||||||
|
if(tag == null && status == null) {
|
||||||
|
return json.LOGS
|
||||||
|
}else if(tag != null && status != null){
|
||||||
|
return json.LOGS.filter { (it.TAG == tag && it.STATUS == status.name) }
|
||||||
|
}else if(tag != null){
|
||||||
|
return json.LOGS.filter { (it.TAG == tag) }
|
||||||
|
}else if(status != null){
|
||||||
|
return json.LOGS.filter { (it.STATUS == status.name) }
|
||||||
|
}
|
||||||
|
return listOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun raw(context: Context, key:String):String{
|
||||||
|
val pref = Logs.storage(context)
|
||||||
|
val string = pref.getString(key,"{}")
|
||||||
|
return string!!
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LogModel{
|
||||||
|
lateinit var TAG:String
|
||||||
|
lateinit var MESSAGE:String
|
||||||
|
lateinit var STATUS:String
|
||||||
|
lateinit var DATE:String
|
||||||
|
|
||||||
|
companion object{
|
||||||
|
fun with(tag:String, message:String, status:String):LogModel{
|
||||||
|
return LogModel().apply {
|
||||||
|
this.TAG = tag
|
||||||
|
this.MESSAGE = message
|
||||||
|
this.STATUS = status
|
||||||
|
this.DATE = DateUtils.dateTimeNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LogsContainerModel{
|
||||||
|
var LOGS = mutableListOf<LogModel>()
|
||||||
|
fun add(log:LogModel){
|
||||||
|
LOGS.add(log)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 102 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
@ -0,0 +1,26 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="103.843" height="79.732" viewBox="0 0 103.843 79.732">
|
||||||
|
<g id="Group_776" data-name="Group 776" transform="translate(-67.806 -333.834)">
|
||||||
|
<g id="Group_772" data-name="Group 772" transform="translate(72.721 385.261)">
|
||||||
|
<path id="Rectangle_494" data-name="Rectangle 494" d="M3.513,0h5.5a3.512,3.512,0,0,1,3.512,3.512V24.794a3.512,3.512,0,0,1-3.512,3.512h-5.5A3.512,3.512,0,0,1,0,24.793V3.513A3.513,3.513,0,0,1,3.513,0Z" transform="translate(81.49)" fill="#404040"/>
|
||||||
|
<path id="Rectangle_495" data-name="Rectangle 495" d="M3.513,0h5.5a3.512,3.512,0,0,1,3.512,3.512V24.794a3.512,3.512,0,0,1-3.512,3.512h-5.5A3.512,3.512,0,0,1,0,24.793V3.513A3.513,3.513,0,0,1,3.513,0Z" transform="translate(0)" fill="#404040"/>
|
||||||
|
</g>
|
||||||
|
<g id="Group_774" data-name="Group 774" transform="translate(67.806 333.834)">
|
||||||
|
<g id="Group_773" data-name="Group 773" transform="translate(0 20.106)">
|
||||||
|
<path id="Path_964" data-name="Path 964" d="M202.791,368.713a2.117,2.117,0,0,1-1.4,1.881l.87,1.595a2.144,2.144,0,0,1,2.578-.721h.784v-2.755Z" transform="translate(-108.451 -364.552)" fill="#b2361d"/>
|
||||||
|
<path id="Path_965" data-name="Path 965" d="M212.887,366.617c.07,1.4-1.91,2.76-3.882,3.26-2.9.735-5.653-.648-5.653-3.515,0-2.783,1.939-4.222,4.769-3.4C210.072,363.532,212.818,365.233,212.887,366.617Z" transform="translate(-109.046 -362.733)" fill="#d84c2f"/>
|
||||||
|
<path id="Path_966" data-name="Path 966" d="M80.223,368.713a2.116,2.116,0,0,0,1.4,1.881l-.87,1.595a2.144,2.144,0,0,0-2.578-.721h-.785v-2.755Z" transform="translate(-70.722 -364.552)" fill="#b2361d"/>
|
||||||
|
<path id="Path_967" data-name="Path 967" d="M67.808,366.617c-.07,1.4,1.909,2.76,3.882,3.26,2.9.735,5.654-.648,5.654-3.515,0-2.783-1.939-4.222-4.769-3.4C70.623,363.532,67.877,365.233,67.808,366.617Z" transform="translate(-67.806 -362.733)" fill="#d84c2f"/>
|
||||||
|
</g>
|
||||||
|
<path id="Path_968" data-name="Path 968" d="M168.258,369.52c-.522-3.479-3.218-7.392-4.7-10.349s-6.929-16.872-8.262-19.307a10.983,10.983,0,0,0-7.653-5.435c-3.479-.522-18.843-.594-25.511-.594s-22.032.072-25.51.594a10.981,10.981,0,0,0-7.653,5.435c-1.334,2.435-6.784,16.35-8.262,19.307s-4.174,6.871-4.7,10.349-.348,24.09.522,27.482a7.356,7.356,0,0,0,6.61,5.479h77.982a7.356,7.356,0,0,0,6.61-5.479C168.606,393.61,168.78,373,168.258,369.52Z" transform="translate(-70.214 -333.834)" fill="#d84c2f"/>
|
||||||
|
<path id="Path_969" data-name="Path 969" d="M75.773,405.294c.09,5.924.349,11.778.779,13.45a7.356,7.356,0,0,0,6.61,5.479h77.982a7.356,7.356,0,0,0,6.61-5.479c.429-1.671.687-7.525.779-13.45Z" transform="translate(-70.23 -355.576)" fill="#d63828"/>
|
||||||
|
<path id="Path_970" data-name="Path 970" d="M160.494,364.834s4.871,7.37,5.508,9.221.725,3.533-1.1,4.374-15.567,4.261-18.7,4.261H101.385c-3.131,0-16.872-3.42-18.7-4.261s-1.739-2.522-1.1-4.374,5.508-9.221,5.508-9.221" transform="translate(-71.873 -343.266)" fill="none" stroke="#b2361d" stroke-miterlimit="10" stroke-width="0.5"/>
|
||||||
|
</g>
|
||||||
|
<path id="Path_971" data-name="Path 971" d="M165.792,420.908a1.465,1.465,0,0,1-1.364,2.224H83.859a1.465,1.465,0,0,1-1.364-2.224l1.75-4.285a3.366,3.366,0,0,1,2.887-1.956h74.025a3.364,3.364,0,0,1,2.887,1.956Z" transform="translate(-4.416 -24.593)" fill="#404040"/>
|
||||||
|
<path id="Path_972" data-name="Path 972" d="M152.824,394.283c-.522-1.565-2.783-2.783-5.044-2.783h-26.96c-2.261,0-4.522,1.218-5.044,2.783s1.826,8.009,2.7,9.179,1.826,1.46,4.609,1.46h22.438c2.783,0,3.74-.29,4.609-1.46S153.346,395.848,152.824,394.283Z" transform="translate(-14.572 -17.545)" fill="#404040"/>
|
||||||
|
<path id="Path_973" data-name="Path 973" d="M163.631,358.436c-.435-1.508-4.609-12.147-5.827-14.669s-2.87-3.392-4.088-3.392H98c-1.218,0-2.87.87-4.088,3.392s-5.392,13.161-5.827,14.669.261,2.2,1.391,2.2h72.764C163.37,360.639,164.066,359.943,163.631,358.436Z" transform="translate(-6.13 -1.99)" fill="#404040"/>
|
||||||
|
<g id="Group_775" data-name="Group 775" transform="translate(76.803 368.998)">
|
||||||
|
<path id="Path_974" data-name="Path 974" d="M175.9,389.332s3.827,4.783,5.74,4.783h11.045a2.421,2.421,0,0,0,2.522-2,23,23,0,0,0,0-7.74A90.156,90.156,0,0,1,175.9,389.332Z" transform="translate(-109.692 -384.375)" fill="#fff"/>
|
||||||
|
<path id="Path_975" data-name="Path 975" d="M100.374,389.332s-3.827,4.783-5.74,4.783H83.589a2.421,2.421,0,0,1-2.522-2,23,23,0,0,1,0-7.74A90.156,90.156,0,0,0,100.374,389.332Z" transform="translate(-80.738 -384.375)" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
@ -0,0 +1,6 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="14.769" viewBox="0 0 16 14.769">
|
||||||
|
<g id="Group_1463" data-name="Group 1463" transform="translate(-236)">
|
||||||
|
<path id="Icon_ionic-md-heart-empty" data-name="Icon ionic-md-heart-empty" d="M14.975,4.5a4.732,4.732,0,0,0-3.6,1.688A4.732,4.732,0,0,0,7.775,4.5a4.35,4.35,0,0,0-4.4,4.427c0,3.058,2.719,5.512,6.838,9.3l1.162,1.046,1.162-1.046c4.119-3.785,6.838-6.238,6.838-9.3A4.35,4.35,0,0,0,14.975,4.5ZM11.867,17.165l-.162.15-.331.3-.331-.3-.162-.15a48.887,48.887,0,0,1-4.719-4.692A5.643,5.643,0,0,1,4.61,8.927a3.2,3.2,0,0,1,.912-2.281,3.13,3.13,0,0,1,2.254-.915,3.527,3.527,0,0,1,2.658,1.25L11.375,8.1l.942-1.119a3.514,3.514,0,0,1,2.658-1.25,3.145,3.145,0,0,1,2.258.915,3.206,3.206,0,0,1,.912,2.281,5.673,5.673,0,0,1-1.554,3.546A48.986,48.986,0,0,1,11.867,17.165Z" transform="translate(232.625 -4.5)" fill="#ed1c2b"/>
|
||||||
|
<path id="Path_1790" data-name="Path 1790" d="M251.438,12.227,249.66,10.76l-3.555.651a15.239,15.239,0,0,0-1.295,2.378c.072.2,1.295,4.436,1.295,4.436l4.258,4.295,1.609,1.241L253.7,22.52l3.551-3.5,1.979-3.813-.72-3.488-1.741-.962-3.069.651-1.883,1.342Z" transform="translate(-8 -10)" fill="#ed1c2b" stroke="#ed1c2b" stroke-width="1"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="14.769" viewBox="0 0 16 14.769">
|
||||||
|
<path id="Icon_ionic-md-heart-empty" data-name="Icon ionic-md-heart-empty" d="M14.975,4.5a4.732,4.732,0,0,0-3.6,1.688A4.732,4.732,0,0,0,7.775,4.5a4.35,4.35,0,0,0-4.4,4.427c0,3.058,2.719,5.512,6.838,9.3l1.162,1.046,1.162-1.046c4.119-3.785,6.838-6.238,6.838-9.3A4.35,4.35,0,0,0,14.975,4.5ZM11.867,17.165l-.162.15-.331.3-.331-.3-.162-.15a48.887,48.887,0,0,1-4.719-4.692A5.643,5.643,0,0,1,4.61,8.927a3.2,3.2,0,0,1,.912-2.281,3.13,3.13,0,0,1,2.254-.915,3.527,3.527,0,0,1,2.658,1.25L11.375,8.1l.942-1.119a3.514,3.514,0,0,1,2.658-1.25,3.145,3.145,0,0,1,2.258.915,3.206,3.206,0,0,1,.912,2.281,5.673,5.673,0,0,1-1.554,3.546A48.986,48.986,0,0,1,11.867,17.165Z" transform="translate(-3.375 -4.5)" fill="#b5b5b5"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 804 B |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 212 B |
|
After Width: | Height: | Size: 194 KiB |
|
After Width: | Height: | Size: 132 KiB |
@ -0,0 +1,37 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 299.19 299.19">
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
.cls-1 {
|
||||||
|
fill: #a02228;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cls-2 {
|
||||||
|
fill: #c42829;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cls-3, .cls-4 {
|
||||||
|
fill: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cls-4 {
|
||||||
|
font-size: 63.99px;
|
||||||
|
font-family: GESSTwoMedium-Medium, GE SS Two;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g id="Layer_2" data-name="Layer 2">
|
||||||
|
<g id="Layer_1-2" data-name="Layer 1">
|
||||||
|
<g>
|
||||||
|
<rect class="cls-1" x="154.78" width="144.13" height="42.56"/>
|
||||||
|
<rect class="cls-1" y="154.77" width="42.56" height="144.13"/>
|
||||||
|
<polygon class="cls-2" points="0 154.31 154.31 0 299.19 0 0 299.19 0 154.31"/>
|
||||||
|
<g>
|
||||||
|
<polygon class="cls-2" points="14.51 160.32 160.32 14.51 264.16 14.51 14.51 264.16 14.51 160.32"/>
|
||||||
|
<path class="cls-3" d="M259.49,16.44l-243,243.05V161.12L161.12,16.44Zm9.34-3.86H159.52L12.58,159.52V268.83L268.83,12.58Z"/>
|
||||||
|
</g>
|
||||||
|
<text class="cls-4" transform="translate(64.37 181.67) rotate(-45)">مصخ</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 312.6 292.7" style="enable-background:new 0 0 312.6 292.7;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#A02228;}
|
||||||
|
.st1{fill:#C42829;}
|
||||||
|
.st2{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<g id="Layer_2_1_">
|
||||||
|
<g id="Layer_1-2">
|
||||||
|
<g>
|
||||||
|
<rect x="152.5" y="1" class="st0" width="141.2" height="41.7"/>
|
||||||
|
<rect x="0.9" y="152.6" class="st0" width="41.7" height="141.2"/>
|
||||||
|
<polygon class="st1" points="0.9,152.2 152.1,1 294,1 0.9,294.1 "/>
|
||||||
|
<g>
|
||||||
|
<polygon class="st1" points="15.1,158.1 158,15.2 259.7,15.2 15.1,259.8 "/>
|
||||||
|
<path class="st2" d="M255.1,17.1l-238,238.1v-96.4L158.7,17.1H255.1z M264.3,13.3H157.2L13.2,157.3v107.1
|
||||||
|
C13.2,264.4,264.3,13.3,264.3,13.3z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st2" d="M30.9,176.1l7.3-7.3c6.3-6.3,13.6-6.2,19.3-0.5c5.3,5.3,5.4,12.8-0.7,18.9l-7.4,7.4L30.9,176.1z
|
||||||
|
M49.9,186.6l3-3c3.8-3.8,3.6-7.8,0.4-11c-3.5-3.5-7.5-3.6-11.4,0.3l-2.9,2.9L49.9,186.6z"/>
|
||||||
|
<path class="st2" d="M50.8,156.2L55,152l18.5,18.5l-4.2,4.2L50.8,156.2z"/>
|
||||||
|
<path class="st2" d="M67.9,149.1c1.4,1.4,3.5,0.6,6.3-1.4c5.6-3.8,8.9-4.5,12.4-1c3.3,3.3,2.8,8.5-1.9,13.2
|
||||||
|
c-1.8,1.8-4,3.2-6.5,3.9c-2.6,0.7-5.4,0.4-7.8-0.8l1.3-5.8c3,1.9,7,1.4,9.4-1.2c2-1.9,2.5-3.8,1.4-5c-1.1-1.1-2.7-1.1-6.5,1.7
|
||||||
|
c-4.5,3.4-8.9,4.1-12.4,0.6c-2.9-2.9-2.6-7.9,1.6-12.1c3.5-3.5,7.7-4.5,11.8-2.5l-1.5,5.4c-2.8-1.4-4.9-1.2-6.9,0.8
|
||||||
|
C67.2,146.4,67,148.2,67.9,149.1z"/>
|
||||||
|
<path class="st2" d="M99.9,137c3.1-3.1,3-7,0.5-10.8l5.4-2.3c3.5,5.6,2.9,11.9-2.2,16.9c-5.9,5.9-13.8,5.6-19.2,0.2
|
||||||
|
c-5.3-5.1-5.4-13.6-0.2-18.8c0.1-0.1,0.3-0.3,0.4-0.4c4.9-4.9,10.7-5.3,14.9-2.6l-2.1,5.6c-2.8-2-6.7-1.6-9.1,0.9
|
||||||
|
c-2.9,2.9-3.1,7.6,0.3,11.1c2.8,3.1,7.7,3.4,10.8,0.6C99.7,137.2,99.8,137.1,99.9,137z"/>
|
||||||
|
<path class="st2" d="M125.2,100.4c5.3,5.1,5.2,14.1-0.3,19.3c-5.2,5.4-14.3,5.5-19.3,0.3c-5.3-5.1-5.2-14.1,0.3-19.3
|
||||||
|
C111.1,95.2,120.1,95.1,125.2,100.4z M120.9,104.6c-3.1-3.1-8-3-11.1,0c-3.1,3.1-3,8,0,11.1c3.1,3,8,3,11,0
|
||||||
|
c3.2-2.6,4-7.1,1.3-10.3C121.9,105,121.6,104.6,120.9,104.6z"/>
|
||||||
|
<path class="st2" d="M122.7,84.3l11,11c2.4,2.4,5.2,2.7,7.5,0.4c2.3-2.3,2-5.1-0.4-7.5l-11-11L134,73l11,11
|
||||||
|
c4.8,4.8,4.8,10.8,0,15.6c-4.8,4.8-10.9,4.8-15.6,0l-11-11L122.7,84.3z"/>
|
||||||
|
<path class="st2" d="M160,84l-4.2,4.2l-18.5-18.5l7.2-7.2l22.5,8.9l-15.7-15.7l4.2-4.2L174.1,70l-7.2,7.2l-22.5-8.9L160,84z"/>
|
||||||
|
<path class="st2" d="M178.6,36.1l-6.3,6.3l14.7,14.7l-4.2,4.2L168,46.7l-6.4,6.4l-3.8-3.8l16.9-16.9L178.6,36.1z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 19 KiB |
@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🐛 Bug Report
|
||||||
|
|
||||||
|
<!--- Summary description of the bug --->
|
||||||
|
|
||||||
|
### Expected behavior
|
||||||
|
|
||||||
|
### Reproduction steps
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
**Version:** 0.1.x
|
||||||
|
|
||||||
|
**Platform:**
|
||||||
|
- [ ] :iphone: iOS
|
||||||
|
- [ ] :robot: Android
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Feature Requests
|
||||||
|
|
||||||
|
<!--- Summary description of the feature --->
|
||||||
|
|
||||||
|
### Contextualize the feature
|
||||||
|
<!--- Where does it fit in the framework and why it's being included there. --->
|
||||||
|
|
||||||
|
### Describe the feature
|
||||||
|
<!--- Use as much detail as possible here! --->
|
||||||
|
|
||||||
|
### Platforms affected (mark all that apply)
|
||||||
|
- [ ] :iphone: iOS
|
||||||
|
- [ ] :robot: Android
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
name: Questions and Help
|
||||||
|
about: If you have questions, please use this for support
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💬 Questions and Help
|
||||||
|
|
||||||
|
Provide question related to this flutter plugin.
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
name: github pages
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Setup Flutter
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/flutter/flutter.git --depth 1 -b beta _flutter
|
||||||
|
echo "::add-path::${GITHUB_WORKSPACE}/_flutter/bin"
|
||||||
|
|
||||||
|
- name: Install
|
||||||
|
run: |
|
||||||
|
cd example
|
||||||
|
flutter config --enable-web
|
||||||
|
flutter pub get
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cd example
|
||||||
|
flutter build web
|
||||||
|
|
||||||
|
- name: Deploy
|
||||||
|
uses: peaceiris/actions-gh-pages@v3
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
publish_dir: ./example/build/web
|
||||||
@ -0,0 +1,94 @@
|
|||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.lock
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.project
|
||||||
|
.svn/
|
||||||
|
bin/
|
||||||
|
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Android Studio related
|
||||||
|
android/.classpath
|
||||||
|
android/.settings/
|
||||||
|
|
||||||
|
# Visual Studio Code related
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# Flutter repo-specific
|
||||||
|
/bin/cache/
|
||||||
|
/bin/mingit/
|
||||||
|
/dev/benchmarks/mega_gallery/
|
||||||
|
/dev/bots/.recipe_deps
|
||||||
|
/dev/bots/android_tools/
|
||||||
|
/dev/docs/doc/
|
||||||
|
/dev/docs/lib/
|
||||||
|
/dev/docs/pubspec.yaml
|
||||||
|
/packages/flutter/coverage/
|
||||||
|
version
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
**/doc/api/
|
||||||
|
.dart_tool/
|
||||||
|
.flutter-plugins
|
||||||
|
.packages
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
|
build/
|
||||||
|
flutter_*.png
|
||||||
|
linked_*.ds
|
||||||
|
unlinked.ds
|
||||||
|
unlinked_spec.ds
|
||||||
|
|
||||||
|
# Android related
|
||||||
|
**/android/**/gradle-wrapper.jar
|
||||||
|
**/android/.gradle
|
||||||
|
**/android/captures/
|
||||||
|
**/android/gradlew
|
||||||
|
**/android/gradlew.bat
|
||||||
|
**/android/local.properties
|
||||||
|
**/android/**/GeneratedPluginRegistrant.java
|
||||||
|
|
||||||
|
# iOS/XCode related
|
||||||
|
**/ios/**/*.mode1v3
|
||||||
|
**/ios/**/*.mode2v3
|
||||||
|
**/ios/**/*.moved-aside
|
||||||
|
**/ios/**/*.pbxuser
|
||||||
|
**/ios/**/*.perspectivev3
|
||||||
|
**/ios/**/*sync/
|
||||||
|
**/ios/**/.sconsign.dblite
|
||||||
|
**/ios/**/.tags*
|
||||||
|
**/ios/**/.vagrant/
|
||||||
|
**/ios/**/DerivedData/
|
||||||
|
**/ios/**/Icon?
|
||||||
|
**/ios/**/Pods/
|
||||||
|
**/ios/**/.symlinks/
|
||||||
|
**/ios/**/profile
|
||||||
|
**/ios/**/xcuserdata
|
||||||
|
**/ios/.generated/
|
||||||
|
**/ios/Flutter/App.framework
|
||||||
|
**/ios/Flutter/Flutter.framework
|
||||||
|
**/ios/Flutter/Generated.xcconfig
|
||||||
|
**/ios/Flutter/app.flx
|
||||||
|
**/ios/Flutter/app.zip
|
||||||
|
**/ios/Flutter/flutter_assets/
|
||||||
|
**/ios/ServiceDefinitions.json
|
||||||
|
**/ios/Runner/GeneratedPluginRegistrant.*
|
||||||
|
|
||||||
|
# Exceptions to above rules.
|
||||||
|
!**/ios/**/default.mode1v3
|
||||||
|
!**/ios/**/default.mode2v3
|
||||||
|
!**/ios/**/default.pbxuser
|
||||||
|
!**/ios/**/default.perspectivev3
|
||||||
|
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
|
||||||
|
example/ios/Flutter/flutter_export_environment.sh
|
||||||
@ -0,0 +1,197 @@
|
|||||||
|
# ChangeLog
|
||||||
|
|
||||||
|
## 1.3.0
|
||||||
|
|
||||||
|
- All: Adding await speak completion
|
||||||
|
|
||||||
|
## 1.2.7
|
||||||
|
|
||||||
|
- iOS: Adding utterance settings to synthesizeToFile
|
||||||
|
- Android: Fix crash when utterance completes after Engine is detached
|
||||||
|
|
||||||
|
## 1.2.6
|
||||||
|
|
||||||
|
- Android: Fixing new API onAttachedToEngine call
|
||||||
|
|
||||||
|
## 1.2.5
|
||||||
|
|
||||||
|
- macOS: Adding support
|
||||||
|
|
||||||
|
## 1.2.4
|
||||||
|
|
||||||
|
- iOS: Deactivate audio session only when needed
|
||||||
|
- Android: Better exception handling for getLanguages
|
||||||
|
- Android: Adding getEngines
|
||||||
|
- Android: Adding new Android plugin APIs
|
||||||
|
|
||||||
|
## 1.2.3
|
||||||
|
|
||||||
|
- iOS: Adding synthesize to file
|
||||||
|
- iOS: Fix set category ios
|
||||||
|
|
||||||
|
## 1.2.2
|
||||||
|
|
||||||
|
- Web: Adding pause and continue
|
||||||
|
|
||||||
|
## 1.2.1
|
||||||
|
|
||||||
|
- iOS: Fix setting iOS Category
|
||||||
|
- iOS/Android: Adding additional platform calls
|
||||||
|
|
||||||
|
## 1.2.0
|
||||||
|
|
||||||
|
- iOS: Adding Set Audio Session Category
|
||||||
|
- Android: Bug fixes
|
||||||
|
|
||||||
|
## 1.1.0
|
||||||
|
|
||||||
|
- iOS: Adding Pause
|
||||||
|
- iOS: Adding set Shared Instance
|
||||||
|
|
||||||
|
## 1.0.0
|
||||||
|
|
||||||
|
- iOS/Android: Feature - Speech marks
|
||||||
|
- iOS/Android: Breaking changes to Speech rate
|
||||||
|
|
||||||
|
## 0.9.2
|
||||||
|
|
||||||
|
- iOS: Changing audio session to playAndRecord
|
||||||
|
|
||||||
|
## 0.9.1
|
||||||
|
|
||||||
|
- Android: Fixing method call error
|
||||||
|
|
||||||
|
## 0.9.0
|
||||||
|
|
||||||
|
- Android: Adding synthesize to file
|
||||||
|
|
||||||
|
## 0.8.7
|
||||||
|
|
||||||
|
- Android: Fix sporadic ANR on initialization
|
||||||
|
|
||||||
|
## 0.8.6
|
||||||
|
|
||||||
|
- iOS: Reducing volume of other sessions while TTS is playing
|
||||||
|
|
||||||
|
## 0.8.5
|
||||||
|
|
||||||
|
- Android: Fix Android async platform initialization
|
||||||
|
- Android: Removing initHandler
|
||||||
|
|
||||||
|
## 0.8.2
|
||||||
|
|
||||||
|
- Web: Adding isLanguageAvailable method
|
||||||
|
- All: Fixing isLanguageAvailable platform channel and making it case insensitive
|
||||||
|
|
||||||
|
## 0.8.0
|
||||||
|
|
||||||
|
- Web: Adding Web Support
|
||||||
|
|
||||||
|
## 0.7.0
|
||||||
|
|
||||||
|
- iOS: Adding Swift version 4.2 to podspec and correct audio playback category
|
||||||
|
|
||||||
|
## 0.6.0
|
||||||
|
|
||||||
|
- Android: AndroidX support
|
||||||
|
|
||||||
|
## 0.5.2
|
||||||
|
|
||||||
|
- Android: Bug Fix on isLanguageAvailable
|
||||||
|
|
||||||
|
## 0.5.1
|
||||||
|
|
||||||
|
- Applying flutter format to fix health suggestion
|
||||||
|
|
||||||
|
## 0.5.0
|
||||||
|
|
||||||
|
- Android: Adding silence before speak
|
||||||
|
- Android: Removing deprecated API
|
||||||
|
|
||||||
|
## 0.2.6
|
||||||
|
|
||||||
|
- IOS: Add voice selection implementation
|
||||||
|
|
||||||
|
## 0.2.5
|
||||||
|
|
||||||
|
- Android: Ensure invokeMethod runs on main thread
|
||||||
|
|
||||||
|
## 0.2.4
|
||||||
|
|
||||||
|
- Android: setting minSDK back to 21 and adding instructions to readme
|
||||||
|
- Android: Adding fallback for getLanguages and defaultLanguage
|
||||||
|
|
||||||
|
## 0.2.3
|
||||||
|
|
||||||
|
- IOS: Audio continues with the Ring/Silent switch set to silent
|
||||||
|
|
||||||
|
## 0.2.2
|
||||||
|
|
||||||
|
- Android: Fixing Locale bug
|
||||||
|
|
||||||
|
## 0.2.1
|
||||||
|
|
||||||
|
- IOS: Fixing getLanguages bug
|
||||||
|
|
||||||
|
## 0.2.0
|
||||||
|
|
||||||
|
- Android: Adding exception catch for samsung devices
|
||||||
|
- Android: Using default com.google.android.tts engine
|
||||||
|
- Android: Get and Set Voice
|
||||||
|
- Android: InitHandler
|
||||||
|
- Cleaning up the example
|
||||||
|
|
||||||
|
## 0.1.2
|
||||||
|
|
||||||
|
- Support for Android background execution
|
||||||
|
- Updating Android build gradle version to 3.2.1
|
||||||
|
|
||||||
|
## 0.1.1
|
||||||
|
|
||||||
|
- Fixing TTS bound error in the example
|
||||||
|
- Fixing default voice language not found error on Android
|
||||||
|
|
||||||
|
## 0.1.0
|
||||||
|
|
||||||
|
- Updating version for improved maintenance score
|
||||||
|
- Updating package description for improved maintenance score
|
||||||
|
|
||||||
|
## 0.0.8
|
||||||
|
|
||||||
|
- Adding analysis_options.yaml for improved health score
|
||||||
|
- Fixing info/errors from flutter analyze
|
||||||
|
|
||||||
|
## 0.0.7
|
||||||
|
|
||||||
|
- Updating SDK version in pubspec.yaml
|
||||||
|
- Adding package link to README
|
||||||
|
- Fixing language string warning received from xcode
|
||||||
|
|
||||||
|
## 0.0.6
|
||||||
|
|
||||||
|
- Android: Upgrading Gradle 4.1 to 4.4
|
||||||
|
- Android: Setting minSdk version to 21
|
||||||
|
- Android: Adding try/catch to getAvailableLanguages & getDefaultVoice methods (Issues with API 21 & 22)
|
||||||
|
|
||||||
|
## 0.0.5
|
||||||
|
|
||||||
|
- Adding IOS/Android isLanguageAvailable
|
||||||
|
- Rename setRate to setSpeechRate
|
||||||
|
|
||||||
|
## 0.0.4
|
||||||
|
|
||||||
|
- Simplify podspec for Cocoapods 1.5.0
|
||||||
|
|
||||||
|
## 0.0.3
|
||||||
|
|
||||||
|
- Adding IOS/Android speech pitch and volume
|
||||||
|
|
||||||
|
## 0.0.2
|
||||||
|
|
||||||
|
- Flutter formatting and fixing pubspec sdk versioning
|
||||||
|
|
||||||
|
## 0.0.1
|
||||||
|
|
||||||
|
- first POC :
|
||||||
|
- methods : speak, stop, setRate, setLangauge, getLanguages
|
||||||
|
- a globalHandler for completion
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to creating a positive environment include:
|
||||||
|
|
||||||
|
* Using welcoming and inclusive language
|
||||||
|
* Being respectful of differing viewpoints and experiences
|
||||||
|
* Gracefully accepting constructive criticism
|
||||||
|
* Focusing on what is best for the community
|
||||||
|
* Showing empathy towards other community members
|
||||||
|
|
||||||
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||||
|
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||||
|
|
||||||
|
## Our Responsibilities
|
||||||
|
|
||||||
|
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||||
|
|
||||||
|
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at eyedea32@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||||
|
|
||||||
|
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||||
|
|
||||||
|
[homepage]: http://contributor-covenant.org
|
||||||
|
[version]: http://contributor-covenant.org/version/1/4/
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 Daniel Lutton
|
||||||
|
|
||||||
|
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.
|
||||||
@ -0,0 +1,194 @@
|
|||||||
|
# Text To Speech
|
||||||
|
|
||||||
|
[](https://pub.dartlang.org/packages/flutter_tts)
|
||||||
|
|
||||||
|
A flutter text to speech plugin (Swift,Java)
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- [x] Android, iOS, Web, & macOS
|
||||||
|
- [x] speak
|
||||||
|
- [x] stop
|
||||||
|
- [x] get languages
|
||||||
|
- [x] set language
|
||||||
|
- [x] set speech rate
|
||||||
|
- [x] set speech volume
|
||||||
|
- [x] set speech pitch
|
||||||
|
- [x] is language available
|
||||||
|
- [x] Android, iOS
|
||||||
|
- [x] get voices
|
||||||
|
- [x] set voice
|
||||||
|
- [x] speech marks (requires iOS 7+ and Android 26+)
|
||||||
|
- [x] synthesize to file (requires iOS 13+)
|
||||||
|
- [x] iOS, Web
|
||||||
|
- [x] pause
|
||||||
|
- [x] Android
|
||||||
|
- [x] set Silence
|
||||||
|
- [x] iOS
|
||||||
|
- [x] set shared instance
|
||||||
|
- [x] set audio session category
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
## macOS
|
||||||
|
|
||||||
|
```bash
|
||||||
|
OSX version: 10.15
|
||||||
|
```
|
||||||
|
|
||||||
|
[Example App](https://github.com/dlutton/flutter_tts/tree/macOS_app) from the macOS_app branch
|
||||||
|
|
||||||
|
## Web
|
||||||
|
|
||||||
|
[Website](https://dlutton.github.io/flutter_tts) from the example directory.
|
||||||
|
|
||||||
|
## Android
|
||||||
|
|
||||||
|
Change the minimum Android sdk version to 21 (or higher) in your `android/app/build.gradle` file.
|
||||||
|
|
||||||
|
```java
|
||||||
|
minSdkVersion 21
|
||||||
|
```
|
||||||
|
|
||||||
|
## iOS
|
||||||
|
|
||||||
|
There's a known issue with integrating plugins that use Swift into a Flutter project created with the Objective-C template. [Flutter#16049](https://github.com/flutter/flutter/issues/16049)
|
||||||
|
|
||||||
|
[Example](https://github.com/dlutton/flutter_tts/blob/master/example/lib/main.dart)
|
||||||
|
|
||||||
|
To use this plugin :
|
||||||
|
|
||||||
|
- add the dependency to your [pubspec.yaml](https://github.com/dlutton/flutter_tts/blob/master/example/pubspec.yaml) file.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
dependencies:
|
||||||
|
flutter:
|
||||||
|
sdk: flutter
|
||||||
|
flutter_tts:
|
||||||
|
```
|
||||||
|
|
||||||
|
- instantiate FlutterTts
|
||||||
|
|
||||||
|
```dart
|
||||||
|
FlutterTts flutterTts = FlutterTts();
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
To set shared audio [instance](https://developer.apple.com/documentation/avfoundation/avaudiosession/1616504-sharedinstance) (iOS only):
|
||||||
|
|
||||||
|
```dart
|
||||||
|
await flutterTts.setSharedInstance(true);
|
||||||
|
```
|
||||||
|
|
||||||
|
To set audio [category and options](https://developer.apple.com/documentation/avfoundation/avaudiosession) (iOS only):
|
||||||
|
|
||||||
|
```dart
|
||||||
|
await flutterTts
|
||||||
|
.setIosAudioCategory(IosTextToSpeechAudioCategory.playAndRecord, [
|
||||||
|
IosTextToSpeechAudioCategoryOptions.allowBluetooth,
|
||||||
|
IosTextToSpeechAudioCategoryOptions.allowBluetoothA2DP,
|
||||||
|
IosTextToSpeechAudioCategoryOptions.mixWithOthers
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
To await speak completion.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
await flutterTts.awaitSpeakCompletion(true);
|
||||||
|
```
|
||||||
|
|
||||||
|
### speak, stop, getLanguages, setLanguage, setSpeechRate, setVoice, setVolume, setPitch, isLanguageAvailable, setSharedInstance
|
||||||
|
|
||||||
|
```dart
|
||||||
|
Future _speak() async{
|
||||||
|
var result = await flutterTts.speak("Hello World");
|
||||||
|
if (result == 1) setState(() => ttsState = TtsState.playing);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future _stop() async{
|
||||||
|
var result = await flutterTts.stop();
|
||||||
|
if (result == 1) setState(() => ttsState = TtsState.stopped);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<dynamic> languages = await flutterTts.getLanguages;
|
||||||
|
|
||||||
|
await flutterTts.setLanguage("en-US");
|
||||||
|
|
||||||
|
await flutterTts.setSpeechRate(1.0);
|
||||||
|
|
||||||
|
await flutterTts.setVolume(1.0);
|
||||||
|
|
||||||
|
await flutterTts.setPitch(1.0);
|
||||||
|
|
||||||
|
await flutterTts.isLanguageAvailable("en-US");
|
||||||
|
|
||||||
|
// iOS and Web only
|
||||||
|
await flutterTts.pause();
|
||||||
|
|
||||||
|
// iOS, macOS, and Android only
|
||||||
|
await flutterTts.synthesizeToFile("Hello World", Platform.isAndroid ? "tts.wav" : "tts.caf");
|
||||||
|
|
||||||
|
await flutterTts.setVoice({"name": "Karen", "locale": "en-AU"});
|
||||||
|
|
||||||
|
// iOS only
|
||||||
|
await flutterTts.setSharedInstance(true);
|
||||||
|
|
||||||
|
// Android only
|
||||||
|
await flutterTts.setSilence(2);
|
||||||
|
|
||||||
|
await flutterTts.getEngines();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Listening for platform calls
|
||||||
|
|
||||||
|
```dart
|
||||||
|
flutterTts.setStartHandler(() {
|
||||||
|
setState(() {
|
||||||
|
ttsState = TtsState.playing;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
flutterTts.setCompletionHandler(() {
|
||||||
|
setState(() {
|
||||||
|
ttsState = TtsState.stopped;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
flutterTts.setProgressHandler((String text, int startOffset, int endOffset, String word) {
|
||||||
|
setState(() {
|
||||||
|
_currentWord = word;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
flutterTts.setErrorHandler((msg) {
|
||||||
|
setState(() {
|
||||||
|
ttsState = TtsState.stopped;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
flutterTts.setCancelHandler((msg) {
|
||||||
|
setState(() {
|
||||||
|
ttsState = TtsState.stopped;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// iOS and Web
|
||||||
|
flutterTts.setPauseHandler((msg) {
|
||||||
|
setState(() {
|
||||||
|
ttsState = TtsState.paused;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
flutterTts.setContinueHandler((msg) {
|
||||||
|
setState(() {
|
||||||
|
ttsState = TtsState.continued;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
For help getting started with Flutter, view our online
|
||||||
|
[documentation](https://flutter.dev/).
|
||||||
|
|
||||||
|
For help on editing plugin code, view the [documentation](https://flutter.dev/platform-plugins/#edit-code).
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
analyzer:
|
||||||
|
strong-mode:
|
||||||
|
implicit-casts: false
|
||||||
|
errors:
|
||||||
|
unused_import: error
|
||||||
|
unused_local_variable: error
|
||||||
|
dead_code: error
|
||||||
|
linter:
|
||||||
|
rules:
|
||||||
|
- avoid_empty_else
|
||||||
|
- comment_references
|
||||||
|
- control_flow_in_finally
|
||||||
|
- empty_statements
|
||||||
|
- hash_and_equals
|
||||||
|
- only_throw_errors
|
||||||
|
- test_types_in_equals
|
||||||
|
- throw_in_finally
|
||||||
|
- unrelated_type_equality_checks
|
||||||
|
- valid_regexps
|
||||||
|
- avoid_init_to_null
|
||||||
|
- avoid_return_types_on_setters
|
||||||
|
- await_only_futures
|
||||||
|
- camel_case_types
|
||||||
|
- directives_ordering
|
||||||
|
- empty_catches
|
||||||
|
- empty_constructor_bodies
|
||||||
|
- library_names
|
||||||
|
- library_prefixes
|
||||||
|
- non_constant_identifier_names
|
||||||
|
- omit_local_variable_types
|
||||||
|
- prefer_final_fields
|
||||||
|
- prefer_is_not_empty
|
||||||
|
- prefer_typing_uninitialized_variables
|
||||||
|
- slash_for_doc_comments
|
||||||
|
- type_init_formals
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
*.iml
|
||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/workspace.xml
|
||||||
|
/.idea/libraries
|
||||||
|
.DS_Store
|
||||||
|
/build
|
||||||
|
/captures
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
def PLUGIN = "flutter_tts";
|
||||||
|
def ANDROIDX_WARNING = "flutterPluginsAndroidXWarning";
|
||||||
|
gradle.buildFinished { buildResult ->
|
||||||
|
if (buildResult.failure && !rootProject.ext.has(ANDROIDX_WARNING)) {
|
||||||
|
println ' *********************************************************'
|
||||||
|
println 'WARNING: This version of ' + PLUGIN + ' will break your Android build if it or its dependencies aren\'t compatible with AndroidX.'
|
||||||
|
println ' See https://goo.gl/CP92wY for more information on the problem and how to fix it.'
|
||||||
|
println ' This warning prints for all Android build failures. The real root cause of the error may be unrelated.'
|
||||||
|
println ' *********************************************************'
|
||||||
|
rootProject.ext.set(ANDROIDX_WARNING, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
group 'com.tundralabs.fluttertts'
|
||||||
|
version '1.0-SNAPSHOT'
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:3.4.2'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.allprojects {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'com.android.library'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 28
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion 21
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
targetSdkVersion 27
|
||||||
|
}
|
||||||
|
lintOptions {
|
||||||
|
disable 'InvalidPackage'
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
org.gradle.jvmargs=-Xmx1536M
|
||||||
|
android.useAndroidX=true
|
||||||
|
android.enableJetifier=true
|
||||||
|
android.enableR8=true
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
#Fri Sep 27 12:18:40 PDT 2019
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
|
||||||
@ -0,0 +1 @@
|
|||||||
|
rootProject.name = 'flutter_tts'
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.tundralabs.fluttertts">
|
||||||
|
|
||||||
|
</manifest>
|
||||||
@ -0,0 +1,454 @@
|
|||||||
|
package com.tundralabs.fluttertts;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.speech.tts.TextToSpeech;
|
||||||
|
import android.speech.tts.UtteranceProgressListener;
|
||||||
|
import android.speech.tts.Voice;
|
||||||
|
import android.util.Log;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import io.flutter.embedding.engine.plugins.FlutterPlugin;
|
||||||
|
import io.flutter.plugin.common.BinaryMessenger;
|
||||||
|
import io.flutter.plugin.common.MethodCall;
|
||||||
|
import io.flutter.plugin.common.MethodChannel;
|
||||||
|
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
|
||||||
|
import io.flutter.plugin.common.MethodChannel.Result;
|
||||||
|
import io.flutter.plugin.common.PluginRegistry.Registrar;
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.MissingResourceException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/** FlutterTtsPlugin */
|
||||||
|
public class FlutterTtsPlugin implements MethodCallHandler, FlutterPlugin {
|
||||||
|
private Handler handler;
|
||||||
|
private MethodChannel methodChannel;
|
||||||
|
private MethodChannel.Result speakResult;
|
||||||
|
private boolean awaitSpeakCompletion = false;
|
||||||
|
private boolean speaking = false;
|
||||||
|
private Context context;
|
||||||
|
private TextToSpeech tts;
|
||||||
|
private final String tag = "TTS";
|
||||||
|
private final String googleTtsEngine = "com.google.android.tts";
|
||||||
|
private boolean isTtsInitialized = false;
|
||||||
|
private ArrayList<Runnable> pendingMethodCalls = new ArrayList<>();
|
||||||
|
private final HashMap<String, String> utterances = new HashMap<>();
|
||||||
|
Bundle bundle;
|
||||||
|
private int silencems;
|
||||||
|
private static final String SILENCE_PREFIX = "SIL_";
|
||||||
|
private static final String SYNTHESIZE_TO_FILE_PREFIX = "STF_";
|
||||||
|
|
||||||
|
/** Plugin registration. */
|
||||||
|
public static void registerWith(Registrar registrar) {
|
||||||
|
FlutterTtsPlugin instance = new FlutterTtsPlugin();
|
||||||
|
instance.initInstance(registrar.messenger(), registrar.activeContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initInstance(BinaryMessenger messenger, Context context) {
|
||||||
|
this.context = context;
|
||||||
|
methodChannel = new MethodChannel(messenger, "flutter_tts");
|
||||||
|
methodChannel.setMethodCallHandler(this);
|
||||||
|
handler = new Handler(Looper.getMainLooper());
|
||||||
|
bundle = new Bundle();
|
||||||
|
tts = new TextToSpeech(context, onInitListener, googleTtsEngine);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Android Plugin APIs */
|
||||||
|
@Override
|
||||||
|
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
|
||||||
|
initInstance(binding.getBinaryMessenger(), binding.getApplicationContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
|
||||||
|
stop();
|
||||||
|
tts.shutdown();
|
||||||
|
context = null;
|
||||||
|
methodChannel.setMethodCallHandler(null);
|
||||||
|
methodChannel = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UtteranceProgressListener utteranceProgressListener =
|
||||||
|
new UtteranceProgressListener() {
|
||||||
|
@Override
|
||||||
|
public void onStart(String utteranceId) {
|
||||||
|
if (utteranceId != null && utteranceId.startsWith(SYNTHESIZE_TO_FILE_PREFIX)) {
|
||||||
|
invokeMethod("synth.onStart", true);
|
||||||
|
} else {
|
||||||
|
Log.d(tag, "Utterance ID has started: " + utteranceId);
|
||||||
|
invokeMethod("speak.onStart", true);
|
||||||
|
}
|
||||||
|
if (Build.VERSION.SDK_INT < 26) {
|
||||||
|
this.onProgress(utteranceId, 0, utterances.get(utteranceId).length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDone(String utteranceId) {
|
||||||
|
if (utteranceId != null && utteranceId.startsWith(SILENCE_PREFIX)) return;
|
||||||
|
if (utteranceId != null && utteranceId.startsWith(SYNTHESIZE_TO_FILE_PREFIX)) {
|
||||||
|
invokeMethod("synth.onComplete", true);
|
||||||
|
} else {
|
||||||
|
Log.d(tag, "Utterance ID has completed: " + utteranceId);
|
||||||
|
if (awaitSpeakCompletion) {
|
||||||
|
speakCompletion(1);
|
||||||
|
}
|
||||||
|
invokeMethod("speak.onComplete", true);
|
||||||
|
}
|
||||||
|
utterances.remove(utteranceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop(String utteranceId, boolean interrupted) {
|
||||||
|
Log.d(
|
||||||
|
tag,
|
||||||
|
"Utterance ID has been stopped: " + utteranceId + ". Interrupted: " + interrupted);
|
||||||
|
if (awaitSpeakCompletion) {
|
||||||
|
speaking = false;
|
||||||
|
}
|
||||||
|
invokeMethod("speak.onCancel", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onProgress(String utteranceId, int startAt, int endAt) {
|
||||||
|
if (utteranceId != null && !utteranceId.startsWith(SYNTHESIZE_TO_FILE_PREFIX)) {
|
||||||
|
final String text = utterances.get(utteranceId);
|
||||||
|
final HashMap<String, String> data = new HashMap<>();
|
||||||
|
data.put("text", text);
|
||||||
|
data.put("start", Integer.toString(startAt));
|
||||||
|
data.put("end", Integer.toString(endAt));
|
||||||
|
data.put("word", text.substring(startAt, endAt));
|
||||||
|
invokeMethod("speak.onProgress", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Requires Android 26 or later
|
||||||
|
@Override
|
||||||
|
public void onRangeStart(String utteranceId, int startAt, int endAt, int frame) {
|
||||||
|
if (utteranceId != null && !utteranceId.startsWith(SYNTHESIZE_TO_FILE_PREFIX)) {
|
||||||
|
super.onRangeStart(utteranceId, startAt, endAt, frame);
|
||||||
|
this.onProgress(utteranceId, startAt, endAt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public void onError(String utteranceId) {
|
||||||
|
if (utteranceId != null && utteranceId.startsWith(SYNTHESIZE_TO_FILE_PREFIX)) {
|
||||||
|
invokeMethod("synth.onError", "Error from TextToSpeech (synth)");
|
||||||
|
} else {
|
||||||
|
if (awaitSpeakCompletion) {
|
||||||
|
speaking = false;
|
||||||
|
}
|
||||||
|
invokeMethod("speak.onError", "Error from TextToSpeech (speak)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(String utteranceId, int errorCode) {
|
||||||
|
if (utteranceId != null && utteranceId.startsWith(SYNTHESIZE_TO_FILE_PREFIX)) {
|
||||||
|
invokeMethod("synth.onError", "Error from TextToSpeech (synth) - " + errorCode);
|
||||||
|
} else {
|
||||||
|
if (awaitSpeakCompletion) {
|
||||||
|
speaking = false;
|
||||||
|
}
|
||||||
|
invokeMethod("speak.onError", "Error from TextToSpeech (speak) - " + errorCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void speakCompletion(final int success) {
|
||||||
|
speaking = false;
|
||||||
|
handler.post(
|
||||||
|
new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
speakResult.success(success);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private TextToSpeech.OnInitListener onInitListener =
|
||||||
|
new TextToSpeech.OnInitListener() {
|
||||||
|
@Override
|
||||||
|
public void onInit(int status) {
|
||||||
|
if (status == TextToSpeech.SUCCESS) {
|
||||||
|
tts.setOnUtteranceProgressListener(utteranceProgressListener);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Locale locale = tts.getDefaultVoice().getLocale();
|
||||||
|
if (isLanguageAvailable(locale)) {
|
||||||
|
tts.setLanguage(locale);
|
||||||
|
}
|
||||||
|
} catch (NullPointerException | IllegalArgumentException e) {
|
||||||
|
Log.e(tag, "getDefaultLocale: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle pending method calls (sent while TTS was initializing)
|
||||||
|
isTtsInitialized = true;
|
||||||
|
for (Runnable call : pendingMethodCalls) {
|
||||||
|
call.run();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.e(tag, "Failed to initialize TextToSpeech");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMethodCall(@NonNull final MethodCall call, @NonNull final Result result) {
|
||||||
|
// If TTS is still loading
|
||||||
|
if (!isTtsInitialized) {
|
||||||
|
// Suspend method call until the TTS engine is ready
|
||||||
|
final Runnable suspendedCall =
|
||||||
|
new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
onMethodCall(call, result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
pendingMethodCalls.add(suspendedCall);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (call.method) {
|
||||||
|
case "speak":
|
||||||
|
{
|
||||||
|
String text = call.arguments.toString();
|
||||||
|
if (this.speaking) {
|
||||||
|
result.success(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
speak(text);
|
||||||
|
if (this.awaitSpeakCompletion) {
|
||||||
|
this.speaking = true;
|
||||||
|
this.speakResult = result;
|
||||||
|
} else {
|
||||||
|
result.success(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "awaitSpeakCompletion":
|
||||||
|
{
|
||||||
|
this.awaitSpeakCompletion = Boolean.parseBoolean(call.arguments.toString());
|
||||||
|
result.success(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "synthesizeToFile":
|
||||||
|
{
|
||||||
|
String text = call.argument("text");
|
||||||
|
String fileName = call.argument("fileName");
|
||||||
|
synthesizeToFile(text, fileName);
|
||||||
|
result.success(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "stop":
|
||||||
|
stop();
|
||||||
|
result.success(1);
|
||||||
|
break;
|
||||||
|
case "setSpeechRate":
|
||||||
|
String rate = call.arguments.toString();
|
||||||
|
setSpeechRate(Float.parseFloat(rate));
|
||||||
|
result.success(1);
|
||||||
|
break;
|
||||||
|
case "setVolume":
|
||||||
|
String volume = call.arguments.toString();
|
||||||
|
setVolume(Float.parseFloat(volume), result);
|
||||||
|
break;
|
||||||
|
case "setPitch":
|
||||||
|
String pitch = call.arguments.toString();
|
||||||
|
setPitch(Float.parseFloat(pitch), result);
|
||||||
|
break;
|
||||||
|
case "setLanguage":
|
||||||
|
{
|
||||||
|
String language = call.arguments.toString();
|
||||||
|
setLanguage(language, result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "getLanguages":
|
||||||
|
getLanguages(result);
|
||||||
|
break;
|
||||||
|
case "getVoices":
|
||||||
|
getVoices(result);
|
||||||
|
break;
|
||||||
|
case "getSpeechRateValidRange":
|
||||||
|
getSpeechRateValidRange(result);
|
||||||
|
break;
|
||||||
|
case "getEngines":
|
||||||
|
getEngines(result);
|
||||||
|
break;
|
||||||
|
case "setVoice":
|
||||||
|
HashMap<String, String> voice = call.arguments();
|
||||||
|
setVoice(voice, result);
|
||||||
|
break;
|
||||||
|
case "isLanguageAvailable":
|
||||||
|
{
|
||||||
|
String language = call.arguments().toString();
|
||||||
|
Locale locale = Locale.forLanguageTag(language);
|
||||||
|
result.success(isLanguageAvailable(locale));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "setSilence":
|
||||||
|
String silencems = call.arguments.toString();
|
||||||
|
this.silencems = Integer.parseInt(silencems);
|
||||||
|
break;
|
||||||
|
case "setSharedInstance":
|
||||||
|
result.success(1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result.notImplemented();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSpeechRate(float rate) {
|
||||||
|
tts.setSpeechRate(rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
Boolean isLanguageAvailable(Locale locale) {
|
||||||
|
return tts.isLanguageAvailable(locale) >= TextToSpeech.LANG_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLanguage(String language, Result result) {
|
||||||
|
Locale locale = Locale.forLanguageTag(language);
|
||||||
|
if (isLanguageAvailable(locale)) {
|
||||||
|
tts.setLanguage(locale);
|
||||||
|
result.success(1);
|
||||||
|
} else {
|
||||||
|
result.success(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setVoice(HashMap<String, String> voice, Result result) {
|
||||||
|
for (Voice ttsVoice : tts.getVoices()) {
|
||||||
|
if (ttsVoice.getName().equals(voice.get("name")) && ttsVoice.getLocale().toLanguageTag().equals(voice.get("locale"))) {
|
||||||
|
tts.setVoice(ttsVoice);
|
||||||
|
result.success(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.d(tag, "Voice name not found: " + voice);
|
||||||
|
result.success(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setVolume(float volume, Result result) {
|
||||||
|
if (volume >= 0.0F && volume <= 1.0F) {
|
||||||
|
bundle.putFloat(TextToSpeech.Engine.KEY_PARAM_VOLUME, volume);
|
||||||
|
result.success(1);
|
||||||
|
} else {
|
||||||
|
Log.d(tag, "Invalid volume " + volume + " value - Range is from 0.0 to 1.0");
|
||||||
|
result.success(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPitch(float pitch, Result result) {
|
||||||
|
if (pitch >= 0.5F && pitch <= 2.0F) {
|
||||||
|
tts.setPitch(pitch);
|
||||||
|
result.success(1);
|
||||||
|
} else {
|
||||||
|
Log.d(tag, "Invalid pitch " + pitch + " value - Range is from 0.5 to 2.0");
|
||||||
|
result.success(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void getVoices(Result result) {
|
||||||
|
ArrayList<HashMap<String, String>> voices = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
for (Voice voice : tts.getVoices()) {
|
||||||
|
HashMap<String, String> voiceMap = new HashMap<>();
|
||||||
|
voiceMap.put("name", voice.getName());
|
||||||
|
voiceMap.put("locale", voice.getLocale().toLanguageTag());
|
||||||
|
voices.add(voiceMap);
|
||||||
|
}
|
||||||
|
result.success(voices);
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
Log.d(tag, "getVoices: " + e.getMessage());
|
||||||
|
result.success(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void getLanguages(Result result) {
|
||||||
|
ArrayList<String> locales = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
// While this method was introduced in API level 21, it seems that it
|
||||||
|
// has not been implemented in the speech service side until API Level 23.
|
||||||
|
for (Locale locale : tts.getAvailableLanguages()) {
|
||||||
|
locales.add(locale.toLanguageTag());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (Locale locale : Locale.getAvailableLocales()) {
|
||||||
|
if (locale.getVariant().isEmpty() && isLanguageAvailable(locale)) {
|
||||||
|
locales.add(locale.toLanguageTag());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (MissingResourceException | NullPointerException e) {
|
||||||
|
Log.d(tag, "getLanguages: " + e.getMessage());
|
||||||
|
}
|
||||||
|
result.success(locales);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getEngines(Result result) {
|
||||||
|
ArrayList<String> engines = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
for (TextToSpeech.EngineInfo engineInfo : tts.getEngines()) {
|
||||||
|
engines.add(engineInfo.name);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.d(tag, "getEngines: " + e.getMessage());
|
||||||
|
}
|
||||||
|
result.success(engines);
|
||||||
|
}
|
||||||
|
|
||||||
|
void getSpeechRateValidRange(Result result) {
|
||||||
|
// Valid values available in the android documentation.
|
||||||
|
// https://developer.android.com/reference/android/speech/tts/TextToSpeech#setSpeechRate(float)
|
||||||
|
final HashMap<String, String> data = new HashMap<String, String>();
|
||||||
|
data.put("min", "0");
|
||||||
|
data.put("normal", "1");
|
||||||
|
data.put("max", "3");
|
||||||
|
data.put("platform", "android");
|
||||||
|
result.success(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void speak(String text) {
|
||||||
|
String uuid = UUID.randomUUID().toString();
|
||||||
|
utterances.put(uuid, text);
|
||||||
|
if (silencems > 0) {
|
||||||
|
tts.playSilentUtterance(silencems, TextToSpeech.QUEUE_FLUSH, SILENCE_PREFIX + uuid);
|
||||||
|
tts.speak(text, TextToSpeech.QUEUE_ADD, bundle, uuid);
|
||||||
|
} else {
|
||||||
|
tts.speak(text, TextToSpeech.QUEUE_FLUSH, bundle, uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stop() {
|
||||||
|
tts.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void synthesizeToFile(String text, String fileName) {
|
||||||
|
File file = new File(context.getExternalFilesDir(null), fileName);
|
||||||
|
String uuid = UUID.randomUUID().toString();
|
||||||
|
bundle.putString(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, SYNTHESIZE_TO_FILE_PREFIX + uuid);
|
||||||
|
|
||||||
|
int result = tts.synthesizeToFile(text, bundle, file, SYNTHESIZE_TO_FILE_PREFIX + uuid);
|
||||||
|
if (result == TextToSpeech.SUCCESS) {
|
||||||
|
Log.d(tag, "Successfully created file : " + file.getPath());
|
||||||
|
} else {
|
||||||
|
Log.d(tag, "Failed creating file : " + file.getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void invokeMethod(final String method, final Object arguments) {
|
||||||
|
handler.post(
|
||||||
|
new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (methodChannel != null) methodChannel.invokeMethod(method, arguments);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
.DS_Store
|
||||||
|
.dart_tool/
|
||||||
|
|
||||||
|
.packages
|
||||||
|
.pub/
|
||||||
|
|
||||||
|
build/
|
||||||
|
|
||||||
|
.flutter-plugins
|
||||||
|
.flutter-plugins-dependencies
|
||||||
|
lib/generated_plugin_registrant.dart
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
# This file tracks properties of this Flutter project.
|
||||||
|
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||||
|
#
|
||||||
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
|
version:
|
||||||
|
revision: b397406561f5e7a9c94e28f58d9e49fca0dd58b7
|
||||||
|
channel: beta
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
# example
|
||||||
|
|
||||||
|
A new Flutter project.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
This project is a starting point for a Flutter application.
|
||||||
|
|
||||||
|
A few resources to get you started if this is your first Flutter project:
|
||||||
|
|
||||||
|
- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
|
||||||
|
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
|
||||||
|
|
||||||
|
For help getting started with Flutter, view our
|
||||||
|
[online documentation](https://flutter.dev/docs), which offers tutorials,
|
||||||
|
samples, guidance on mobile development, and a full API reference.
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
*.iml
|
||||||
|
*.class
|
||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/workspace.xml
|
||||||
|
/.idea/libraries
|
||||||
|
.DS_Store
|
||||||
|
/build
|
||||||
|
/captures
|
||||||
|
GeneratedPluginRegistrant.java
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
#Sat Apr 14 11:55:40 PDT 2018
|
||||||
|
connection.project.dir=
|
||||||