diff --git a/manifest.json.in b/manifest.json.in index 7d5cbe1..6136bd4 100644 --- a/manifest.json.in +++ b/manifest.json.in @@ -8,7 +8,7 @@ "desktop": "mines.neothethird.desktop" } }, - "version": "1.0", + "version": "1.1", "maintainer": "Jan Sprinz ", "framework" : "ubuntu-sdk-15.04.6" } diff --git a/po/mines.neothethird.pot b/po/mines.neothethird.pot index e0131e4..e1beae3 100644 --- a/po/mines.neothethird.pot +++ b/po/mines.neothethird.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: mines.neothethird\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-06-20 18:19+0000\n" +"POT-Creation-Date: 2017-06-20 20:00+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,102 +18,138 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" #. TRANSLATORS: Title for dialog shown when starting a new game while one in progress -#: ../qml/Main.qml:93 +#: ../qml/Main.qml:95 msgid "Game in progress" msgstr "" #. TRANSLATORS: Content for dialog shown when starting a new game while one in progress -#: ../qml/Main.qml:95 +#: ../qml/Main.qml:97 msgid "Are you sure you want to restart this game?" msgstr "" #. TRANSLATORS: Button in new game dialog that cancels the current game and starts a new one -#: ../qml/Main.qml:98 +#: ../qml/Main.qml:100 msgid "Restart game" msgstr "" #. TRANSLATORS: Button in new game dialog that cancels new game request -#: ../qml/Main.qml:107 +#: ../qml/Main.qml:109 msgid "Continue current game" msgstr "" #. TRANSLATORS: Title for dialog confirming if scores should be cleared #. TRANSLATORS: Button in clear scores dialog that clears scores #. TRANSLATORS: Action in high scores page that clears scores -#: ../qml/Main.qml:118 ../qml/Main.qml:123 ../qml/Main.qml:233 +#: ../qml/Main.qml:120 ../qml/Main.qml:125 ../qml/Main.qml:315 msgid "Clear scores" msgstr "" #. TRANSLATORS: Content for dialog confirming if scores should be cleared -#: ../qml/Main.qml:120 +#: ../qml/Main.qml:122 msgid "Existing scores will be deleted. This cannot be undone." msgstr "" #. TRANSLATORS: Button in clear scores dialog that cancels clear scores request -#: ../qml/Main.qml:132 +#: ../qml/Main.qml:134 msgid "Keep existing scores" msgstr "" #. TRANSLATORS: Title of application -#: ../qml/Main.qml:146 +#: ../qml/Main.qml:148 ../qml/Main.qml:224 msgid "Mines" msgstr "" #. TRANSLATORS: Action on main page that shows game instructions #. TRANSLATORS: Title of page with game instructions -#: ../qml/Main.qml:151 ../qml/Main.qml:201 +#: ../qml/Main.qml:153 ../qml/Main.qml:203 msgid "How to Play" msgstr "" #. TRANSLATORS: Action on main page that shows settings dialog #. TRANSLATORS: Title of page showing settings -#: ../qml/Main.qml:157 ../qml/Main.qml:244 +#: ../qml/Main.qml:159 ../qml/Main.qml:326 msgid "Settings" msgstr "" #. TRANSLATORS: Action on main page that starts a new game -#: ../qml/Main.qml:163 +#: ../qml/Main.qml:165 msgid "New Game" msgstr "" +#: ../qml/Main.qml:242 +msgid "Version: " +msgstr "" + +#. TRANSLATORS: Short description +#: ../qml/Main.qml:251 +msgid "" +"Mines is a puzzle game where the goal is to find the mines in a minefield." +msgstr "" + #. TRANSLATORS: Game instructions -#: ../qml/Main.qml:210 +#: ../qml/Main.qml:261 msgid "" -"

Mines is a puzzle game where the goal is to find the mines in a " -"minefield


The minefield is divided into a grid of squares. Touch " -"a square to check if there is a mine there. If no mine is present the square " -"will show the number of mines surrounding it. Use logic to determine a " -"square that cannot contain a mine to check next. If you hit a mine it " -"explodes and the game is over. You can flag where a mine is by touching and " -"holding that square.

Have fun!

