Skip to content

Commit 0df570b

Browse files
committed
feat: add private cloud sync audio management
1 parent 88d2ede commit 0df570b

42 files changed

Lines changed: 2534 additions & 11 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/lib/backend/http/api/audio.dart

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,69 @@ Future<List<AudioFileUrlInfo>> getConversationAudioSignedUrls(String conversatio
8282
return [];
8383
}
8484
}
85+
86+
class CloudAudioConversation {
87+
final String id;
88+
final String title;
89+
final DateTime? createdAt;
90+
final int audioFileCount;
91+
final double totalDuration;
92+
93+
CloudAudioConversation({
94+
required this.id,
95+
required this.title,
96+
this.createdAt,
97+
required this.audioFileCount,
98+
required this.totalDuration,
99+
});
100+
101+
factory CloudAudioConversation.fromJson(Map<String, dynamic> json) {
102+
return CloudAudioConversation(
103+
id: json['id'] ?? '',
104+
title: json['title'] ?? 'Untitled',
105+
createdAt: json['created_at'] != null ? DateTime.parse(json['created_at']).toLocal() : null,
106+
audioFileCount: json['audio_file_count'] ?? 0,
107+
totalDuration: (json['total_duration'] ?? 0).toDouble(),
108+
);
109+
}
110+
}
111+
112+
Future<List<CloudAudioConversation>> getCloudAudioConversations() async {
113+
try {
114+
final headers = await buildHeaders(requireAuthCheck: true);
115+
final response = await makeApiCall(
116+
url: '${Env.apiBaseUrl}v1/sync/audio/conversations',
117+
headers: headers,
118+
method: 'GET',
119+
body: '',
120+
);
121+
122+
if (response == null || response.statusCode != 200) {
123+
return [];
124+
}
125+
126+
final decoded = jsonDecode(response.body) as Map<String, dynamic>;
127+
final conversations = decoded['conversations'] as List<dynamic>? ?? [];
128+
return conversations.map((c) => CloudAudioConversation.fromJson(c as Map<String, dynamic>)).toList();
129+
} catch (e) {
130+
Logger.debug('Error getting cloud audio conversations: $e');
131+
return [];
132+
}
133+
}
134+
135+
Future<bool> deleteAllCloudAudio() async {
136+
try {
137+
final headers = await buildHeaders(requireAuthCheck: true);
138+
final response = await makeApiCall(
139+
url: '${Env.apiBaseUrl}v1/sync/audio',
140+
headers: headers,
141+
method: 'DELETE',
142+
body: '',
143+
);
144+
145+
return response?.statusCode == 200;
146+
} catch (e) {
147+
Logger.debug('Error deleting all cloud audio: $e');
148+
return false;
149+
}
150+
}

