Browse Source

上传代码

weicu
liwei1dao 1 year ago
parent
commit
9633e85cf0
  1. 8
      android/app/src/main/kotlin/com/yunqiinnovation/deepsound/MainActivity.kt
  2. 4
      android/app/src/main/kotlin/com/yunqiinnovation/deepsound/VoiceInteractionHandler.kt
  3. 6
      android/app/src/main/kotlin/com/yunqiinnovation/deepsound/VoiceInteractionService.kt
  4. 133
      lib/data/services/volcano_translation_service.dart
  5. 311
      local_plugins/spotify_sdk/android/src/main/kotlin/de/minimalme/spotify_sdk/SpotifySdkService.kt

8
android/app/src/main/kotlin/com/yunqiinnovation/deepsound/MainActivity.kt

@ -173,7 +173,9 @@ class MainActivity: FlutterActivity() {
var volcanoSpeechAppId: String = ""
var volcanoSpeechAppToken: String = ""
var mcpServer: String = ""
var spotifyClientId: String = ""
var spotifyRedirectUrl: String = ""
// 安全存储相关常量
private const val SECURE_PREFS_FILENAME = "deep_voice_secure_prefs"
private const val KEY_AZURE_SPEECH_KEY = "azure_speech_key"
@ -186,6 +188,8 @@ class MainActivity: FlutterActivity() {
private const val KEY_VOLCANO_SPEECH_APP_ID = "volcano_speech_app_id"
private const val KEY_VOLCANO_SPEECH_APP_TOKEN = "volcano_speech_app_token"
private const val KEY_MCP_SERVER = "mcp_server"
private const val KEY_SPOTIFY_CLIENT_ID = "spotify_client_id"
private const val KEY_SPOTIFY_REDIRECT_URL = "spotify_redirect_url"
// 会话管理
private const val KEY_SESSION_ID = "session_id"
@ -227,6 +231,8 @@ class MainActivity: FlutterActivity() {
.putString(KEY_VOLCANO_SPEECH_APP_ID, volcanoSpeechAppId)
.putString(KEY_VOLCANO_SPEECH_APP_TOKEN, volcanoSpeechAppToken)
.putString(KEY_MCP_SERVER, mcpServer)
.putString(KEY_SPOTIFY_CLIENT_ID, spotifyClientId)
.putString(KEY_SPOTIFY_REDIRECT_URL, spotifyRedirectUrl)
.apply()
FileLogger.d("MainActivity", "密钥已安全保存到加密存储中")

4
android/app/src/main/kotlin/com/yunqiinnovation/deepsound/VoiceInteractionHandler.kt

@ -26,7 +26,9 @@ class VoiceInteractionHandler(
private val openaiModel: String = "",
private val volcanoSpeechAppId: String,
private val volcanoSpeechAppToken: String,
private val mcpServer: String
private val mcpServer: String,
private val spotifyclientid: String,
private val spotifyRedirectUrl: String
) {
private val TAG = "VoiceInteractionHandler"

6
android/app/src/main/kotlin/com/yunqiinnovation/deepsound/VoiceInteractionService.kt

@ -148,6 +148,8 @@ class VoiceInteractionService : Service() {
var volcanoSpeechAppId = MainActivity.volcanoSpeechAppId ?: ""
var volcanoSpeechAppToken = MainActivity.volcanoSpeechAppToken ?: ""
var mcpServer = MainActivity.mcpServer ?: ""
var spotifyclientid = MainActivity.spotifyClientId ?: ""
var spotifyRedirectUrl = MainActivity.spotifyRedirectUrl ?: ""
// 如果静态变量中没有配置,尝试从加密存储中加载
if (subscriptionKey.isEmpty() || serviceRegion.isEmpty() || openaiKey.isEmpty()) {
@ -166,6 +168,8 @@ class VoiceInteractionService : Service() {
volcanoSpeechAppId = MainActivity.volcanoSpeechAppId ?: ""
volcanoSpeechAppToken = MainActivity.volcanoSpeechAppToken ?: ""
mcpServer = MainActivity.mcpServer ?: ""
spotifyclientid = MainActivity.spotifyClientId ?: ""
spotifyRedirectUrl = MainActivity.spotifyRedirectUrl ?: ""
FileLogger.d(TAG, "已从加密存储加载配置信息")
} else {
FileLogger.e(TAG, "无法从加密存储加载配置信息")
@ -177,7 +181,7 @@ class VoiceInteractionService : Service() {
subscriptionKey, serviceRegion,
openaiKey, openaiBaseUrl, openaiModel,
volcanoSpeechAppId, volcanoSpeechAppToken,
mcpServer)
mcpServer,spotifyclientid,spotifyRedirectUrl)
// 初始化回调
voiceInteractionHandler.setCallback(object : VoiceInteractionHandler.InteractionCallback {

133
lib/data/services/volcano_translation_service.dart

@ -1,5 +1,6 @@
import 'dart:convert';
import 'dart:math';
import 'package:get_storage/get_storage.dart';
import 'package:http/http.dart' as http;
import 'package:crypto/crypto.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
@ -10,7 +11,7 @@ import 'language_manager.dart';
class VolcanoTranslationService extends GetxService {
// API 配置
late String _baseUrl;
final String _endpoint = '/'; // 修改为根路径
final String _endpoint = '/'; // 修改为根路径
late final String _accessKey;
late final String _secretKey;
late final String _region;
@ -21,7 +22,7 @@ class VolcanoTranslationService extends GetxService {
// 语言管理器
final LanguageManager _languageManager = Get.find<LanguageManager>();
final GetStorage _storage = GetStorage();
// 构造函数
VolcanoTranslationService();
@ -32,9 +33,10 @@ class VolcanoTranslationService extends GetxService {
String? region,
}) async {
try {
_accessKey = accessKey ?? dotenv.env['VOLCANO_TRANSLATION_ACCESS_KEY'] ?? '';
_secretKey = secretKey ?? dotenv.env['VOLCANO_TRANSLATION_SECRET_KEY'] ?? '';
_region = region ?? dotenv.env['VOLCANO_TRANSLATION_REGION'] ?? 'cn-north-1';
final _env = _storage.read("ENV") as Map<String, String>;
_accessKey = accessKey ?? _env['VOLCANO_TRANSLATION_ACCESS_KEY'] ?? '';
_secretKey = secretKey ?? _env['VOLCANO_TRANSLATION_SECRET_KEY'] ?? '';
_region = region ?? _env['VOLCANO_TRANSLATION_REGION'] ?? 'cn-north-1';
_service = 'translate';
_baseUrl = 'https://translate.volcengineapi.com';
@ -50,14 +52,21 @@ class VolcanoTranslationService extends GetxService {
}
// 生成签名
Map<String, String> _generateSignature(String method, Map<String, dynamic> requestBody, Map<String, String> queryParams) {
Map<String, String> _generateSignature(String method,
Map<String, dynamic> requestBody, Map<String, String> queryParams) {
// 1. 准备时间相关参数
final now = DateTime.now().toUtc();
final date = now.toIso8601String().split('T')[0].replaceAll('-', '');
final timestamp = now.toIso8601String().replaceAll(':', '').replaceAll('-', '').split('.')[0] + 'Z';
final timestamp = now
.toIso8601String()
.replaceAll(':', '')
.replaceAll('-', '')
.split('.')[0] +
'Z';
// 2. 构建规范查询字符串 - 按照参数名ASCII排序
final sortedParams = Map.fromEntries(queryParams.entries.toList()..sort((a, b) => a.key.compareTo(b.key)));
final sortedParams = Map.fromEntries(
queryParams.entries.toList()..sort((a, b) => a.key.compareTo(b.key)));
final List<String> queryParts = [];
sortedParams.forEach((key, value) {
// 使用RFC 3986编码,确保特殊字符被正确处理
@ -66,48 +75,53 @@ class VolcanoTranslationService extends GetxService {
queryParts.add('$encodedKey=$encodedValue');
});
final canonicalQueryString = queryParts.join('&');
// 3. 创建规范请求
final contentType = 'application/json';
final payloadHash = sha256.convert(utf8.encode(json.encode(requestBody))).toString();
final payloadHash =
sha256.convert(utf8.encode(json.encode(requestBody))).toString();
final host = 'translate.volcengineapi.com';
// 确保头部按照字典序排序,且键名小写
// 注意:只包含host和x-date头部,与示例保持一致
final canonicalHeaders = 'host:$host\nx-date:$timestamp\n';
final signedHeaders = 'host;x-date';
// 构建规范请求,格式必须与示例完全一致
final canonicalRequest = '$method\n$_endpoint\n$canonicalQueryString\n$canonicalHeaders\n$signedHeaders\n$payloadHash';
final canonicalRequest =
'$method\n$_endpoint\n$canonicalQueryString\n$canonicalHeaders\n$signedHeaders\n$payloadHash';
// 4. 创建待签字符串
final algorithm = 'HMAC-SHA256';
final credentialScope = '$date/$_region/$_service/request';
final stringToSign = '$algorithm\n$timestamp\n$credentialScope\n${sha256.convert(utf8.encode(canonicalRequest)).toString()}';
final stringToSign =
'$algorithm\n$timestamp\n$credentialScope\n${sha256.convert(utf8.encode(canonicalRequest)).toString()}';
// 5. 计算签名 - 按照文档正确派生密钥
// 注意:这里是关键修复点,确保密钥派生过程完全符合文档
final kSecret = utf8.encode(_secretKey); // 直接使用原始密钥,不添加前缀
final kSecret = utf8.encode(_secretKey); // 直接使用原始密钥,不添加前缀
// kDate = HMAC(kSecret, Date)
var kDate = Hmac(sha256, kSecret).convert(utf8.encode(date)).bytes;
// kRegion = HMAC(kDate, Region)
var kRegion = Hmac(sha256, kDate).convert(utf8.encode(_region)).bytes;
// kService = HMAC(kRegion, Service)
var kService = Hmac(sha256, kRegion).convert(utf8.encode(_service)).bytes;
// kSigning = HMAC(kService, "request")
var kSigning = Hmac(sha256, kService).convert(utf8.encode('request')).bytes;
// 使用派生的签名密钥计算最终签名
final signature = Hmac(sha256, kSigning).convert(utf8.encode(stringToSign)).toString();
final signature =
Hmac(sha256, kSigning).convert(utf8.encode(stringToSign)).toString();
// 6. 添加签名到请求头 - 格式必须与示例完全一致
final authorization = '$algorithm Credential=$_accessKey/$credentialScope, SignedHeaders=$signedHeaders, Signature=$signature';
final authorization =
'$algorithm Credential=$_accessKey/$credentialScope, SignedHeaders=$signedHeaders, Signature=$signature';
// 只返回必要的头部,与示例保持一致
return {
'Content-Type': contentType,
@ -131,27 +145,29 @@ class VolcanoTranslationService extends GetxService {
// 获取源语言和目标语言的短代码
String sourceCode = '';
String targetCode = 'zh';
// 从 ASR 代码获取短代码
if (sourceLanguageCode.isNotEmpty) {
final sourceShortCode = _languageManager.getShortCodeByAsrCode(sourceLanguageCode);
final sourceShortCode =
_languageManager.getShortCodeByAsrCode(sourceLanguageCode);
if (sourceShortCode != null) {
sourceCode = sourceShortCode;
}
}
final targetShortCode = _languageManager.getShortCodeByAsrCode(targetLanguageCode);
final targetShortCode =
_languageManager.getShortCodeByAsrCode(targetLanguageCode);
if (targetShortCode != null) {
targetCode = targetShortCode;
}
// 构建请求体
final requestBody = {
'SourceLanguage': sourceCode,
'TargetLanguage': targetCode,
'TextList': [text],
};
// 添加必要的查询参数 - 确保包含所有必需参数
final queryParams = {
'Action': 'TranslateText',
@ -159,60 +175,61 @@ class VolcanoTranslationService extends GetxService {
'Region': _region,
'Service': _service,
};
// 生成包含查询参数的签名
final headers = _generateSignature('POST', requestBody, queryParams);
// 构建带有查询参数的URL
final queryString = Uri(queryParameters: queryParams).query;
final url = '$_baseUrl/?$queryString';
final response = await http.post(
Uri.parse(url),
headers: headers,
body: json.encode(requestBody),
);
if (response.statusCode == 200) {
final responseData = json.decode(response.body);
// 尝试从不同的响应结构中提取翻译结果
String? translation;
// 1. 标准响应结构
if (responseData['TranslationList'] != null &&
responseData['TranslationList'] is List &&
if (responseData['TranslationList'] != null &&
responseData['TranslationList'] is List &&
responseData['TranslationList'].isNotEmpty) {
final translationItem = responseData['TranslationList'][0];
if (translationItem is Map && translationItem.containsKey('Translation')) {
if (translationItem is Map &&
translationItem.containsKey('Translation')) {
translation = translationItem['Translation'];
}
}
// 2. 检查是否有错误响应
if (translation == null &&
responseData['ResponseMetadata'] != null &&
responseData['ResponseMetadata'] is Map &&
if (translation == null &&
responseData['ResponseMetadata'] != null &&
responseData['ResponseMetadata'] is Map &&
responseData['ResponseMetadata']['Error'] != null) {
return null;
}
// 3. 尝试其他可能的响应结构
if (translation == null) {
if (responseData.containsKey('Translation')) {
translation = responseData['Translation'];
} else if (responseData.containsKey('Result') &&
responseData['Result'] is Map &&
responseData['Result'].containsKey('Translation')) {
} else if (responseData.containsKey('Result') &&
responseData['Result'] is Map &&
responseData['Result'].containsKey('Translation')) {
translation = responseData['Result']['Translation'];
} else if (responseData.containsKey('Data') &&
responseData['Data'] is Map) {
} else if (responseData.containsKey('Data') &&
responseData['Data'] is Map) {
final data = responseData['Data'];
if (data.containsKey('Translation')) {
translation = data['Translation'];
} else if (data.containsKey('TranslationList') &&
data['TranslationList'] is List &&
data['TranslationList'].isNotEmpty) {
} else if (data.containsKey('TranslationList') &&
data['TranslationList'] is List &&
data['TranslationList'].isNotEmpty) {
final item = data['TranslationList'][0];
if (item is Map && item.containsKey('Translation')) {
translation = item['Translation'];
@ -220,14 +237,14 @@ class VolcanoTranslationService extends GetxService {
}
}
}
// 返回提取到的翻译结果
return translation;
}
return null;
} catch (e) {
return null;
}
}
}
}

311
local_plugins/spotify_sdk/android/src/main/kotlin/de/minimalme/spotify_sdk/SpotifySdkService.kt

@ -0,0 +1,311 @@
package de.minimalme.spotify_sdk
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.util.Log
import com.spotify.android.appremote.api.ConnectionParams
import com.spotify.android.appremote.api.Connector
import com.spotify.android.appremote.api.PlayerApi
import com.spotify.android.appremote.api.SpotifyAppRemote
import com.spotify.android.appremote.api.error.AuthenticationFailedException
import com.spotify.android.appremote.api.error.CouldNotFindSpotifyApp
import com.spotify.android.appremote.api.error.NotLoggedInException
import com.spotify.android.appremote.api.error.OfflineModeException
import com.spotify.android.appremote.api.error.SpotifyConnectionTerminatedException
import com.spotify.android.appremote.api.error.SpotifyDisconnectedException
import com.spotify.android.appremote.api.error.SpotifyRemoteServiceException
import com.spotify.android.appremote.api.error.UnsupportedFeatureVersionException
import com.spotify.android.appremote.api.error.UserNotAuthorizedException
import com.spotify.sdk.android.auth.AuthorizationClient
import com.spotify.sdk.android.auth.AuthorizationRequest
import com.spotify.sdk.android.auth.AuthorizationResponse
import de.minimalme.spotify_sdk.subscriptions.CapabilitiesChannel
import de.minimalme.spotify_sdk.subscriptions.ConnectionStatusChannel
import de.minimalme.spotify_sdk.subscriptions.PlayerContextChannel
import de.minimalme.spotify_sdk.subscriptions.PlayerStateChannel
import de.minimalme.spotify_sdk.subscriptions.UserStatusChannel
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.PluginRegistry
import kotlinx.event.SetEvent
import kotlinx.event.event
class SpotifySdkService(private val context: Context? = null) {
// application context
private var applicationContext : Context? = null
private var applicationActivity : Activity? = null
// method channel
private lateinit var methodChannel : MethodChannel
private val channelName = "spotify_sdk"
private val loggingTag = "spotify_sdk"
// event channels
private var playerContextChannel : EventChannel? = null
private var playerStateChannel : EventChannel? = null
private var capabilitiesChannel : EventChannel? = null
private var userStatusChannel : EventChannel? = null
private var connectionStatusChannel : EventChannel? = null
private val playerContextSubscription = "player_context_subscription"
private val playerStateSubscription = "player_state_subscription"
private val capabilitiesSubscription = "capabilities_subscription"
private val userStatusSubscription = "user_status_subscription"
private val connectionStatusSubscription = "connection_status_subscription"
//connecting
private val methodConnectToSpotify = "connectToSpotify"
private val methodGetAccessToken = "getAccessToken"
private val methodDisconnectFromSpotify = "disconnectFromSpotify"
// connectApi
private val methodSwitchToLocalDevice = "switchToLocalDevice"
//playerApi
private val methodGetCrossfadeState = "getCrossfadeState"
private val methodGetPlayerState = "getPlayerState"
private val methodPlay = "play"
private val methodPause = "pause"
private val methodQueueTrack = "queueTrack"
private val methodResume = "resume"
private val methodSeekToRelativePosition = "seekToRelativePosition"
private val methodSetPodcastPlaybackSpeed = "setPodcastPlaybackSpeed"
private val methodSkipNext = "skipNext"
private val methodSkipPrevious = "skipPrevious"
private val methodSkipToIndex = "skipToIndex"
private val methodSeekTo = "seekTo"
private val methodToggleRepeat = "toggleRepeat"
private val methodToggleShuffle = "toggleShuffle"
private val methodSetShuffle = "setShuffle"
private val methodSetRepeatMode = "setRepeatMode"
//userApi
private val methodAddToLibrary = "addToLibrary"
private val methodRemoveFromLibrary = "removeFromLibrary"
private val methodGetCapabilities = "getCapabilities"
private val methodGetLibraryState = "getLibraryState"
//imagesApi
private val methodGetImage = "getImage"
private val paramClientId = "clientId"
private val paramRedirectUrl = "redirectUrl"
private val paramScope = "scope"
private val paramSpotifyUri = "spotifyUri"
private val paramImageUri = "imageUri"
private val paramImageDimension = "imageDimension"
private val paramPositionedMilliseconds = "positionedMilliseconds"
private val paramRelativeMilliseconds = "relativeMilliseconds"
private val paramPodcastPlaybackSpeed = "podcastPlaybackSpeed"
private val paramTrackIndex = "trackIndex"
private val paramRepeatMode = "repeatMode"
private val paramShuffle = "shuffle"
private val errorConnecting = "errorConnecting"
private val errorDisconnecting = "errorDisconnecting"
private val errorConnection = "errorConnection"
private val errorAuthenticationToken = "authenticationTokenError"
private val requestCodeAuthentication = 1337
private var spotifyAppRemote: SpotifyAppRemote? = null
private var playerApi: PlayerApi? = null
//-- Method implementations
private fun connectToSpotify(clientId: String?, redirectUrl: String?, result: MethodChannel.Result) {
if (clientId.isNullOrBlank() || redirectUrl.isNullOrBlank()) {
result.error(errorConnecting, "client id or redirectUrl are not set or have invalid format", "")
} else {
val connectionParams = ConnectionParams.Builder(clientId)
.setRedirectUri(redirectUrl)
.showAuthView(true)
.build()
SpotifyAppRemote.disconnect(spotifyAppRemote)
var initiallyConnected = false
SpotifyAppRemote.connect(applicationContext, connectionParams,
object : Connector.ConnectionListener {
override fun onConnected(spotifyAppRemoteValue: SpotifyAppRemote) {
spotifyAppRemote = spotifyAppRemoteValue
playerApi = spotifyAppRemote?.playerApi
initiallyConnected = true
Log.i(loggingTag, "App Remote successfully connected")
result.success(true)
}
override fun onFailure(throwable: Throwable) {
val errorDetails = throwable.toString()
// determine the error
val errorMessage: String
val errorCode: String
var connected = false
when (throwable) {
is SpotifyDisconnectedException, is SpotifyConnectionTerminatedException -> {
// The Spotify app was/is disconnected by the Spotify app.
// This indicates typically that the Spotify app was closed by the user or for other reasons.
// You need to reconnect to continue using Spotify App Remote.
errorMessage =
"The Spotify app was/is disconnected by the Spotify app.Reconnect necessary"
errorCode = "SpotifyDisconnectedException"
}
is CouldNotFindSpotifyApp -> {
errorMessage = "The Spotify app is not installed on the device"
errorCode = "CouldNotFindSpotifyApp"
}
is AuthenticationFailedException -> {
errorMessage =
"Partner app failed to authenticate with Spotify. Check client credentials and make sure your app is registered correctly at developer.spotify.com"
errorCode = "AuthenticationFailedException"
}
is UserNotAuthorizedException -> {
errorMessage =
"Indicates the user did not authorize this client of App Remote to use Spotify on the users behalf."
errorCode = "UserNotAuthorizedException"
}
is UnsupportedFeatureVersionException -> {
errorMessage =
"Spotify app can't support requested features. User should update Spotify app."
errorCode = "UnsupportedFeatureVersionException"
connected = true
}
is OfflineModeException -> {
errorMessage =
"Spotify user has set their Spotify app to be in offline mode"
errorCode = "OfflineModeException"
connected = true
}
is NotLoggedInException -> {
errorMessage = "User has logged out from Spotify."
errorCode = "NotLoggedInException"
}
is SpotifyRemoteServiceException -> {
errorMessage =
"Encapsulates possible SecurityException and IllegalStateException errors."
errorCode = "SpotifyRemoteServiceException"
}
else -> {
errorMessage = "Something went wrong connecting spotify remote"
errorCode = errorConnection
}
}
Log.e(loggingTag, errorMessage)
// notify plugin
if (initiallyConnected) {
// emit connection error event
// connStatusEventChannel(
// ConnectionStatusChannel.ConnectionEvent(
// connected,
// errorMessage,
// errorCode,
// errorDetails
// )
// )
} else {
// throw exception as the connect method
result.error(errorCode, errorMessage, errorDetails)
}
}
})
}
}
private fun getAccessToken(clientId: String?, redirectUrl: String?, scope: String?, result: MethodChannel.Result) {
if (applicationActivity == null) {
throw IllegalStateException("getAccessToken needs a foreground activity")
}
if (clientId.isNullOrBlank() || redirectUrl.isNullOrBlank()) {
result.error(errorConnecting, "client id or redirectUrl are not set or have invalid format", "")
} else {
//Convert String? scope to Array. Delimiter set as comma ","
val scopeArray = scope?.split(",")?.toTypedArray()
// methodConnectToSpotify.checkAndSetPendingOperation(result)
val builder = AuthorizationRequest.Builder(
clientId,
AuthorizationResponse.Type.TOKEN,
redirectUrl
)
builder.setScopes(scopeArray)
val request = builder.build()
AuthorizationClient.openLoginActivity(
applicationActivity,
requestCodeAuthentication,
request
)
}
}
private fun disconnectFromSpotify(result: MethodChannel.Result) {
if (spotifyAppRemote != null && spotifyAppRemote!!.isConnected) {
SpotifyAppRemote.disconnect(spotifyAppRemote)
// emit connection terminated event
// connStatusEventChannel(
// ConnectionStatusChannel.ConnectionEvent(
// false,
// "Successfully disconnected from Spotify.",
// null,
// null
// )
// )
// method success
result.success(true)
} else if (!spotifyAppRemote!!.isConnected) {
result.error(errorDisconnecting, "could not disconnect spotify remote", "you are not connected, no need to disconnect")
} else {
result.error(errorDisconnecting, "could not disconnect spotify remote", "spotifyAppRemote is not set")
}
}
private fun play(spotifyUri: String?){
// if (playerApi != null && !spotifyUri.isNullOrBlank()) {
// playerApi.play(spotifyUri)
// .setResultCallback { result.success(true) }
// .setErrorCallback { throwable -> result.error(errorPlay, "error when playing uri: $spotifyUri", throwable.toString()) }
// } else if (spotifyUri.isNullOrBlank()) {
// result.error(errorPlay, "spotifyUri has invalid format or is not set", "")
// } else {
// spotifyRemoteAppNotSetError()
// }
if (playerApi != null && !spotifyUri.isNullOrBlank()) {
playerApi!!.play(spotifyUri)
} else if (spotifyUri.isNullOrBlank()) {
} else {
}
}
private fun pause(){
// if (playerApi != null) {
// playerApi.pause()
// .setResultCallback { result.success(true) }
// .setErrorCallback { throwable -> result.error(errorPause, "error when pausing", throwable.toString()) }
// } else {
// spotifyRemoteAppNotSetError()
// }
if (playerApi != null) {
playerApi!!.pause()
.setResultCallback {}
.setErrorCallback { }
} else {
}
}
}
Loading…
Cancel
Save