" +"The minefield is divided into a grid of squares. Touch a square to check if " +"there is a mine there. If no mine is present the square will show the number " +"of mines surrounding it. Use logic to determine a square that cannot contain " +"a mine to check next. If you hit a mine it explodes and the game is over. " +"You can flag where a mine is by touching and holding that square. Have fun!" +msgstr "" + +#. TRANSLATORS: GPL notice +#: ../qml/Main.qml:271 +msgid "" +"This program is free software: you can redistribute it and/or modify it " +"under the terms of the GNU General Public License as published by the Free " +"Software Foundation, either version 3 of the License, or (at your option) " +"any later version. This program 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 General Public " +"License for more details." +msgstr "" + +#: ../qml/Main.qml:280 +msgid "" +"SOURCE | ISSUES | DONATE" +msgstr "" + +#: ../qml/Main.qml:290 +msgid "Copyright (c) 2015 Robert Ancell" +msgstr "" + +#: ../qml/Main.qml:299 +msgid "Copyright (c) 2017 Jan Sprinz " msgstr "" #. TRANSLATORS: Title of page showing high scores -#: ../qml/Main.qml:227 +#: ../qml/Main.qml:309 msgid "High Scores" msgstr "" #. TRANSLATORS: Label beside checkbox setting for controlling vibrations when placing flags -#: ../qml/Main.qml:250 +#: ../qml/Main.qml:332 msgid "Vibrate when placing flags" msgstr "" #. TRANSLATORS: Label above setting to choose the minefield size -#: ../qml/Main.qml:260 +#: ../qml/Main.qml:342 msgid "Minefield size:" msgstr "" #. TRANSLATORS: Setting name for small minefield -#: ../qml/Main.qml:267 +#: ../qml/Main.qml:349 msgid "Small" msgstr "" #. TRANSLATORS: Setting name for large minefield -#: ../qml/Main.qml:270 +#: ../qml/Main.qml:352 msgid "Large" msgstr "" #. TRANSLATORS: Description format for minefield size, %width%, %height% and %nmines% is replaced with the field width, height and number of mines -#: ../qml/Main.qml:276 +#: ../qml/Main.qml:358 msgid "%width%×%height%, %nmines% mines" msgstr "" diff --git a/qml/Main.qml b/qml/Main.qml index 76462d6..34f90e2 100644 --- a/qml/Main.qml +++ b/qml/Main.qml @@ -36,6 +36,8 @@ MainView { automaticOrientation: true id: app + property string version: "1.1" + width: units.gu (40) height: units.gu (71) @@ -58,94 +60,94 @@ MainView { if (s.grid_width == item.grid_width && s.grid_height == item.grid_height && s.n_mines == item.n_mines) { - size_selector.selectedIndex = i - break + size_selector.selectedIndex = i + break + } } } - } - catch (e) { - } - }) + catch (e) { + } + }) - reset_field () - } + reset_field () + } - function save_state () { - get_state_database ().transaction (function (t) { - var grid_options = size_selector.model.get (size_selector.selectedIndex) - // The lock field is to ensure the INSERT will always replace this row instead of adding another - t.executeSql ("CREATE TABLE IF NOT EXISTS Settings(lock INTEGER, use_haptic BOOLEAN, grid_width INTEGER, grid_height INTEGER, n_mines INTEGER, PRIMARY KEY (lock))") - t.executeSql ("INSERT OR REPLACE INTO Settings VALUES(0, ?, ?, ?, ?)", [haptic_check.checked, grid_options.grid_width, grid_options.grid_height, grid_options.n_mines]) - }) - } + function save_state () { + get_state_database ().transaction (function (t) { + var grid_options = size_selector.model.get (size_selector.selectedIndex) + // The lock field is to ensure the INSERT will always replace this row instead of adding another + t.executeSql ("CREATE TABLE IF NOT EXISTS Settings(lock INTEGER, use_haptic BOOLEAN, grid_width INTEGER, grid_height INTEGER, n_mines INTEGER, PRIMARY KEY (lock))") + t.executeSql ("INSERT OR REPLACE INTO Settings VALUES(0, ?, ?, ?, ?)", [haptic_check.checked, grid_options.grid_width, grid_options.grid_height, grid_options.n_mines]) + }) + } - function reset_field () - { - var grid_options = size_selector.model.get (size_selector.selectedIndex) - minefield.set_size (grid_options.grid_width, grid_options.grid_height, grid_options.n_mines) - } + function reset_field () + { + var grid_options = size_selector.model.get (size_selector.selectedIndex) + minefield.set_size (grid_options.grid_width, grid_options.grid_height, grid_options.n_mines) + } - Component { - id: confirm_new_game_dialog - Dialog { - id: d - // TRANSLATORS: Title for dialog shown when starting a new game while one in progress - title: i18n.tr ("Game in progress") - // TRANSLATORS: Content for dialog shown when starting a new game while one in progress - text: i18n.tr ("Are you sure you want to restart this game?") - Button { - // TRANSLATORS: Button in new game dialog that cancels the current game and starts a new one - text: i18n.tr ("Restart game") - color: UbuntuColors.red - onClicked: { - reset_field () - PopupUtils.close (d) + Component { + id: confirm_new_game_dialog + Dialog { + id: d + // TRANSLATORS: Title for dialog shown when starting a new game while one in progress + title: i18n.tr ("Game in progress") + // TRANSLATORS: Content for dialog shown when starting a new game while one in progress + text: i18n.tr ("Are you sure you want to restart this game?") + Button { + // TRANSLATORS: Button in new game dialog that cancels the current game and starts a new one + text: i18n.tr ("Restart game") + color: UbuntuColors.red + onClicked: { + reset_field () + PopupUtils.close (d) + } + } + Button { + // TRANSLATORS: Button in new game dialog that cancels new game request + text: i18n.tr ("Continue current game") + onClicked: PopupUtils.close (d) } - } - Button { - // TRANSLATORS: Button in new game dialog that cancels new game request - text: i18n.tr ("Continue current game") - onClicked: PopupUtils.close (d) } } - } - Component { - id: confirm_clear_scores_dialog - Dialog { - id: d - // TRANSLATORS: Title for dialog confirming if scores should be cleared - title: i18n.tr ("Clear scores") - // TRANSLATORS: Content for dialog confirming if scores should be cleared - text: i18n.tr ("Existing scores will be deleted. This cannot be undone.") - Button { - // TRANSLATORS: Button in clear scores dialog that clears scores - text: i18n.tr ("Clear scores") - color: UbuntuColors.red - onClicked: { - table.clear_scores () - PopupUtils.close (d) + Component { + id: confirm_clear_scores_dialog + Dialog { + id: d + // TRANSLATORS: Title for dialog confirming if scores should be cleared + title: i18n.tr ("Clear scores") + // TRANSLATORS: Content for dialog confirming if scores should be cleared + text: i18n.tr ("Existing scores will be deleted. This cannot be undone.") + Button { + // TRANSLATORS: Button in clear scores dialog that clears scores + text: i18n.tr ("Clear scores") + color: UbuntuColors.red + onClicked: { + table.clear_scores () + PopupUtils.close (d) + } + } + Button { + // TRANSLATORS: Button in clear scores dialog that cancels clear scores request + text: i18n.tr ("Keep existing scores") + onClicked: PopupUtils.close (d) } - } - Button { - // TRANSLATORS: Button in clear scores dialog that cancels clear scores request - text: i18n.tr ("Keep existing scores") - onClicked: PopupUtils.close (d) } } - } - PageStack { - id: page_stack - Component.onCompleted: push (main_page) - - Page { - id: main_page - visible: false - // TRANSLATORS: Title of application - title: i18n.tr ("Mines") - head.actions: - [ + PageStack { + id: page_stack + Component.onCompleted: push (main_page) + + Page { + id: main_page + visible: false + // TRANSLATORS: Title of application + title: i18n.tr ("Mines") + head.actions: + [ Action { // TRANSLATORS: Action on main page that shows game instructions text: i18n.tr ("How to Play") @@ -164,140 +166,220 @@ MainView { iconName: "reload" onTriggered: { if (minefield.started && !minefield.completed) - PopupUtils.open (confirm_new_game_dialog) + PopupUtils.open (confirm_new_game_dialog) else - reset_field () + reset_field () } } - ] - - MinefieldModel { - id: minefield - onSolved: { - get_history_database ().transaction (function (t) { - t.executeSql ("CREATE TABLE IF NOT EXISTS History(grid_width INTEGER, grid_height INTEGER, n_mines INTEGER, date TEXT, duration INTEGER)") - var duration = minefield.end_time - minefield.start_time - t.executeSql ("INSERT INTO History VALUES(?, ?, ?, ?, ?)", [minefield.columns, minefield.rows, minefield.n_mines, minefield.start_time.toISOString (), duration]) - }) + ] + + MinefieldModel { + id: minefield + onSolved: { + get_history_database ().transaction (function (t) { + t.executeSql ("CREATE TABLE IF NOT EXISTS History(grid_width INTEGER, grid_height INTEGER, n_mines INTEGER, date TEXT, duration INTEGER)") + var duration = minefield.end_time - minefield.start_time + t.executeSql ("INSERT INTO History VALUES(?, ?, ?, ?, ?)", [minefield.columns, minefield.rows, minefield.n_mines, minefield.start_time.toISOString (), duration]) + }) + } } - } - Item { - anchors.fill: parent - anchors.margins: units.gu (2) - MinefieldView { - model: minefield - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - use_haptic_feedback: haptic_check.checked + Item { + anchors.fill: parent + anchors.margins: units.gu (2) + MinefieldView { + model: minefield + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + use_haptic_feedback: haptic_check.checked + } } } - } - Page { - id: how_to_play_page - visible: false - // TRANSLATORS: Title of page with game instructions - title: i18n.tr ("How to Play") - - Label { - anchors.fill: parent - anchors.margins: units.gu (2) - - wrapMode: Text.Wrap - textFormat: Text.StyledText - // TRANSLATORS: Game instructions - text: i18n.tr ("

