[gnome-sound-recorder/bilelmoussaoui/refresh] Start refreshing the HIG of Sound Recorder
- From: Bilal Elmoussaoui <bilelmoussaoui src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-sound-recorder/bilelmoussaoui/refresh] Start refreshing the HIG of Sound Recorder
- Date: Sun, 16 Jun 2019 14:52:52 +0000 (UTC)
commit 1818ca8edeae10ef2cdab69ced0aa7f6f1a97394
Author: Bilal Elmoussaoui <bil elmoussaoui gmail com>
Date: Sun Jun 16 16:52:35 2019 +0200
Start refreshing the HIG of Sound Recorder
data/application.css | 7 +
data/org.gnome.SoundRecorder.data.gresource.xml | 3 +
data/ui/main_window.ui | 217 ++++++++++++++
data/ui/recording_row.ui | 149 ++++++++++
data/ui/recording_waveform_row.ui | 50 ++++
org.gnome.SoundRecorder.json | 16 ++
src/application.js | 4 +-
src/audioProfile.js | 12 +-
src/fileUtil.js | 110 -------
src/listview.js | 352 -----------------------
src/main.js | 6 +-
src/mainWindow.js | 219 +++++++-------
src/org.gnome.SoundRecorder.src.gresource.xml.in | 9 +-
src/{play.js => player.js} | 55 +++-
src/{record.js => recorder.js} | 107 +++----
src/recording.js | 199 +++++++++++++
src/recordingsManager.js | 251 ++++++++++++++++
src/util.js | 40 ---
src/utils.js | 79 +++++
src/waveform.js | 52 ++--
20 files changed, 1232 insertions(+), 705 deletions(-)
---
diff --git a/data/application.css b/data/application.css
index 7aeab22..92f2cc7 100644
--- a/data/application.css
+++ b/data/application.css
@@ -1,4 +1,11 @@
+.record-button label{
+ color: @theme_bg_color;
+}
+
+.new-recording-widget{
+ background-color: white;
+}
.emptyGrid {
background-color: @theme_bg_color;
}
diff --git a/data/org.gnome.SoundRecorder.data.gresource.xml b/data/org.gnome.SoundRecorder.data.gresource.xml
index c0306b2..be02925 100644
--- a/data/org.gnome.SoundRecorder.data.gresource.xml
+++ b/data/org.gnome.SoundRecorder.data.gresource.xml
@@ -2,6 +2,9 @@
<gresources>
<gresource prefix="/org/gnome/SoundRecorder">
<file>application.css</file>
+ <file compressed="true" preprocess="xml-stripblanks" alias="main_window.ui">ui/main_window.ui</file>
+ <file compressed="true" preprocess="xml-stripblanks" alias="recording_row.ui">ui/recording_row.ui</file>
+ <file compressed="true" preprocess="xml-stripblanks"
alias="recording_waveform_row.ui">ui/recording_waveform_row.ui</file>
</gresource>
</gresources>
diff --git a/data/ui/main_window.ui b/data/ui/main_window.ui
new file mode 100644
index 0000000..6c9c651
--- /dev/null
+++ b/data/ui/main_window.ui
@@ -0,0 +1,217 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface>
+ <requires lib="gtk+" version="3.20"/>
+ <requires lib="libhandy" version="0.0"/>
+ <template class="Gjs_MainWindow" parent="GtkApplicationWindow">
+ <property name="width_request">480</property>
+ <property name="height_request">640</property>
+ <property name="can_focus">False</property>
+ <property name="default_width">480</property>
+ <property name="default_height">780</property>
+ <property name="icon_name">@APP_ID@</property>
+ <child type="titlebar">
+ <object class="GtkHeaderBar">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes">SoundRecorder</property>
+ <property name="show_close_button">True</property>
+ <child>
+ <object class="GtkButton" id="record_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">media-record-symbolic</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="record_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Record</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <style>
+ <class name="suggested-action"/>
+ <class name="record-button"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="menu_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_popover">False</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">open-menu-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStack" id="main_stack">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="icon_name">audio-input-microphone-symbolic</property>
+ <property name="icon_size">6</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="label" translatable="yes">Add Recordings</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="label" translatable="yes">Use the <b>Record</b> button to make
sound recordings</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="name">empty_view</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="HdyColumn">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="maximum_width">760</property>
+ <property name="linear_growth_width">760</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="vexpand">True</property>
+ <property name="border_width">18</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkRevealer" id="new_recording_revealer">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="hexpand">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkListBox" id="records_listbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="vexpand">True</property>
+ <property name="selection_mode">none</property>
+ <style>
+ <class name="frame"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">records_view</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/recording_row.ui b/data/ui/recording_row.ui
new file mode 100644
index 0000000..91dcf2f
--- /dev/null
+++ b/data/ui/recording_row.ui
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface>
+ <requires lib="gtk+" version="3.20"/>
+ <template class="Gjs_RecordingRow" parent="GtkListBoxRow">
+ <property name="width_request">100</property>
+ <property name="height_request">80</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkBox" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkStack" id="buttons_stack">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkButton" id="play_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Pause Recording</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <child>
+ <object class="GtkImage" id="play_image">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">media-playback-start-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">play</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="pause_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="icon_name">media-playback-pause-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">pause</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="clip_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="created_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkOverlay" id="overlay">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkLabel" id="time_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">end</property>
+ <property name="valign">start</property>
+ <property name="margin_left">6</property>
+ <property name="margin_right">6</property>
+ <property name="margin_top">6</property>
+ <property name="margin_bottom">6</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="index">-1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/recording_waveform_row.ui b/data/ui/recording_waveform_row.ui
new file mode 100644
index 0000000..3743fd1
--- /dev/null
+++ b/data/ui/recording_waveform_row.ui
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface>
+ <requires lib="gtk+" version="3.20"/>
+ <template class="Gjs_NewRecording" parent="GtkBox">
+ <property name="height_request">120</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="margin_bottom">18</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkOverlay" id="overlay">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkLabel" id="record_time_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">end</property>
+ <property name="valign">start</property>
+ <property name="margin_left">6</property>
+ <property name="margin_right">6</property>
+ <property name="margin_top">6</property>
+ <property name="margin_bottom">6</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="index">-1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <style>
+ <class name="new-recording-widget"/>
+ <class name="frame"/>
+ </style>
+ </template>
+</interface>
diff --git a/org.gnome.SoundRecorder.json b/org.gnome.SoundRecorder.json
index 4edae0b..b8abfbf 100644
--- a/org.gnome.SoundRecorder.json
+++ b/org.gnome.SoundRecorder.json
@@ -20,6 +20,22 @@
"--filesystem=~/Recordings:create"
],
"modules" : [
+ {
+ "name": "libhandy",
+ "buildsystem": "meson",
+ "config-opts": [
+ "-Dexamples=false",
+ "-Dglade_catalog=disabled",
+ "-Dtests=false",
+ "-Dvapi=false"
+ ],
+ "sources":[{
+ "type": "git",
+ "url": "https://source.puri.sm/Librem5/libhandy.git",
+ "tag": "v0.0.10",
+ "commit": "2d777677352d037b6f5cc24d9c1c8d9a74ac0ded"
+ }]
+ },
{
"name" : "gnome-sound-recorder",
"buildsystem": "meson",
diff --git a/src/application.js b/src/application.js
index 5149272..6062c6c 100644
--- a/src/application.js
+++ b/src/application.js
@@ -83,7 +83,9 @@ var Application = GObject.registerClass(class Application extends Gtk.Applicatio
}
vfunc_activate() {
- (this.window = new MainWindow.MainWindow({ application: this })).show();
+ this.window = new MainWindow.MainWindow();
+ this.window.set_application(this);
+ this.window.show();
if (pkg.name.endsWith('Devel'))
this.window.get_style_context().add_class("devel");
}
diff --git a/src/audioProfile.js b/src/audioProfile.js
index 090d976..fcee4eb 100644
--- a/src/audioProfile.js
+++ b/src/audioProfile.js
@@ -52,8 +52,13 @@ var audioCodecMap = {
VORBIS: "audio/x-vorbis"
};
-var AudioProfile = class AudioProfile {
- profile(profileName) {
+var AudioProfile = GObject.registerClass({
+
+
+ },
+ class AudioProfile extends GObject.Object {
+ _init(profileName) {
+ super._init();
if (profileName) {
this._profileName = profileName;
} else {
@@ -120,4 +125,5 @@ var AudioProfile = class AudioProfile {
this.audioSuffix = ("." + suffixName);
return this.audioSuffix;
}
-}
+ }
+);
diff --git a/src/main.js b/src/main.js
index 80e4f2a..854a38d 100644
--- a/src/main.js
+++ b/src/main.js
@@ -34,7 +34,11 @@ pkg.require({ 'Gdk': '3.0',
'Gtk': '3.0',
'Gst': '1.0',
'GstAudio': '1.0',
- 'GstPbutils': '1.0' });
+ 'GstPbutils': '1.0',
+ 'Handy': '0.0' });
+
+const Handy = imports.gi.Handy;
+Handy.init(null);
const Application = imports.application;
diff --git a/src/mainWindow.js b/src/mainWindow.js
index 37194c5..abc7409 100644
--- a/src/mainWindow.js
+++ b/src/mainWindow.js
@@ -1,4 +1,4 @@
-/* exported audioProfile displayTime list offsetController
+/* exported displayTime list offsetController
play recordPipeline view volumeValue wave ActiveArea
RecordPipelineStates _SEC_TIMEOUT MainWindow
EncoderComboBox ChannelsComboBox */
@@ -33,17 +33,18 @@ const Gtk = imports.gi.Gtk;
const Pango = imports.gi.Pango;
const Application = imports.application;
-const AudioProfile = imports.audioProfile;
-const FileUtil = imports.fileUtil;
+
const Info = imports.info;
-const Listview = imports.listview;
-const Play = imports.play;
+const RecordingsManager = imports.recordingsManager.RecordingsManager;
+const NewRecording = imports.recording.NewRecording;
+const RecordingRow = imports.recording.RecordingRow;
+
const Preferences = imports.preferences;
-const Record = imports.record;
+
const Waveform = imports.waveform;
let activeProfile = null;
-var audioProfile = null;
+
var displayTime = null;
let grid = null;
let groupGrid;
@@ -85,53 +86,131 @@ var RecordPipelineStates = {
STOPPED: 2
};
+var RecordingState = {
+ RECORDING: 0,
+ PAUSED: 1,
+ STOPPED: 2
+};
+
const _TIME_DIVISOR = 60;
var _SEC_TIMEOUT = 100;
-var MainWindow = GObject.registerClass(class MainWindow extends Gtk.ApplicationWindow {
- _init(params) {
- audioProfile = new AudioProfile.AudioProfile();
- offsetController = new FileUtil.OffsetController;
- displayTime = new FileUtil.DisplayTime;
- view = new MainView();
- play = new Play.Play();
+var MainWindow = GObject.registerClass({
+ Template: 'resource:///org/gnome/SoundRecorder/main_window.ui',
+ Properties: {
+ 'recording-state': GObject.ParamSpec.int(
+ 'recording-state',
+ 'RecordingState',
+ 'The recording state',
+ GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT,
+ 0, 2,
+ RecordingState.STOPPED
+ )
+ },
+ InternalChildren: [
+ 'menu_button',
+ 'main_stack',
+ 'record_button',
+ 'record_label',
+ 'records_listbox',
+ 'new_recording_revealer',
+ ]
+ },
+ class MainWindow extends Gtk.ApplicationWindow {
+ _init() {
+ super._init();
+ this._addAppMenu();
+ this._recordingsManager = new RecordingsManager();
+ this._initWidgets();
- super._init(Object.assign({
- title: GLib.get_application_name(),
- default_height: 480,
- default_width: 780,
- height_request: 480,
- width_request: 640,
- hexpand: true,
- vexpand: true,
- icon_name: pkg.name
- }, params));
+ this.show_all();
+ }
- header = new Gtk.HeaderBar({ hexpand: true,
- show_close_button: true });
- this.set_titlebar(header);
- header.get_style_context().add_class('titlebar');
+ _initWidgets() {
- recordButton = new RecordButton({ label: _("Record") });
- recordButton.get_style_context().add_class('suggested-action');
- header.pack_start(recordButton);
+ this._record_button.connect('clicked', () => this._onRecordClicked())
+ this._recordingsManager.connect('recording-added', (obj, recording) => {
+ this._onRecordingAdded(recording);
+ });
- this._addAppMenu();
+ this._records_listbox.set_header_func(this._updateHeaderFunc)
+ this._records_listbox.set_sort_func(this._sortRecordings);
- this.add(view);
- this.show_all();
+ this._newRecordingWidget = new NewRecording();
+ this._newRecordingWidget.connect("paused", () => this._record.pauseRecording());
+ this._newRecordingWidget.connect("resumed", () => this._record.resumeRecording());
+ this._recordingsManager._recorder.connect("timer-updated", (obj ,recordTime) => {
+ this._newRecordingWidget.updateRecordTime(recordTime);
+ });
+ this._new_recording_revealer.add(this._newRecordingWidget);
}
+
+
_addAppMenu() {
let menu = new Gio.Menu();
menu.append(_("Preferences"), 'app.preferences');
menu.append(_("About Sound Recorder"), 'app.about');
- appMenuButton = new Gtk.MenuButton({
- image: new Gtk.Image({ icon_name: 'open-menu-symbolic' }),
- menu_model: menu
- });
- header.pack_end(appMenuButton);
+ this._menu_button.set_menu_model(menu);
+ }
+
+ _onRecordClicked() {
+ if(this.recording_state === RecordingState.STOPPED) {
+ this._main_stack.set_visible_child_name('records_view');
+ this._main_stack.show_all();
+ this._record_button.get_style_context().remove_class('suggeted-action');
+ this._record_button.get_style_context().add_class('destructive-action');
+
+ this._record_label.set_text('Stop');
+
+ let wave = this._recordingsManager.startNewRecording();
+ this._newRecordingWidget.setWave(wave);
+ this._newRecordingWidget.show_all();
+
+ this._new_recording_revealer.set_reveal_child(true);
+
+ this.set_property('recording-state', RecordingState.RECORDING);
+ } else {
+
+ this._recordingsManager.saveRecording();
+ this._newRecordingWidget.reset();
+
+ this._record_button.get_style_context().add_class('suggested-action');
+ this._record_button.get_style_context().remove_class('destructive-action');
+ this._record_label.set_text('Record');
+ this.set_property('recording-state', RecordingState.STOPPED);
+
+ this._new_recording_revealer.set_reveal_child(false);
+ }
+ }
+
+ _onRecordingAdded(recording) {
+ this._main_stack.set_visible_child_name('records_view');
+ let recordingRow = new RecordingRow(recording);
+ this._records_listbox.add(recordingRow);
+ this._records_listbox.show_all();
+ }
+
+
+ _updateHeaderFunc(row, before) {
+ if (before) {
+ let separator = new Gtk.Separator();
+ separator.connect("realize", (seperator) => {
+ separator.set_size_request(before.get_allocated_width(), -1)
+ })
+ row.set_header(separator)
+ separator.show()
+ }
+ }
+ _sortRecordings(row1, row2) {
+ if (row2.recording) {
+ if(row1.recording.fileName < row2.recording.fileName) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
}
});
@@ -148,38 +227,11 @@ const MainView = GObject.registerClass(class MainView extends Gtk.Stack {
this.labelID = null;
}
- _addEmptyPage() {
- this.emptyGrid = new Gtk.Grid({ orientation: Gtk.Orientation.VERTICAL,
- hexpand: true,
- vexpand: true,
- halign: Gtk.Align.CENTER,
- valign: Gtk.Align.CENTER });
- this._scrolledWin.add(this.emptyGrid);
-
- let emptyPageImage = new Gtk.Image({ icon_name: 'audio-input-microphone-symbolic',
- icon_size: Gtk.IconSize.DIALOG });
- emptyPageImage.get_style_context().add_class('dim-label');
- this.emptyGrid.add(emptyPageImage);
- let emptyPageTitle = new Gtk.Label({ label: _("Add Recordings"),
- halign: Gtk.Align.CENTER,
- valign: Gtk.Align.CENTER });
- emptyPageTitle.get_style_context().add_class('dim-label');
- this.emptyGrid.add(emptyPageTitle);
- let emptyPageDirections = new Gtk.Label({ label: _("Use the <b>Record</b> button to make sound
recordings"),
- use_markup: true,
- max_width_chars: 30,
- halign: Gtk.Align.CENTER,
- valign: Gtk.Align.CENTER });
- emptyPageDirections.get_style_context().add_class('dim-label');
- this.emptyGrid.add(emptyPageDirections);
- this.emptyGrid.show_all();
- }
-
_addListviewPage(name) {
list = new Listview.Listview();
list.setListTypeNew();
list.enumerateDirectory();
- this._record = new Record.Record(audioProfile);
+
groupGrid = new Gtk.Grid({ orientation: Gtk.Orientation.VERTICAL,
hexpand: true,
@@ -773,39 +825,6 @@ const MainView = GObject.registerClass(class MainView extends Gtk.Stack {
}
});
-const RecordButton = GObject.registerClass(class RecordButton extends Gtk.Button {
- _init(activeProfile) {
- super._init();
- this.image = Gtk.Image.new_from_icon_name('media-record-symbolic', Gtk.IconSize.BUTTON);
- this.set_always_show_image(true);
- this.set_valign(Gtk.Align.CENTER);
- this.set_label(_("Record"));
- this.get_style_context().add_class('text-button');
- this.connect("clicked", () => this._onRecord());
- }
-
- _onRecord() {
- view.destroyLoadMoreButton();
- view.hasPreviousSelRow();
-
- if (view.listBox) {
- view.listBox.set_selection_mode(Gtk.SelectionMode.NONE);
- } else {
- view.emptyGrid.destroy();
- }
-
- this.set_sensitive(false);
- setVisibleID = ActiveArea.RECORD;
- view.recordGrid.show_all();
-
- if (activeProfile == null)
- activeProfile = 0;
-
- audioProfile.profile(activeProfile);
- view._record.startRecording(activeProfile);
- wave = new Waveform.WaveForm(view.recordGrid, null);
- }
-});
var EncoderComboBox = GObject.registerClass(class EncoderComboBox extends Gtk.ComboBoxText {
// encoding setting labels in combobox
diff --git a/src/org.gnome.SoundRecorder.src.gresource.xml.in
b/src/org.gnome.SoundRecorder.src.gresource.xml.in
index 7fb1ff4..48f7ff9 100644
--- a/src/org.gnome.SoundRecorder.src.gresource.xml.in
+++ b/src/org.gnome.SoundRecorder.src.gresource.xml.in
@@ -3,14 +3,15 @@
<gresource prefix="/org/gnome/SoundRecorder@profile@/js">
<file>application.js</file>
<file>audioProfile.js</file>
- <file>fileUtil.js</file>
+ <file>utils.js</file>
<file>info.js</file>
- <file>listview.js</file>
<file>main.js</file>
<file>mainWindow.js</file>
- <file>play.js</file>
+ <file>player.js</file>
<file>preferences.js</file>
- <file>record.js</file>
+ <file>recording.js</file>
+ <file>recordingsManager.js</file>
+ <file>recorder.js</file>
<file>waveform.js</file>
</gresource>
</gresources>
diff --git a/src/play.js b/src/player.js
similarity index 88%
rename from src/play.js
rename to src/player.js
index 0d2bcd4..c6606d2 100644
--- a/src/play.js
+++ b/src/player.js
@@ -20,10 +20,12 @@
const _ = imports.gettext.gettext;
const Gio = imports.gi.Gio;
+const GObject = imports.gi.GObject;
const GLib = imports.gi.GLib;
const Gst = imports.gi.Gst;
const GstAudio = imports.gi.GstAudio;
const GstPbutils = imports.gi.GstPbutils;
+
const Gtk = imports.gi.Gtk;
const Mainloop = imports.mainloop;
@@ -47,16 +49,28 @@ let errorDialogState;
const _TENTH_SEC = 100000000;
-var Play = class Play {
+var Player = GObject.registerClass({
+ Signals: {
+ 'timer-updated': {
+ flags: GObject.SignalFlags.RUN_FIRST,
+ param_types: [ GObject.TYPE_INT ]
+ }
+ }
+
+ },
+ class Player extends GObject.Object {
+ _init() {
+ super._init();
+ this.playState = PipelineStates.STOPPED;
+ this.play = Gst.ElementFactory.make("playbin", "play");
+ this.sink = Gst.ElementFactory.make("pulsesink", "sink");
+ this.play.set_property("audio-sink", this.sink);
+ this.clock = this.play.get_clock();
+ this.playBus = this.play.get_bus();
+ this._asset = null;
+ }
_playPipeline() {
errorDialogState = ErrState.OFF;
- let uri = this._fileToPlay.get_uri();
- this.play = Gst.ElementFactory.make("playbin", "play");
- this.play.set_property("uri", uri);
- this.sink = Gst.ElementFactory.make("pulsesink", "sink");
- this.play.set_property("audio-sink", this.sink);
- this.clock = this.play.get_clock();
- this.playBus = this.play.get_bus();
this.playBus.add_signal_watch();
this.playBus.connect("message", (playBus, message) => {
if (message != null) {
@@ -65,6 +79,16 @@ var Play = class Play {
});
}
+ get duration() {
+ return this.play.query_duration(Gst.Format.TIME)
+
+ }
+
+ setUri(uri) {
+ this.play.set_property("uri", uri);
+ }
+
+
startPlaying() {
this.baseTime = 0;
@@ -85,7 +109,7 @@ var Play = class Play {
this._showErrorDialog(_('Unable to play recording'));
errorDialogState = ErrState.ON;
} else if (this.ret == Gst.StateChangeReturn.SUCCESS) {
- MainWindow.view.setVolume();
+ /*MainWindow.view.setVolume();*/
}
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, Application.SIGINT,
Application.application.onWindowDestroy);
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, Application.SIGTERM,
Application.application.onWindowDestroy);
@@ -117,15 +141,17 @@ var Play = class Play {
GLib.source_remove(this.timeout);
this.timeout = null;
}
-
+ /*
if (MainWindow.wave != null)
MainWindow.wave.endDrawing();
-
+ */
errorDialogState = ErrState.OFF;
}
onEndOfStream() {
+ /*
MainWindow.view.onPlayStopClicked();
+ */
}
_onMessageReceived(message) {
@@ -179,9 +205,9 @@ var Play = class Play {
this.trackDurationSecs = this.trackDuration/Gst.SECOND;
if (time >= 0 && this.playState != PipelineStates.STOPPED) {
- MainWindow.view.setLabel(time);
+ this.emit("timer-updated", time);
} else if (time >= 0 && this.playState == PipelineStates.STOPPED) {
- MainWindow.view.setLabel(0);
+ this.emit("timer-updated", 0);
}
let absoluteTime = 0;
@@ -253,4 +279,5 @@ var Play = class Play {
errorDialog.show();
}
}
-}
+ }
+);
diff --git a/src/record.js b/src/recorder.js
similarity index 85%
rename from src/record.js
rename to src/recorder.js
index 00405c5..5ab1586 100644
--- a/src/record.js
+++ b/src/recorder.js
@@ -32,8 +32,9 @@ const Signals = imports.signals;
const Application = imports.application;
const AudioProfile = imports.audioProfile;
+const WaveForm = imports.waveform.WaveForm;
const MainWindow = imports.mainWindow;
-const Listview = imports.listview;
+const RecordingsManager = imports.recordingsManager;
const PipelineStates = {
PLAYING: 0,
@@ -55,17 +56,33 @@ const _TENTH_SEC = 100000000;
let errorDialogState;
-var Record = class Record {
- _recordPipeline() {
+var Recorder = GObject.registerClass({
+ Signals: {
+ 'timer-updated': {
+ flags: GObject.SignalFlags.RUN_FIRST,
+ param_types: [ GObject.TYPE_INT ]
+ }
+ }
+
+ },class Recorder extends GObject.Object {
+ _init() {
+ super._init();
+
+ let audioProfile = new AudioProfile.AudioProfile();
+ this._mediaProfile = audioProfile.mediaProfile();
+ this.pipeline = null;
+ this.wave = null;
+ this.clipFile = null;
+ }
+
+ _recordPipeline(clipFile) {
errorDialogState = ErrState.OFF;
+ this.clipFile = clipFile;
this.baseTime = 0;
- this._view = MainWindow.view;
- this._buildFileName = new BuildFileName();
- this.initialFileName = this._buildFileName.buildInitialFilename();
- let localDateTime = this._buildFileName.getOrigin();
- this.gstreamerDateTime = Gst.DateTime.new_from_g_date_time(localDateTime);
+ this.wave = new WaveForm(null);
- if (this.initialFileName == -1) {
+ let gstreamerDateTime = Gst.DateTime.new_from_g_date_time(GLib.DateTime.new_now_local());
+ if (!clipFile) {
this._showErrorDialog(_("Unable to create Recordings directory."));
errorDialogState = ErrState.ON;
this.onEndOfStream();
@@ -114,9 +131,9 @@ var Record = class Record {
this.taglist = Gst.TagList.new_empty();
this.taglist.add_value(Gst.TagMergeMode.APPEND, Gst.TAG_APPLICATION_NAME, _("Sound
Recorder"));
element.merge_tags(this.taglist, Gst.TagMergeMode.REPLACE);
- this.taglist.add_value(Gst.TagMergeMode.APPEND, Gst.TAG_TITLE, this.initialFileName);
+ this.taglist.add_value(Gst.TagMergeMode.APPEND, Gst.TAG_TITLE, clipFile.get_uri());
element.merge_tags(this.taglist, Gst.TagMergeMode.REPLACE);
- this.taglist.add_value(Gst.TagMergeMode.APPEND, Gst.TAG_DATE_TIME,
this.gstreamerDateTime);
+ this.taglist.add_value(Gst.TagMergeMode.APPEND, Gst.TAG_DATE_TIME, gstreamerDateTime);
element.merge_tags(this.taglist, Gst.TagMergeMode.REPLACE);
}
}
@@ -125,7 +142,7 @@ var Record = class Record {
let ebinProfile = this.ebin.set_property("profile", this._mediaProfile);
let srcpad = this.ebin.get_static_pad("src");
this.filesink = Gst.ElementFactory.make("filesink", "filesink");
- this.filesink.set_property("location", this.initialFileName);
+ this.filesink.set_property("location", clipFile.get_path());
this.pipeline.add(this.filesink);
if (!this.pipeline || !this.filesink) {
@@ -154,51 +171,63 @@ var Record = class Record {
let time = this.pipeline.query_position(Gst.Format.TIME)[1]/Gst.SECOND;
if (time >= 0) {
- this._view.setLabel(time, 0);
+ this.emit("timer-updated", time);
}
return true;
}
- startRecording(profile) {
- this.profile = profile;
- this._audioProfile = MainWindow.audioProfile;
- this._mediaProfile = this._audioProfile.mediaProfile();
-
+ startNewRecording(uri) {
+ this.uri = uri;
if (this._mediaProfile == -1) {
this._showErrorDialog(_("No Media Profile was set."));
errorDialogState = ErrState.ON;
}
if (!this.pipeline || this.pipeState == PipelineStates.STOPPED )
- this._recordPipeline();
+ this._recordPipeline(uri);
let ret = this.pipeline.set_state(Gst.State.PLAYING);
this.pipeState = PipelineStates.PLAYING;
+ /* FIX ME
if (ret == Gst.StateChangeReturn.FAILURE) {
this._showErrorDialog(_("Unable to set the pipeline \n to the recording state."));
errorDialogState = ErrState.ON;
- this._buildFileName.getTitle().delete_async(GLib.PRIORITY_DEFAULT, null, null);
+ clip.delete_async(GLib.PRIORITY_DEFAULT, null, null);
} else {
MainWindow.view.setVolume();
- }
+ }
+ */
if (!this.timeout) {
this.timeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, MainWindow._SEC_TIMEOUT, () =>
this._updateTime());
}
}
+ isRecording () {
+ if (!this.pipeline)
+ return false;
+ return this.pipeline.get_state(10000) === Gst.State.PLAYING;
+ }
+
+ pauseRecording () {
+ this.pipeline.set_state(Gst.State.PAUSED);
+ }
+
+ resumeRecording () {
+ this.pipeline.set_state(Gst.State.PLAYING);
+ }
+
stopRecording() {
let sent = this.pipeline.send_event(Gst.Event.new_eos());
-
+ let clipFile = this.clipFile;
+ this.clipFile = null;
if (this.timeout) {
GLib.source_remove(this.timeout);
this.timeout = null;
}
-
- if (MainWindow.wave != null)
- MainWindow.wave.endDrawing();
+ return clipFile;
}
onEndOfStream() {
@@ -215,8 +244,8 @@ var Record = class Record {
_onMessageReceived(message) {
this.localMsg = message;
let msg = message.type;
- switch(msg) {
+ switch(msg) {
case Gst.MessageType.ELEMENT:
if (GstPbutils.is_missing_plugin_message(this.localMsg)) {
let errorOne = null;
@@ -271,7 +300,7 @@ var Record = class Record {
this.runTime = this.absoluteTime- this.baseTime;
let approxTime = Math.round(this.runTime/_TENTH_SEC);
- MainWindow.wave._drawEvent(approxTime, this.peak);
+ this.wave._drawEvent(approxTime, this.peak);
}
}
}
@@ -343,27 +372,5 @@ var Record = class Record {
errorDialog.show();
}
}
-}
-
-const BuildFileName = class BuildFileName {
- buildInitialFilename() {
- var fileExtensionName = MainWindow.audioProfile.fileExtensionReturner();
- var dir = Gio.Application.get_default().saveDir;
- this.dateTime = GLib.DateTime.new_now_local();
- var clipNumber = Listview.trackNumber + 1;
- /* Translators: ""Clip %d"" is the default name assigned to a file created
- by the application (for example, "Clip 1"). */
- var clipName = _("Clip %d").format(clipNumber.toString());
- this.clip = dir.get_child_for_display_name(clipName);
- var file = this.clip.get_path();
- return file;
- }
+});
- getTitle() {
- return this.clip;
- }
-
- getOrigin() {
- return this.dateTime;
- }
-}
diff --git a/src/recording.js b/src/recording.js
new file mode 100644
index 0000000..8608e74
--- /dev/null
+++ b/src/recording.js
@@ -0,0 +1,199 @@
+/* exported Record */
+/*
+ * Copyright 2019 Bilal Elmoussaoui
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Bilal Elmoussaoui <bilal elmoussaoui gnome org>
+ *
+ */
+const Gtk = imports.gi.Gtk;
+const GLib = imports.gi.GLib;
+const Gio = imports.gi.Gio;
+const GObject = imports.gi.GObject;
+
+const Gst = imports.gi.Gst;
+const GstPbutils = imports.gi.GstPbutils;
+const Player = imports.player.Player;
+const utils = imports.utils;
+
+const WaveForm = imports.waveform.WaveForm;
+
+var Recording = GObject.registerClass({},
+ class Recording extends GObject.Object {
+
+ _init(file) {
+ super._init();
+ this._file = file;
+
+ this.fileName = null;
+ this.uri = null;
+ this.dateCreated = null;
+ this.duration = 0;
+
+ this._parseInfo();
+ this.wave = new WaveForm(this);
+ }
+
+ get file() {
+ return this._file;
+ }
+
+ _parseInfo() {
+ let returnedName = this._file.get_attribute_as_string("standard::display-name");
+
+ let filePath = GLib.build_filenamev([Gio.Application.get_default().saveDir.get_path(),
+ returnedName]);
+ this.uri = GLib.filename_to_uri(filePath, null);
+
+ if (this._file.has_attribute("time::created")) {
+ let dateCreatedVal = this._file.get_attribute_uint64("time::created");
+ this.dateCreated = GLib.DateTime.new_from_timeval_local(dateCreatedVal);
+ } else {
+ let modificationTime = this._file.get_modification_time();
+ this.dateCreated = GLib.DateTime.new_from_timeval_local(modificationTime);
+ }
+ this.fileName = returnedName;
+
+ let discoverer = new GstPbutils.Discoverer();
+ discoverer.start();
+ discoverer.discover_uri_async(this.uri);
+ discoverer.connect('discovered', (_discoverer, info, error) => {
+ let result = info.get_result();
+ log(result);
+ this._onDiscovererFinished(result, info, error);
+ });
+ }
+
+ _onDiscovererFinished(res, info, err) {
+
+ if (res == GstPbutils.DiscovererResult.OK) {
+
+ this.tagInfo = info.get_tags();
+
+ let dateTimeTag = this.tagInfo.get_date_time('datetime')[1];
+ let durationInfo = info.get_duration();
+ this.duration = durationInfo;
+
+ /* this.file.dateCreated will usually be null since time::created it doesn't usually exist.
+ Therefore, we prefer to set it with tags */
+ if (dateTimeTag != null) {
+ this.dateCreated = dateTimeTag.to_g_date_time();;
+ }
+ /* FIX ME
+ this._getCapsForList(info);
+ */
+ } else {
+ // don't index files we can't play
+
+ log("File cannot be played");
+ }
+
+ }
+
+ }
+);
+
+
+var RecordingRow = GObject.registerClass({
+ Template: 'resource:///org/gnome/SoundRecorder/recording_row.ui',
+ InternalChildren: [
+ 'clip_label',
+ 'created_label',
+ 'time_label',
+ 'play_button',
+ 'pause_button',
+ 'overlay',
+ 'buttons_stack'
+ ],
+ Signals: {
+ }
+ },
+ class RecordingRow extends Gtk.ListBoxRow {
+ _init(recording) {
+ super._init();
+
+ this._player = new Player();
+ this.recording = recording;
+ this._clip_label.set_text(recording.fileName);
+ this._created_label.set_text(utils.getDisplayTime(recording.dateCreated));
+
+ this._overlay.add_overlay(recording.wave);
+
+ this._player.setUri(recording.uri);
+
+ this._play_button.connect('clicked', () => {
+ this._player.startPlaying();
+ this._buttons_stack.set_visible_child_name("pause");
+ });
+
+ this._pause_button.connect('clicked', () => {
+ this._player.pausePlaying();
+ this._buttons_stack.set_visible_child_name("play");
+ });
+
+ this._player.connect("timer-updated", (obj, seconds)=> {
+
+ this._time_label.set_text(utils.getDisplayDuration(seconds));
+ })
+
+ this.show_all();
+ }
+ }
+);
+
+
+var NewRecording = GObject.registerClass({
+ Template: 'resource:///org/gnome/SoundRecorder/recording_waveform_row.ui',
+ InternalChildren: [
+ 'overlay',
+ 'record_time_label'
+ ],
+ Signals: {
+ 'paused': {
+ flags: GObject.SignalFlags.RUN_FIRST
+ },
+ 'resumed': {
+ flags: GObject.SignalFlags.RUN_FIRST
+ }
+ },
+ }, class NewRecording extends Gtk.Box {
+
+ _init() {
+ super._init();
+
+
+ this._state = 0;
+
+ this.show_all();
+ }
+
+ updateRecordTime(seconds) {
+ this._record_time_label.set_text(utils.getDisplayDuration(seconds));
+ }
+
+ setWave(wave) {
+ this._overlay.add_overlay(wave);
+ }
+
+ reset() {
+ this._overlay.remove(this._overlay.get_children()[0])
+ this.updateRecordTime(0);
+
+ }
+
+
+ }
+);
+
+
diff --git a/src/recordingsManager.js b/src/recordingsManager.js
new file mode 100644
index 0000000..2468098
--- /dev/null
+++ b/src/recordingsManager.js
@@ -0,0 +1,251 @@
+/* exported Listview */
+/*
+ * Copyright 2013 Meg Ford
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Author: Meg Ford <megford gnome org>
+ *
+ */
+
+const _ = imports.gettext.gettext;
+const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
+const GObject = imports.gi.GObject;
+const Gst = imports.gi.Gst;
+const GstPbutils = imports.gi.GstPbutils;
+const Signals = imports.signals;
+
+
+const Recording = imports.recording.Recording;
+const AudioProfile = imports.audioProfile;
+const MainWindow = imports.mainWindow;
+const Recorder = imports.recorder.Recorder;
+
+
+const utils = imports.utils;
+
+const EnumeratorState = {
+ ACTIVE: 0,
+ CLOSED: 1
+};
+
+const mediaTypeMap = {
+ FLAC: "FLAC",
+ OGG_VORBIS: "Ogg Vorbis",
+ OPUS: "Opus",
+ MP3: "MP3",
+ MP4: "MP4"
+};
+
+const ListType = {
+ NEW: 0,
+ REFRESH: 1
+};
+
+const CurrentlyEnumerating = {
+ TRUE: 0,
+ FALSE: 1
+};
+
+
+let currentlyEnumerating = null;
+let fileInfo = null;
+let listType = null;
+let startRecording = false;
+let stopVal = null;
+
+var RecordingsManager = GObject.registerClass({
+ Signals: {
+ 'recording-added': {
+ flags: GObject.SignalFlags.RUN_FIRST,
+ param_types: [ GObject.Object ]
+ }
+ }
+ },
+ class RecordingsManager extends GObject.Object {
+ _init() {
+ super._init();
+
+ stopVal = EnumeratorState.ACTIVE;
+ this._recordings = [];
+
+ this._recorder = new Recorder();
+
+ // Save a reference to the savedir to quickly access it
+ this._saveDir = Gio.Application.get_default().saveDir;
+ this.enumerateDirectory();
+ this.dirMonitor = this._saveDir.monitor_directory(Gio.FileMonitorFlags.WATCH_MOVES, null);
+ this.dirMonitor.connect('changed', (dirMonitor, file1, file2, eventType) =>
this._onDirChanged(dirMonitor, file1, file2, eventType));
+
+ }
+
+ getTracksCount() {
+ return this._recordings.length;
+ }
+
+ startNewRecording() {
+ if (!this._recorder.isRecording()) {
+ var dir = Gio.Application.get_default().saveDir;
+ var clipNumber = this._recordings.length + 1;
+ /* Translators: ""Clip %d"" is the default name assigned to a file created
+ by the application (for example, "Clip 1"). */
+ var clipName = _("Clip %d").format(clipNumber.toString());
+ let clipFile = dir.get_child_for_display_name(clipName);
+ this._recorder.startNewRecording(clipFile);
+ return this._recorder.wave;
+ }
+ }
+
+ saveRecording() {
+ let clipFile = this._recorder.stopRecording();
+ let fileInfo = clipFile.query_info('standard::display-name,time::created,time::modified',
+ Gio.FileQueryInfoFlags.NONE, null)
+ let recording = new Recording(fileInfo);
+ this._recordings.push(recording);
+ this.emit("recording-added", recording);
+
+ }
+
+ enumerateDirectory() {
+ this._saveDir.enumerate_children_async('standard::display-name,time::created,time::modified',
+ Gio.FileQueryInfoFlags.NONE,
+ GLib.PRIORITY_LOW,
+ null,
+ (obj, res) => this._onEnumerator(obj, res));
+ }
+
+ _onEnumerator(obj, res) {
+ this._enumerator = obj.enumerate_children_finish(res);
+
+ if (this._enumerator == null)
+ log("The contents of the Recordings directory were not indexed.");
+ else
+ this._onNextFileComplete();
+ }
+
+ _onNextFileComplete () {
+ fileInfo = [];
+ try{
+ this._enumerator.next_files_async(20, GLib.PRIORITY_DEFAULT, null, (obj, res) => {
+ let files = obj.next_files_finish(res);
+
+
+ files.forEach((file) => {
+
+ let recording = new Recording(file);
+ this._recordings.push(recording);
+ this.emit("recording-added", recording);
+
+ });
+ // this._sortItems(fileInfo);
+ });
+ } catch(e) {
+ log(e);
+ }
+ }
+
+
+ _onDirChanged(dirMonitor, file1, file2, eventType) {
+
+ if (eventType == Gio.FileMonitorEvent.DELETED && Gio.Application.get_default().saveDir.equal(file1))
{
+ Gio.Application.get_default().ensure_directory();
+ this._saveDir = Gio.Application.get_default().saveDir;
+ }
+ if ((eventType == Gio.FileMonitorEvent.MOVED_OUT) ||
+ (eventType == Gio.FileMonitorEvent.CHANGES_DONE_HINT
+ && MainWindow.recordPipeline == MainWindow.RecordPipelineStates.STOPPED) || (eventType ==
Gio.FileMonitorEvent.RENAMED)) {
+ stopVal = EnumeratorState.ACTIVE;
+
+ listType = ListType.REFRESH;
+
+ if (currentlyEnumerating == CurrentlyEnumerating.FALSE) {
+ currentlyEnumerating = CurrentlyEnumerating.TRUE;
+ MainWindow.view.listBoxRefresh();
+ }
+ }
+ log(eventType);
+ if (eventType == Gio.FileMonitorEvent.CHANGES_DONE_HINT ) {
+
+ }
+ }
+
+
+ _onDirChangedDeb(dirMonitor, file1, file2, eventType) {
+ /* Workaround for Debian and Tails not recognizing Gio.FileMointor.WATCH_MOVES */
+ if (eventType == Gio.FileMonitorEvent.DELETED && Gio.Application.get_default().saveDir.equal(file1))
{
+ Gio.Application.get_default().ensure_directory();
+ this._saveDir = Gio.Application.get_default().saveDir;
+ }
+ if ((eventType == Gio.FileMonitorEvent.DELETED) ||
+ (eventType == Gio.FileMonitorEvent.CHANGES_DONE_HINT && MainWindow.recordPipeline ==
MainWindow.RecordPipelineStates.STOPPED)) {
+ stopVal = EnumeratorState.ACTIVE;
+ allFilesInfo.length = 0;
+ fileInfo.length = 0;
+ this.idx = 0;
+ listType = ListType.REFRESH;
+
+ if (currentlyEnumerating == CurrentlyEnumerating.FALSE) {
+ currentlyEnumerating = CurrentlyEnumerating.TRUE;
+ MainWindow.view.listBoxRefresh();
+ }
+ }
+
+ else if (eventType == Gio.FileMonitorEvent.CREATED) {
+ log("hey) ")
+ startRecording = true;
+ }
+ }
+
+ _getCapsForList(info) {
+ let discovererStreamInfo = null;
+ discovererStreamInfo = info.get_stream_info();
+ let containerStreams = info.get_container_streams()[0];
+ let containerCaps = discovererStreamInfo.get_caps();
+ let audioStreams = info.get_audio_streams()[0];
+ let audioCaps = audioStreams.get_caps();
+
+ if (containerCaps.can_intersect(this.capTypes(AudioProfile.containerProfileMap.AUDIO_OGG))) {
+
+ if (audioCaps.can_intersect(this.capTypes(AudioProfile.audioCodecMap.VORBIS)))
+ allFilesInfo[this.idx].mediaType = mediaTypeMap.OGG_VORBIS;
+ else if (audioCaps.can_intersect(this.capTypes(AudioProfile.audioCodecMap.OPUS)))
+ allFilesInfo[this.idx].mediaType = mediaTypeMap.OPUS;
+
+ } else if (containerCaps.can_intersect(this.capTypes(AudioProfile.containerProfileMap.ID3))) {
+
+ if (audioCaps.can_intersect(this.capTypes(AudioProfile.audioCodecMap.MP3)))
+ allFilesInfo[this.idx].mediaType = mediaTypeMap.MP3;
+
+ } else if (containerCaps.can_intersect(this.capTypes(AudioProfile.containerProfileMap.MP4))) {
+
+ if (audioCaps.can_intersect(this.capTypes(AudioProfile.audioCodecMap.MP4)))
+ allFilesInfo[this.idx].mediaType = mediaTypeMap.MP4;
+
+ } else if (audioCaps.can_intersect(this.capTypes(AudioProfile.audioCodecMap.FLAC))) {
+ allFilesInfo[this.idx].mediaType = mediaTypeMap.FLAC;
+
+ }
+
+ if (allFilesInfo[this.idx].mediaType == null) {
+ // Remove the file from the array if we don't recognize it
+ allFilesInfo.splice(this.idx, 1);
+ }
+ }
+
+ capTypes(capString) {
+ let caps = Gst.Caps.from_string(capString);
+ return caps;
+ }
+});
diff --git a/src/utils.js b/src/utils.js
new file mode 100644
index 0000000..e052954
--- /dev/null
+++ b/src/utils.js
@@ -0,0 +1,79 @@
+/* exported getDisplayTime */
+/*
+ * Copyright 2013 Meg Ford
+ * Copyright (c) 2013 Giovanni Campagna <scampa giovanni gmail com>
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Meg Ford <megford gnome org>
+ *
+ */
+ // -*- Mode: js; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*-
+
+const Gdk = imports.gi.Gdk;
+const GLib = imports.gi.GLib;
+const Gtk = imports.gi.Gtk;
+
+
+const Gettext = imports.gettext;
+const _ = imports.gettext.gettext;
+
+
+var getDisplayTime = function (mtime) {
+ let text = "";
+ let DAY = 86400000000;
+ let now = GLib.DateTime.new_now_local();
+ let difference = now.difference(mtime);
+ let days = Math.floor(difference / DAY);
+ let weeks = Math.floor(difference / (7 * DAY));
+ let months = Math.floor(difference / (30 * DAY));
+ let years = Math.floor(difference / (365 * DAY));
+
+ if (difference < DAY) {
+ let time = mtime.format('%X');
+ text = _(`Today, ${time}`);
+ } else if (difference < 2 * DAY) {
+ text = _("Yesterday");
+ } else if (difference < 7 * DAY) {
+ text = Gettext.ngettext("%d day ago",
+ "%d days ago",
+ days).format(days);
+ } else if (difference < 14 * DAY) {
+ text = _("Last week");
+ } else if (difference < 28 * DAY) {
+ text = Gettext.ngettext("%d week ago",
+ "%d weeks ago",
+ weeks).format(weeks);
+ } else if (difference < 60 * DAY) {
+ text = _("Last month");
+ } else if (difference < 360 * DAY) {
+ text = Gettext.ngettext("%d month ago",
+ "%d months ago",
+ months).format(months);
+ } else if (difference < 730 * DAY) {
+ text = _("Last year");
+ } else {
+ text = Gettext.ngettext("%d year ago",
+ "%d years ago",
+ years).format(years);
+ }
+ return text;
+}
+
+
+var getDisplayDuration = function (seconds) {
+ let hoursStr = String(parseInt((seconds / 3600) % 60)).padStart(2, '0')
+ let minutesStr = String(parseInt((seconds / 60) % 60)).padStart(2, '0')
+ let secondsStr = String(parseInt(seconds % 60)).padStart(2, '0')
+ return `${hoursStr}:${minutesStr}:${secondsStr}`;
+}
diff --git a/src/waveform.js b/src/waveform.js
index 6813884..7ab1351 100644
--- a/src/waveform.js
+++ b/src/waveform.js
@@ -45,10 +45,9 @@ const WaveType = {
PLAY: 1
};
-var WaveForm = class WaveForm {
- constructor(grid, file) {
- this._grid = grid;
-
+var WaveForm = GObject.registerClass(class WaveForm extends Gtk.DrawingArea {
+ _init(file) {
+ super._init();
let placeHolder = -100;
for (let i = 0; i < 40; i++)
peaks.push(placeHolder);
@@ -56,34 +55,30 @@ var WaveForm = class WaveForm {
this.waveType = WaveType.PLAY;
this.file = file;
this.duration = this.file.duration;
+
this._uri = this.file.uri;
+ log(this.duration );
} else {
this.waveType = WaveType.RECORD;
}
+ this.recordTime = -1;
+ this.playTime = 0;
let gridWidth = 0;
let drawingWidth = 0;
let drawingHeight = 0;
- this.drawing = Gtk.DrawingArea.new();
- if (this.waveType == WaveType.RECORD) {
- this.drawing.set_property("valign", Gtk.Align.FILL);
- this.drawing.set_property("hexpand",true);
- this._grid.attach(this.drawing, 2, 0, 3, 2);
- } else {
- this.drawing.set_property("valign", Gtk.Align.FILL);
- this.drawing.set_property("hexpand",true);
- this.drawing.set_property("vexpand",true);
- this._grid.add(this.drawing);
- }
- this.drawing.connect("draw", (drawing, cr) => this.fillSurface(drawing, cr));
- this.drawing.show_all();
- this._grid.show_all();
+ this.set_property("hexpand", true);
+
+ this.connect("draw", (drawing, cr) => this.fillSurface(drawing, cr));
if (this.waveType == WaveType.PLAY) {
this._launchPipeline();
this.startGeneration();
+
}
+ this.show_all();
+
}
_launchPipeline() {
@@ -93,6 +88,7 @@ var WaveForm = class WaveForm {
let decode = this.pipeline.get_by_name("decode");
let bus = this.pipeline.get_bus();
bus.add_signal_watch();
+
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, Application.SIGINT,
Application.application.onWindowDestroy);
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, Application.SIGTERM,
Application.application.onWindowDestroy);
@@ -107,7 +103,6 @@ var WaveForm = class WaveForm {
_messageCb(message) {
let msg = message.type;
-
switch(msg) {
case Gst.MessageType.ELEMENT:
let s = message.get_structure();
@@ -154,6 +149,7 @@ var WaveForm = class WaveForm {
stopGeneration() {
this.pipeline.set_state(Gst.State.NULL);
+
}
fillSurface(drawing, cr) {
@@ -168,14 +164,16 @@ var WaveForm = class WaveForm {
} else {
if (this.recordTime >= 0) {
start = this.recordTime;
+ } else {
+ return
}
}
let i = 0;
let xAxis = 0;
let end = start + 40;
- let width = this.drawing.get_allocated_width();
- let waveheight = this.drawing.get_allocated_height();
+ let width = this.get_allocated_width();
+ let waveheight = this.get_allocated_height();
let length = this.nSamples;
let pixelsPerSample = width/waveSamples;
let gradient = new Cairo.LinearGradient(0, 0, width , waveheight);
@@ -231,7 +229,7 @@ var WaveForm = class WaveForm {
}
if (lastTime != this.playTime) {
- this.drawing.queue_draw();
+ this.queue_draw();
}
} else {
@@ -243,8 +241,7 @@ var WaveForm = class WaveForm {
log("error");
return true;
}
- if (this.drawing)
- this.drawing.queue_draw();
+ this.queue_draw();
}
return true;
}
@@ -255,10 +252,5 @@ var WaveForm = class WaveForm {
this.count = 0;
peaks.length = 0;
- try {
- this.drawing.destroy();
- } catch (e) {
- log(e);
- }
}
-}
+});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]