Initial commmit
This commit is contained in:
commit
ff749d68b6
18 changed files with 534 additions and 0 deletions
35
.gitignore
vendored
Normal file
35
.gitignore
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
node_modules
|
||||
# See https://www.dartlang.org/tools/private-files.html
|
||||
|
||||
# Files and directories created by pub
|
||||
.buildlog
|
||||
.packages
|
||||
.project
|
||||
.pub/
|
||||
build/
|
||||
**/packages/
|
||||
|
||||
# Files created by dart2js
|
||||
# (Most Dart developers will use pub build to compile Dart, use/modify these
|
||||
# rules if you intend to use dart2js directly
|
||||
# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
|
||||
# differentiate from explicit Javascript files)
|
||||
*.dart.js
|
||||
*.part.js
|
||||
*.js.deps
|
||||
*.js.map
|
||||
*.info.json
|
||||
|
||||
# Directory created by dartdoc
|
||||
doc/api/
|
||||
|
||||
# Don't commit pubspec lock file
|
||||
# (Library packages only! Remove pattern if developing an application package)
|
||||
pubspec.lock
|
||||
web/packages
|
||||
|
||||
# IDE files
|
||||
.idea/
|
||||
*.iml
|
||||
.atom/
|
||||
completer.hist
|
3
.jshintrc
Normal file
3
.jshintrc
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"esversion": 6
|
||||
}
|
6
AUTHORS
Normal file
6
AUTHORS
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Here is a list of people that have contributed to this project
|
||||
# Please keep this form:
|
||||
#
|
||||
# Name / Organization <email address>
|
||||
|
||||
Marcel Kapfer <marcelmichaelkapfer@yahoo.co.nz>
|
17
CONTRIBUTING.md
Normal file
17
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Contributing
|
||||
|
||||
If you want to contribute have a look at the project board at [phab.mmk2410.org](https://phab.mmk2410.org/project/view/19/) to see what you should do.
|
||||
|
||||
## Workflow
|
||||
|
||||
While there is no stable release this project will follow the feature workflow. As soon as there is a stable release I will switch to the Gitflow workflow.
|
||||
|
||||
If your unfamiliar with these workflows I recommend reading [this article](https://www.atlassian.com/git/tutorials/comparing-workflows/forking-workflow/).
|
||||
|
||||
## Contact
|
||||
|
||||
If you want to ask me some questions, feel free to contact me at (marcelmichaelkapfer@yahoo.co.nz)[mailto:marcelmichaelkapfer@yahoo.co.nz].
|
||||
|
||||
## Honor
|
||||
|
||||
Please add yourself to the AUTHORS file.
|
22
LICENSE.txt
Normal file
22
LICENSE.txt
Normal file
|
@ -0,0 +1,22 @@
|
|||
COPYRIGHT (c) 2016 Marcel Kapfer (mmk2410)
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
7
README.md
Normal file
7
README.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
# Rangitaki Desktop Client
|
||||
|
||||
This is the Rangitaki desktop client made with Dart, Polymer and Electron.
|
||||
|
||||
***It is not fully developed and misses many features. The content of this repository is right now only for development purposes, but not for any productive usage.***
|
||||
|
||||
For contributing see the CONTRIBUTING.md.
|
3
bcli.sh
Executable file
3
bcli.sh
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
rlwrap /bin/bash ./run.sh
|
20
pubspec.yaml
Normal file
20
pubspec.yaml
Normal file
|
@ -0,0 +1,20 @@
|
|||
name: rangitakidesktop
|
||||
version: 0.0.1
|
||||
description: >
|
||||
Desktop app for Rangitaki
|
||||
author: Marcel Kapfer (mmk2410) <marcelmichaelkapfer@yahoo.co.nz>
|
||||
homepage: https://mmk2410.org/rangitaki/rangitaki-desktop/
|
||||
documentation: https://mmk2410.org/rangitaki/rangitaki-lib/docs/
|
||||
|
||||
dependencies:
|
||||
browser: '>=0.10.0 <0.11.0'
|
||||
http: '^0.11.3+7'
|
||||
polymer_elements: ^1.0.0-rc.8
|
||||
polymer: ^1.0.0-rc.2
|
||||
web_components: ^0.12.0
|
||||
test: "^0.12.13+4"
|
||||
|
||||
transformers:
|
||||
- polymer:
|
||||
entry_points:
|
||||
- web/index.html
|
44
run.sh
Normal file
44
run.sh
Normal file
|
@ -0,0 +1,44 @@
|
|||
#!/bin/bash
|
||||
|
||||
while true; do
|
||||
echo -n " (BCLI) > "
|
||||
read -r command
|
||||
|
||||
case $command in
|
||||
build | b ) pub build & ;;
|
||||
run | r )
|
||||
killall -q electron
|
||||
electron build/web/ &
|
||||
;;
|
||||
bar | br )
|
||||
killall -q electron
|
||||
pub build
|
||||
electron build/web/ &
|
||||
;;
|
||||
get | g) pub get ;;
|
||||
close | c) killall -q electron ;;
|
||||
test | t) pub run test;;
|
||||
lint | l)
|
||||
jshint web/main.js
|
||||
jshint web/renderer.js
|
||||
dartanalyzer web/
|
||||
;;
|
||||
exit | quit | q | x | e)
|
||||
exit ;;
|
||||
about ) echo "mmk2410 - Build CLI script - MIT License" ;;
|
||||
help | h | ? )
|
||||
echo """
|
||||
run, r Close running instances and run Electron in background
|
||||
build, b Build app in background
|
||||
bar, br Short for build and run
|
||||
test, t Run tests.
|
||||
close, c Exit running Electron instances
|
||||
exit, quit, q, x, e Exit the script
|
||||
about About text
|
||||
get, g Get updates.
|
||||
help, h, ? Prints this help
|
||||
"""
|
||||
;;
|
||||
* ) echo "Command $command not found." ;;
|
||||
esac
|
||||
done
|
119
web/api.dart
Normal file
119
web/api.dart
Normal file
|
@ -0,0 +1,119 @@
|
|||
import 'dart:async';
|
||||
import 'dart:html';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:polymer_elements/paper_item.dart';
|
||||
|
||||
import 'article-view.dart';
|
||||
|
||||
/**
|
||||
* Easily connects with the Rangitaki API and does also a part of the frontend.
|
||||
*/
|
||||
class RangitakiConnect {
|
||||
|
||||
String baseurl;
|
||||
String _username;
|
||||
String _password;
|
||||
String _auth;
|
||||
|
||||
/**
|
||||
* Initializer for RangitaiConnect.
|
||||
* @value baseurl Root URL of your Rangitaki installation.
|
||||
* @value username Username for authentication.
|
||||
* @value password Password for authentication.
|
||||
*/
|
||||
RangitakiConnect(this.baseurl, this._username, this._password) {
|
||||
_auth = BASE64.encode(UTF8.encode("$_username:$_password"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all blogs from the server and list them in the #list element.
|
||||
*/
|
||||
Future addBlogs() async {
|
||||
var data = await _getBlogs();
|
||||
data = JSON.decode(data);
|
||||
for (String blog in data) {
|
||||
blog = blog.substring(0, blog.length - 3);
|
||||
PaperItem item = new PaperItem();
|
||||
item.text = blog;
|
||||
item.id = blog;
|
||||
querySelector("#main-list").children.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all articles of a blog from the server and list the in the #list
|
||||
* element.
|
||||
* @value blog Blog for which the articles shoul be fetched.
|
||||
*/
|
||||
Future addArticles(String blog) async {
|
||||
var data = await _getArticles(blog);
|
||||
|
||||
data = JSON.decode(data);
|
||||
for (String article in data) {
|
||||
article = article.substring(0, article.length - 3);
|
||||
PaperItem item = new PaperItem();
|
||||
item.text = article;
|
||||
item.id = article;
|
||||
querySelector("#main-list").children.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
Future showArticle(String blog, String post, ArticleView articleView) async {
|
||||
var data = await _getArticle(blog, post);
|
||||
|
||||
print(data);
|
||||
|
||||
data = JSON.decode(data);
|
||||
List tags = data['tags'];
|
||||
String tag = tags.join(", ");
|
||||
|
||||
print("Tags: $tag");
|
||||
|
||||
print("ArticleView: $articleView");
|
||||
|
||||
articleView
|
||||
..title = data['title']
|
||||
..author = data['author']
|
||||
..date = data['date']
|
||||
..tags = tag
|
||||
..text = data['text'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method for fetching blogs from the server.
|
||||
*/
|
||||
Future _getBlogs() async {
|
||||
String _url = "$baseurl/rcc/api/list/";
|
||||
return (await
|
||||
HttpRequest.request(
|
||||
_url, withCredentials: true,
|
||||
requestHeaders: {'authorization' : 'Basic $_auth'}
|
||||
)).responseText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method for fetching articles of blog from the server.
|
||||
*/
|
||||
Future _getArticles(String blog) async {
|
||||
String _url = "$baseurl/rcc/api/list/?blog=$blog";
|
||||
|
||||
return (await
|
||||
HttpRequest.request(
|
||||
_url, withCredentials: true,
|
||||
requestHeaders: {'authorization' : 'Basic $_auth'}
|
||||
)).responseText;
|
||||
}
|
||||
|
||||
Future _getArticle(blog, post) async {
|
||||
print("Blog: $blog");
|
||||
print("Post: $post");
|
||||
String _url = "$baseurl/rcc/api/post/?blog=$blog&post=$post.md";
|
||||
print("URL: $_url");
|
||||
return (await
|
||||
HttpRequest.request(_url, withCredentials: true,
|
||||
requestHeaders: {'authorization' : 'Basic $_auth'}
|
||||
)).responseText;
|
||||
}
|
||||
|
||||
}
|
18
web/article-view.dart
Normal file
18
web/article-view.dart
Normal file
|
@ -0,0 +1,18 @@
|
|||
@HtmlImport('article_view.html')
|
||||
library mmk2410_rangitaki_app.article_view;
|
||||
|
||||
import 'package:polymer/polymer.dart';
|
||||
import 'package:web_components/web_components.dart' show HtmlImport;
|
||||
|
||||
@PolymerRegister('article-view')
|
||||
class ArticleView extends PolymerElement {
|
||||
|
||||
ArticleView.created() : super.created();
|
||||
|
||||
@property
|
||||
String title;
|
||||
String author;
|
||||
String date;
|
||||
String text;
|
||||
String tags;
|
||||
}
|
16
web/article_view.html
Normal file
16
web/article_view.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
<dom-module id="article-view">
|
||||
<style>
|
||||
/* css rules */
|
||||
</style>
|
||||
<template>
|
||||
<paper-material elevation="1">
|
||||
<paper-input label="Title" value="{{title}}"></paper-input>
|
||||
<paper-input label="Date" value="{{date}}"></paper-input>
|
||||
<paper-input label="Author" value="{{author}}"></paper-input>
|
||||
<paper-input label="Tags" value="{{tags}}"></paper-input>
|
||||
<paper-autogrow-textarea id="a1">
|
||||
<textarea id="t1" value="{{text}}"></textarea>
|
||||
<paper-autogrow-textarea>
|
||||
</paper-material>
|
||||
</template>
|
||||
</dom-module>
|
61
web/index.dart
Normal file
61
web/index.dart
Normal file
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* @author Marcel Kapfer (mmk2410) <marcelmichaelkapfer@yahoo.co.nz>
|
||||
* Library for easily working with the Rangitaki API in your browswer.
|
||||
*/
|
||||
library mmk2410_rangitaki_app.index;
|
||||
|
||||
import 'dart:html';
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:polymer/polymer.dart';
|
||||
|
||||
import 'api.dart';
|
||||
import 'article-view.dart';
|
||||
|
||||
export 'article-view.dart';
|
||||
export 'package:polymer/init.dart';
|
||||
|
||||
final String username = "";
|
||||
final String pwd = "";
|
||||
final String baseurl = "";
|
||||
|
||||
RangitakiConnect rcc;
|
||||
Element itemList;
|
||||
ArticleView articleView;
|
||||
String currentBlog;
|
||||
|
||||
main() async {
|
||||
await initPolymer();
|
||||
|
||||
print("Starting...");
|
||||
|
||||
rcc = new RangitakiConnect(baseurl, username, pwd);
|
||||
|
||||
await rcc.addBlogs();
|
||||
|
||||
itemList = querySelector("#main-list");
|
||||
|
||||
for (Element item in itemList.children) {
|
||||
item.onClick.listen(blogSelected);
|
||||
}
|
||||
|
||||
articleView = querySelector("articlev-iew");
|
||||
}
|
||||
|
||||
Future blogSelected(Event e) async {
|
||||
Element element = e.target;
|
||||
itemList.children.clear();
|
||||
currentBlog = element.id;
|
||||
await rcc.addArticles(element.id);
|
||||
|
||||
for (Element item in itemList.children) {
|
||||
item.onClick.listen(articleSelected);
|
||||
}
|
||||
}
|
||||
|
||||
Future articleSelected(Event e) async {
|
||||
Element element = e.target;
|
||||
await rcc.showArticle(currentBlog, element.id, articleView);
|
||||
itemList.hidden = true;
|
||||
articleView.hidden = false;
|
||||
}
|
57
web/index.html
Normal file
57
web/index.html
Normal file
|
@ -0,0 +1,57 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Rangitaki</title>
|
||||
<!--Polymer-->
|
||||
<link rel="import" href="packages/polymer_elements/paper_header_panel.html">
|
||||
<link rel="import" href="packages/polymer_elements/paper_drawer_panel.html">
|
||||
<link rel="import" href="packages/polymer_elements/paper_toolbar.html">
|
||||
<link rel="import"
|
||||
href="packages/polymer_elements/paper_icon_button.html">
|
||||
<link rel="import"
|
||||
href="packages/polymer_elements/paper_material.html">
|
||||
<link rel="import" href="packages/polymer_elements/paper_menu.html">
|
||||
<link rel="import" href="packages/polymer_elements/paper_item.html">
|
||||
<link rel="import" href="packages/polymer_elements/iron_icons.html">
|
||||
<link rel="import" href="packages/polymer_elements/paper_textarea.html"
|
||||
<link rel="import" href="article_view.html">
|
||||
</head>
|
||||
<body unresolved class="fullbleed layout vertical">
|
||||
<paper-drawer-panel>
|
||||
|
||||
<paper-header-panel drawer>
|
||||
<paper-toolbar class="medium-tall">
|
||||
<span>Menu</span>
|
||||
</paper-toolbar>
|
||||
|
||||
<paper-menu selected="0">
|
||||
<paper-item>Blogs</paper-item>
|
||||
<paper-item>Articles</paper-item>
|
||||
<paper-item>Media</paper-item>
|
||||
<paper-item>Settings</paper-item>
|
||||
</paper-menu>
|
||||
</paper-header-panel>
|
||||
|
||||
<paper-header-panel main>
|
||||
<paper-toolbar>
|
||||
<paper-icon-button icon="menu" paper-drawer-toggle></paper-icon-button>
|
||||
<div class="appname title">Rangitaki</div>
|
||||
</paper-toolbar>
|
||||
|
||||
<paper-material elevation="1">
|
||||
<div role="listbox" id="main-list"></div>
|
||||
</paper-material>
|
||||
|
||||
<article-view hidden></article-view>
|
||||
|
||||
</paper-header-panel>
|
||||
</paper-drawer-panel>
|
||||
|
||||
<script type="application/dart" src="index.dart"></script>
|
||||
|
||||
<!-- support for non-Dart browsers -->
|
||||
<link rel="import" href="style.html" />
|
||||
<script src="packages/browser/dart.js"></script>
|
||||
</body>
|
||||
</html>
|
53
web/main.js
Normal file
53
web/main.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
const electron = require('electron');
|
||||
// Module to control application life.
|
||||
const app = electron.app;
|
||||
// Module to create native browser window.
|
||||
const BrowserWindow = electron.BrowserWindow;
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow;
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({width: 1000, height: 800});
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadURL(`file://${__dirname}/index.html`);
|
||||
|
||||
// Open the DevTools.
|
||||
mainWindow.webContents.openDevTools();
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null;
|
||||
});
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.on('ready', createWindow);
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
app.on('activate', function () {
|
||||
// On OS X it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow();
|
||||
}
|
||||
});
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
23
web/package.json
Normal file
23
web/package.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "rangitaki-desktop",
|
||||
"version": "0.0.1",
|
||||
"description": "Rangtaki desktop app made with Dart, Polymer and Electron",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"start": "electron main.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://gitlab.com/mmk2410/rangitaki-desktop.git"
|
||||
},
|
||||
"keywords": [
|
||||
"Rangitaki",
|
||||
"desktop"
|
||||
],
|
||||
"author": "Marcel Kapfer (mmk2410)",
|
||||
"license": "MIT",
|
||||
"homepage": "https://gitlab.com/mmk2410/rangitaki-desktop",
|
||||
"devDependencies": {
|
||||
"electron-prebuilt": "^1.0.1"
|
||||
}
|
||||
}
|
3
web/renderer.js
Normal file
3
web/renderer.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
// This file is required by the index.html file and will
|
||||
// be executed in the renderer process for that window.
|
||||
// All of the Node.js APIs are available in this process.
|
27
web/style.html
Normal file
27
web/style.html
Normal file
|
@ -0,0 +1,27 @@
|
|||
<style is="custom-style">
|
||||
:root {
|
||||
--primary-text-color: var(--paper-grey-900);
|
||||
--primary-background-color: #ffffff;
|
||||
--secondary-text-color: #737373;
|
||||
--disabled-text-color: #9b9b9b;
|
||||
--divider-color: #dbdbdb;
|
||||
--primary-color: #ff4415;
|
||||
--light-primary-color: #ff4415;
|
||||
--dark-primary-color: #ff4415;
|
||||
--accent-color: var(--paper-pink-a200);
|
||||
--light-accent-color: var(--paper-pink-a100);
|
||||
--dark-accent-color: var(--paper-pink-a400);
|
||||
/* Components */
|
||||
/* paper-drawer-panel */
|
||||
--drawer-menu-color: #ffffff;
|
||||
--drawer-border-color: 1px solid #ccc;
|
||||
--drawer-toolbar-border-color: 1px solid rgba(0, 0, 0, 0.22);
|
||||
/* paper-menu */
|
||||
--paper-menu-background-color: #fff;
|
||||
--menu-link-color: #111111;
|
||||
}
|
||||
|
||||
paper-toolbar {
|
||||
background-color: var(--primary-color);
|
||||
}
|
||||
</style>
|
Reference in a new issue