Mines is a puzzle game where the goal is to find the mines in a minefield

\ -
\ -

The minefield is divided into a grid of squares. \ -Touch a square to check if there is a mine there. \ -If no mine is present the square will show the number of mines surrounding it. \ -Use logic to determine a square that cannot contain a mine to check next. \ -If you hit a mine it explodes and the game is over. \ -You can flag where a mine is by touching and holding that square. \ -
\ -

Have fun!

") + Page { + id: how_to_play_page + visible: false + // TRANSLATORS: Title of page with game instructions + title: i18n.tr ("How to Play") + Flickable { + id: flick + anchors { + fill: parent + margins: units.gu(3) + topMargin: 0 + bottomMargin: 0 + } + clip: true + contentWidth: aboutColumn.width + contentHeight: aboutColumn.height + + Column { + id: aboutColumn + width: parent.parent.width + spacing: units.gu(3) + + Label { + anchors.horizontalCenter: parent.horizontalCenter + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + text: i18n.tr("Mines") + fontSize: "x-large" + } + + UbuntuShape { + width: units.gu(12); height: units.gu(12) + anchors.horizontalCenter: parent.horizontalCenter + radius: "medium" + image: Image { + source: Qt.resolvedUrl("../assets/mines.png") + } + } + + Label { + width: parent.width + linkColor: UbuntuColors.orange + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + text: i18n.tr("Version: ") + app.version + } + + Label { + width: parent.width + linkColor: UbuntuColors.orange + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + // TRANSLATORS: Short description + text: i18n.tr("Mines is a puzzle game where the goal is to find the mines in a minefield.") + onLinkActivated: Qt.openUrlExternally(link) + } + + Label { + width: parent.width + linkColor: UbuntuColors.orange + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + // TRANSLATORS: Game instructions + text: i18n.tr("The minefield is divided into a grid of squares. Touch a square to check if there is a mine there. If no mine is present the square will show the number of mines surrounding it. Use logic to determine a square that cannot contain a mine to check next. If you hit a mine it explodes and the game is over. You can flag where a mine is by touching and holding that square. Have fun!") + onLinkActivated: Qt.openUrlExternally(link) + } + + Label { + width: parent.width + linkColor: UbuntuColors.orange + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + // TRANSLATORS: GPL notice + text: i18n.tr("This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details.") + onLinkActivated: Qt.openUrlExternally(link) + } + + Label { + width: parent.width + linkColor: UbuntuColors.orange + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + text: i18n.tr("SOURCE | ISSUES | DONATE") + onLinkActivated: Qt.openUrlExternally(link) + } + + Label { + width: parent.width + linkColor: UbuntuColors.orange + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + style: Font.Bold + text: i18n.tr("Copyright (c) 2015 Robert Ancell") + } + + Label { + width: parent.width + linkColor: UbuntuColors.orange + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + style: Font.Bold + text: i18n.tr("Copyright (c) 2017 Jan Sprinz ") + } + } + } } - } - Page { - id: scores_page - visible: false - // TRANSLATORS: Title of page showing high scores - title: i18n.tr ("High Scores") + Page { + id: scores_page + visible: false + // TRANSLATORS: Title of page showing high scores + title: i18n.tr ("High Scores") - head.actions: - [ + head.actions: + [ Action { // TRANSLATORS: Action in high scores page that clears scores text: i18n.tr ("Clear scores") iconName: "reset" onTriggered: PopupUtils.open (confirm_clear_scores_dialog) } - ] - } + ] + } + + Page { + id: settings_page + visible: false + // TRANSLATORS: Title of page showing settings + title: i18n.tr ("Settings") - Page { - id: settings_page - visible: false - // TRANSLATORS: Title of page showing settings - title: i18n.tr ("Settings") - - Column { - anchors.fill: parent - ListItem.Standard { - // TRANSLATORS: Label beside checkbox setting for controlling vibrations when placing flags - text: i18n.tr ("Vibrate when placing flags") - control: CheckBox { - id: haptic_check - checked: true - onCheckedChanged: save_state () + Column { + anchors.fill: parent + ListItem.Standard { + // TRANSLATORS: Label beside checkbox setting for controlling vibrations when placing flags + text: i18n.tr ("Vibrate when placing flags") + control: CheckBox { + id: haptic_check + checked: true + onCheckedChanged: save_state () + } } - } - ListItem.ItemSelector { - id: size_selector - // TRANSLATORS: Label above setting to choose the minefield size - text: i18n.tr ("Minefield size:") - model: field_size_model - delegate: OptionSelectorDelegate { - text: { - switch (name) { - case "small": - // TRANSLATORS: Setting name for small minefield - return i18n.tr ("Small") - case "large": - // TRANSLATORS: Setting name for large minefield - return i18n.tr ("Large") - default: - return "" + ListItem.ItemSelector { + id: size_selector + // TRANSLATORS: Label above setting to choose the minefield size + text: i18n.tr ("Minefield size:") + model: field_size_model + delegate: OptionSelectorDelegate { + text: { + switch (name) { + case "small": + // TRANSLATORS: Setting name for small minefield + return i18n.tr ("Small") + case "large": + // TRANSLATORS: Setting name for large minefield + return i18n.tr ("Large") + default: + return "" + } } + // TRANSLATORS: Description format for minefield size, %width%, %height% and %nmines% is replaced with the field width, height and number of mines + subText: i18n.tr ("%width%×%height%, %nmines% mines").replace ("%width%", grid_width).replace ("%height%", grid_height).replace ("%nmines%", n_mines) } - // TRANSLATORS: Description format for minefield size, %width%, %height% and %nmines% is replaced with the field width, height and number of mines - subText: i18n.tr ("%width%×%height%, %nmines% mines").replace ("%width%", grid_width).replace ("%height%", grid_height).replace ("%nmines%", n_mines) - } - onSelectedIndexChanged: { - save_state () - if (!minefield.started || minefield.completed) + onSelectedIndexChanged: { + save_state () + if (!minefield.started || minefield.completed) reset_field () + } } } } - } - ListModel { - id: field_size_model - ListElement { - name: "small" - grid_width: 8 - grid_height: 8 - n_mines: 10 - } - ListElement { - name: "large" - grid_width: 10 - grid_height: 16 - n_mines: 25 + ListModel { + id: field_size_model + ListElement { + name: "small" + grid_width: 8 + grid_height: 8 + n_mines: 10 + } + ListElement { + name: "large" + grid_width: 10 + grid_height: 16 + n_mines: 25 + } } } } -}