app/lib/l10n/app_en.arb

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10499,5 +10499,66 @@
1049910499
"microphone": "Microphone",
1050010500
"@microphone": {
1050110501
"description": "Label for microphone permission"
10502+
},
10503+
"cloudAudioFiles": "Cloud Audio Files",
10504+
"@cloudAudioFiles": {
10505+
"description": "Title for cloud audio files section"
10506+
},
10507+
"noCloudAudioFiles": "No cloud audio files yet",
10508+
"@noCloudAudioFiles": {
10509+
"description": "Empty state for cloud audio files"
10510+
},
10511+
"noCloudAudioDescription": "Audio files will appear here once you record conversations with cloud sync enabled.",
10512+
"@noCloudAudioDescription": {
10513+
"description": "Description for empty cloud audio state"
10514+
},
10515+
"deleteAllAudio": "Delete All Audio",
10516+
"@deleteAllAudio": {
10517+
"description": "Button to delete all cloud audio"
10518+
},
10519+
"deleteAllAudioTitle": "Delete All Cloud Audio?",
10520+
"@deleteAllAudioTitle": {
10521+
"description": "Title for delete all audio dialog"
10522+
},
10523+
"deleteAllAudioMessage": "This will permanently delete all your cloud-synced audio files. This action cannot be undone.\n\nNote: The Data Training Program requires cloud-synced audio. Deleting these files will remove your contribution to the program.",
10524+
"@deleteAllAudioMessage": {
10525+
"description": "Message for delete all audio dialog"
10526+
},
10527+
"deleteAll": "Delete All",
10528+
"@deleteAll": {
10529+
"description": "Button text for delete all confirmation"
10530+
},
10531+
"deletingAudio": "Deleting audio files...",
10532+
"@deletingAudio": {
10533+
"description": "Loading text while deleting audio"
10534+
},
10535+
"audioDeletedSuccessfully": "All cloud audio files deleted",
10536+
"@audioDeletedSuccessfully": {
10537+
"description": "Success message after deleting audio"
10538+
},
10539+
"failedToDeleteAudio": "Failed to delete audio files",
10540+
"@failedToDeleteAudio": {
10541+
"description": "Error message when audio deletion fails"
10542+
},
10543+
"nAudioFiles": "{count} audio {count, plural, =1{file} other{files}}",
10544+
"@nAudioFiles": {
10545+
"description": "Number of audio files",
10546+
"placeholders": {
10547+
"count": {
10548+
"type": "int"
10549+
}
10550+
}
10551+
},
10552+
"preparingCloudAudioTryAgain": "Preparing audio. Please try again in a moment.",
10553+
"@preparingCloudAudioTryAgain": {
10554+
"description": "Shown when cloud audio is being prepared and the user should retry shortly"
10555+
},
10556+
"failedToPlayCloudAudio": "Failed to play audio",
10557+
"@failedToPlayCloudAudio": {
10558+
"description": "Error message when cloud audio playback fails"
10559+
},
10560+
"failedToShareCloudAudio": "Failed to share audio",
10561+
"@failedToShareCloudAudio": {
10562+
"description": "Error message when cloud audio sharing fails"
1050210563
}
1050310564
}

app/lib/l10n/app_localizations.dart

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15945,7 +15945,7 @@ abstract class AppLocalizations {
1594515945
/// **'Delete All Recordings'**
1594615946
String get deleteAllFiles;
1594715947

15948-
/// Menu option to delete all recordings
15948+
/// Button text for delete all confirmation
1594915949
///
1595015950
/// In en, this message translates to:
1595115951
/// **'Delete All'**
@@ -16328,6 +16328,84 @@ abstract class AppLocalizations {
1632816328
/// In en, this message translates to:
1632916329
/// **'Microphone'**
1633016330
String get microphone;
16331+
16332+
/// Title for cloud audio files section
16333+
///
16334+
/// In en, this message translates to:
16335+
/// **'Cloud Audio Files'**
16336+
String get cloudAudioFiles;
16337+
16338+
/// Empty state for cloud audio files
16339+
///
16340+
/// In en, this message translates to:
16341+
/// **'No cloud audio files yet'**
16342+
String get noCloudAudioFiles;
16343+
16344+
/// Description for empty cloud audio state
16345+
///
16346+
/// In en, this message translates to:
16347+
/// **'Audio files will appear here once you record conversations with cloud sync enabled.'**
16348+
String get noCloudAudioDescription;
16349+
16350+
/// Button to delete all cloud audio
16351+
///
16352+
/// In en, this message translates to:
16353+
/// **'Delete All Audio'**
16354+
String get deleteAllAudio;
16355+
16356+
/// Title for delete all audio dialog
16357+
///
16358+
/// In en, this message translates to:
16359+
/// **'Delete All Cloud Audio?'**
16360+
String get deleteAllAudioTitle;
16361+
16362+
/// Message for delete all audio dialog
16363+
///
16364+
/// In en, this message translates to:
16365+
/// **'This will permanently delete all your cloud-synced audio files. This action cannot be undone.\n\nNote: The Data Training Program requires cloud-synced audio. Deleting these files will remove your contribution to the program.'**
16366+
String get deleteAllAudioMessage;
16367+
16368+
/// Loading text while deleting audio
16369+
///
16370+
/// In en, this message translates to:
16371+
/// **'Deleting audio files...'**
16372+
String get deletingAudio;
16373+
16374+
/// Success message after deleting audio
16375+
///
16376+
/// In en, this message translates to:
16377+
/// **'All cloud audio files deleted'**
16378+
String get audioDeletedSuccessfully;
16379+
16380+
/// Error message when audio deletion fails
16381+
///
16382+
/// In en, this message translates to:
16383+
/// **'Failed to delete audio files'**
16384+
String get failedToDeleteAudio;
16385+
16386+
/// Number of audio files
16387+
///
16388+
/// In en, this message translates to:
16389+
/// **'{count} audio {count, plural, =1{file} other{files}}'**
16390+
String nAudioFiles(int count);
16391+
16392+
/// Shown when cloud audio is being prepared and the user should retry shortly
16393+
///
16394+
/// In en, this message translates to:
16395+
/// **'Preparing audio. Please try again in a moment.'**
16396+
String get preparingCloudAudioTryAgain;
16397+
16398+
/// Error message when cloud audio playback fails
16399+
///
16400+
/// In en, this message translates to:
16401+
/// **'Failed to play audio'**
16402+
String get failedToPlayCloudAudio;
16403+
16404+
/// Error message when cloud audio sharing fails
16405+
///
16406+
/// In en, this message translates to:
16407+
/// **'Failed to share audio'**
16408+
String get failedToShareCloudAudio;
1633116409
}
1633216410

1633316411
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {

app/lib/l10n/app_localizations_ar.dart

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8694,4 +8694,53 @@ class AppLocalizationsAr extends AppLocalizations {
86948694

86958695
@override
86968696
String get microphone => 'الميكروفون';
8697+
8698+
@override
8699+
String get cloudAudioFiles => 'Cloud Audio Files';
8700+
8701+
@override
8702+
String get noCloudAudioFiles => 'No cloud audio files yet';
8703+
8704+
@override
8705+
String get noCloudAudioDescription =>
8706+
'Audio files will appear here once you record conversations with cloud sync enabled.';
8707+
8708+
@override
8709+
String get deleteAllAudio => 'Delete All Audio';
8710+
8711+
@override
8712+
String get deleteAllAudioTitle => 'Delete All Cloud Audio?';
8713+
8714+
@override
8715+
String get deleteAllAudioMessage =>
8716+
'This will permanently delete all your cloud-synced audio files. This action cannot be undone.\n\nNote: The Data Training Program requires cloud-synced audio. Deleting these files will remove your contribution to the program.';
8717+
8718+
@override
8719+
String get deletingAudio => 'Deleting audio files...';
8720+
8721+
@override
8722+
String get audioDeletedSuccessfully => 'All cloud audio files deleted';
8723+
8724+
@override
8725+
String get failedToDeleteAudio => 'Failed to delete audio files';
8726+
8727+
@override
8728+
String nAudioFiles(int count) {
8729+
String _temp0 = intl.Intl.pluralLogic(
8730+
count,
8731+
locale: localeName,
8732+
other: 'files',
8733+
one: 'file',
8734+
);
8735+
return '$count audio $_temp0';
8736+
}
8737+
8738+
@override
8739+
String get preparingCloudAudioTryAgain => 'Preparing audio. Please try again in a moment.';
8740+
8741+
@override
8742+
String get failedToPlayCloudAudio => 'Failed to play audio';
8743+
8744+
@override
8745+
String get failedToShareCloudAudio => 'Failed to share audio';
86978746
}

app/lib/l10n/app_localizations_bg.dart

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8790,4 +8790,53 @@ class AppLocalizationsBg extends AppLocalizations {
87908790

87918791
@override
87928792
String get microphone => 'Микрофон';
8793+
8794+
@override
8795+
String get cloudAudioFiles => 'Cloud Audio Files';
8796+
8797+
@override
8798+
String get noCloudAudioFiles => 'No cloud audio files yet';
8799+
8800+
@override
8801+
String get noCloudAudioDescription =>
8802+
'Audio files will appear here once you record conversations with cloud sync enabled.';
8803+
8804+
@override
8805+
String get deleteAllAudio => 'Delete All Audio';
8806+
8807+
@override
8808+
String get deleteAllAudioTitle => 'Delete All Cloud Audio?';
8809+
8810+
@override
8811+
String get deleteAllAudioMessage =>
8812+
'This will permanently delete all your cloud-synced audio files. This action cannot be undone.\n\nNote: The Data Training Program requires cloud-synced audio. Deleting these files will remove your contribution to the program.';
8813+
8814+
@override
8815+
String get deletingAudio => 'Deleting audio files...';
8816+
8817+
@override
8818+
String get audioDeletedSuccessfully => 'All cloud audio files deleted';
8819+
8820+
@override
8821+
String get failedToDeleteAudio => 'Failed to delete audio files';
8822+
8823+
@override
8824+
String nAudioFiles(int count) {
8825+
String _temp0 = intl.Intl.pluralLogic(
8826+
count,
8827+
locale: localeName,
8828+
other: 'files',
8829+
one: 'file',
8830+
);
8831+
return '$count audio $_temp0';
8832+
}
8833+
8834+
@override
8835+
String get preparingCloudAudioTryAgain => 'Preparing audio. Please try again in a moment.';
8836+
8837+
@override
8838+
String get failedToPlayCloudAudio => 'Failed to play audio';
8839+
8840+
@override
8841+
String get failedToShareCloudAudio => 'Failed to share audio';
87938842
}

app/lib/l10n/app_localizations_ca.dart

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8806,4 +8806,53 @@ class AppLocalizationsCa extends AppLocalizations {
88068806

88078807
@override
88088808
String get microphone => 'Micròfon';
8809+
8810+
@override
8811+
String get cloudAudioFiles => 'Cloud Audio Files';
8812+
8813+
@override
8814+
String get noCloudAudioFiles => 'No cloud audio files yet';
8815+
8816+
@override
8817+
String get noCloudAudioDescription =>
8818+
'Audio files will appear here once you record conversations with cloud sync enabled.';
8819+
8820+
@override
8821+
String get deleteAllAudio => 'Delete All Audio';
8822+
8823+
@override
8824+
String get deleteAllAudioTitle => 'Delete All Cloud Audio?';
8825+
8826+
@override
8827+
String get deleteAllAudioMessage =>
8828+
'This will permanently delete all your cloud-synced audio files. This action cannot be undone.\n\nNote: The Data Training Program requires cloud-synced audio. Deleting these files will remove your contribution to the program.';
8829+
8830+
@override
8831+
String get deletingAudio => 'Deleting audio files...';
8832+
8833+
@override
8834+
String get audioDeletedSuccessfully => 'All cloud audio files deleted';
8835+
8836+
@override
8837+
String get failedToDeleteAudio => 'Failed to delete audio files';
8838+
8839+
@override
8840+
String nAudioFiles(int count) {
8841+
String _temp0 = intl.Intl.pluralLogic(
8842+
count,
8843+
locale: localeName,
8844+
other: 'files',
8845+
one: 'file',
8846+
);
8847+
return '$count audio $_temp0';
8848+
}
8849+
8850+
@override
8851+
String get preparingCloudAudioTryAgain => 'Preparing audio. Please try again in a moment.';
8852+
8853+
@override
8854+
String get failedToPlayCloudAudio => 'Failed to play audio';
8855+
8856+
@override
8857+
String get failedToShareCloudAudio => 'Failed to share audio';
88098858
}

0 commit comments

Comments
 (0)