├── mOrgAnd
├── .gitignore
├── src
│ ├── main
│ │ ├── ic_launcher-web.png
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── colors.xml
│ │ │ │ ├── styles.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── arrays.xml
│ │ │ │ ├── strings.xml
│ │ │ │ └── strings_settings.xml
│ │ │ ├── drawable-hdpi
│ │ │ │ ├── file.png
│ │ │ │ ├── folder.png
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── outline_item_selected.xml
│ │ │ ├── drawable-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── drawable-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── drawable-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── xml
│ │ │ │ ├── pref_general.xml
│ │ │ │ ├── pref_headers.xml
│ │ │ │ ├── pref_interface.xml
│ │ │ │ ├── pref_data_sync.xml
│ │ │ │ ├── pref_calendar.xml
│ │ │ │ └── pref_git.xml
│ │ │ ├── layout
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── edit_text_fragment.xml
│ │ │ │ ├── fragment_main.xml
│ │ │ │ ├── file_dialog_row.xml
│ │ │ │ ├── outline_item.xml
│ │ │ │ ├── edit_heading_fragment.xml
│ │ │ │ ├── edit_date_fragment.xml
│ │ │ │ ├── file_dialog_main.xml
│ │ │ │ └── fragment_outline.xml
│ │ │ └── menu
│ │ │ │ ├── outline.xml
│ │ │ │ └── main.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ ├── hdweiss
│ │ │ │ └── morgand
│ │ │ │ │ ├── events
│ │ │ │ │ ├── DataUpdatedEvent.java
│ │ │ │ │ └── SyncEvent.java
│ │ │ │ │ ├── gui
│ │ │ │ │ ├── edit
│ │ │ │ │ │ ├── controller
│ │ │ │ │ │ │ ├── EditController.java
│ │ │ │ │ │ │ ├── BaseEditController.java
│ │ │ │ │ │ │ └── AddController.java
│ │ │ │ │ │ ├── EditTextFragment.java
│ │ │ │ │ │ ├── EditHeadingFragment.java
│ │ │ │ │ │ ├── BaseEditFragment.java
│ │ │ │ │ │ └── EditDateFragment.java
│ │ │ │ │ ├── theme
│ │ │ │ │ │ ├── MonoTheme.java
│ │ │ │ │ │ ├── WhiteTheme.java
│ │ │ │ │ │ └── DefaultTheme.java
│ │ │ │ │ ├── AgendaFragment.java
│ │ │ │ │ ├── MainPagerAdapter.java
│ │ │ │ │ ├── outline
│ │ │ │ │ │ ├── OutlineActionMode.java
│ │ │ │ │ │ ├── OutlineFragment.java
│ │ │ │ │ │ ├── OutlineListView.java
│ │ │ │ │ │ └── OutlineAdapter.java
│ │ │ │ │ ├── SynchronizerNotification.java
│ │ │ │ │ └── MainActivity.java
│ │ │ │ │ ├── utils
│ │ │ │ │ ├── MultiMap.java
│ │ │ │ │ ├── FileUtils.java
│ │ │ │ │ ├── Utils.java
│ │ │ │ │ └── SafeAsyncTask.java
│ │ │ │ │ ├── data
│ │ │ │ │ ├── dao
│ │ │ │ │ │ ├── OrgAgenda.java
│ │ │ │ │ │ ├── OrgFile.java
│ │ │ │ │ │ ├── DatabaseHelper.java
│ │ │ │ │ │ └── OrgNodeRepository.java
│ │ │ │ │ ├── CalendarUtils.java
│ │ │ │ │ ├── OrgNodeUtils.java
│ │ │ │ │ ├── OrgCalendarEntry.java
│ │ │ │ │ └── OrgNodeTimeDate.java
│ │ │ │ │ ├── settings
│ │ │ │ │ ├── LocalPathSettingsActivity.java
│ │ │ │ │ ├── PreferenceUtils.java
│ │ │ │ │ ├── KeySettingActivity.java
│ │ │ │ │ └── SettingsActivity.java
│ │ │ │ │ ├── synchronizer
│ │ │ │ │ ├── calendar
│ │ │ │ │ │ ├── CalendarEntry.java
│ │ │ │ │ │ ├── CalendarEntriesParser.java
│ │ │ │ │ │ └── SyncCalendarTask.java
│ │ │ │ │ ├── git
│ │ │ │ │ │ ├── JGitConfigSessionFactory.java
│ │ │ │ │ │ ├── JGitCredentialsProvider.java
│ │ │ │ │ │ └── SyncGitTask.java
│ │ │ │ │ ├── parser
│ │ │ │ │ │ ├── SyncParserTask.java
│ │ │ │ │ │ └── OrgRepository.java
│ │ │ │ │ ├── writer
│ │ │ │ │ │ ├── SyncWriterTask.java
│ │ │ │ │ │ └── OrgFileWriter.java
│ │ │ │ │ └── SyncService.java
│ │ │ │ │ └── Application.java
│ │ │ │ └── lamerman
│ │ │ │ └── SelectionMode.java
│ │ └── AndroidManifest.xml
│ ├── debug
│ │ └── res
│ │ │ └── values
│ │ │ └── strings.xml
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── hdweiss
│ │ └── morgand
│ │ └── test
│ │ ├── OrgNodeStubbed.java
│ │ ├── TestUtils.java
│ │ ├── JGitWrapperTests.java
│ │ ├── OrgFileWriterTests.java
│ │ └── OrgFileTestScenario.java
├── proguard-rules.txt
└── build.gradle
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── README.org
├── .gitignore
├── gradle.properties
├── gradlew.bat
└── gradlew
/mOrgAnd/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include 'mOrgAnd'
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hdweiss/mOrgAnd/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/mOrgAnd/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hdweiss/mOrgAnd/HEAD/mOrgAnd/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #66000000
4 |
5 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/drawable-hdpi/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hdweiss/mOrgAnd/HEAD/mOrgAnd/src/main/res/drawable-hdpi/file.png
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/drawable-hdpi/folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hdweiss/mOrgAnd/HEAD/mOrgAnd/src/main/res/drawable-hdpi/folder.png
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hdweiss/mOrgAnd/HEAD/mOrgAnd/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hdweiss/mOrgAnd/HEAD/mOrgAnd/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hdweiss/mOrgAnd/HEAD/mOrgAnd/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/events/DataUpdatedEvent.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.events;
2 |
3 | public class DataUpdatedEvent {
4 | }
5 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hdweiss/mOrgAnd/HEAD/mOrgAnd/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/mOrgAnd/src/debug/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | mOrgAnd debug
4 |
5 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/lamerman/SelectionMode.java:
--------------------------------------------------------------------------------
1 | package com.lamerman;
2 |
3 | public class SelectionMode {
4 | public static final int MODE_CREATE = 0;
5 |
6 | public static final int MODE_OPEN = 1;
7 | }
8 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/xml/pref_general.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Aug 13 11:53:21 CEST 2014
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
7 |
--------------------------------------------------------------------------------
/README.org:
--------------------------------------------------------------------------------
1 | All documentation for this project is located at [[https://github.com/hdweiss/mOrgAnd/wiki]]
2 |
3 | * Building
4 | Follow the instructions at [[https://github.com/hdweiss/mOrgAnd/wiki/Starting%20Development][Starting Development]]
5 |
6 | * Notes
7 | - This project uses https://code.google.com/p/android-file-dialog/
8 |
9 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 | 70dp
7 | 70dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/drawable-hdpi/outline_item_selected.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/gui/edit/controller/EditController.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.gui.edit.controller;
2 |
3 | import com.hdweiss.morgand.data.dao.OrgNode;
4 | import com.hdweiss.morgand.data.dao.OrgNodeRepository;
5 |
6 | public class EditController extends BaseEditController {
7 |
8 | public EditController(OrgNode node) {
9 | mode = EditMode.Edit;
10 | this.node = node;
11 | }
12 |
13 | @Override
14 | public void save(OrgNode node) {
15 | OrgNodeRepository.update(node);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/gui/edit/controller/BaseEditController.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.gui.edit.controller;
2 |
3 | import com.hdweiss.morgand.data.dao.OrgNode;
4 |
5 | public abstract class BaseEditController {
6 | public enum EditMode {Add, Edit}
7 |
8 | protected EditMode mode;
9 | protected OrgNode node;
10 |
11 | public abstract void save(OrgNode node);
12 |
13 | public EditMode getMode() {
14 | return this.mode;
15 | }
16 |
17 | public OrgNode getNode() {
18 | return this.node;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/menu/outline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/layout/edit_text_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
16 |
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Android
2 | *.apk
3 | gen/
4 | build/
5 | local.properties
6 | .gradle/
7 | # Old Android
8 | bin/
9 |
10 | # Idea
11 | # According to this
12 | # see http://devnet.jetbrains.com/docs/DOC-1186
13 | # I shouldn't ignore most of this stuff.. but looking at the content
14 | # I see environment stuffs in it.
15 | # And I don't see any particular advantage in having the idea stuff
16 | # in my repo
17 | # it would be helpful for code templates but it's simply not worth
18 | # the effort currently
19 | *.iws
20 | *.iml
21 | *.ipr
22 | .idea
23 | out
24 |
25 | # Eclipse
26 | .project
27 | .classpath
28 | .settings
29 |
30 | # Mac
31 | .DS_Store
32 |
33 | # Generic
34 | *~
35 | .swp
36 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/events/SyncEvent.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.events;
2 |
3 | public class SyncEvent {
4 | public enum State {
5 | Done, Intermediate, Progress, SecondaryProgress
6 | }
7 |
8 | public State state;
9 | public int progress = 0;
10 | public String filename = "";
11 |
12 | public SyncEvent(State state) {
13 | this(state, 0);
14 | }
15 |
16 | public SyncEvent(State state, int progress) {
17 | this(state, progress, "");
18 | }
19 |
20 | public SyncEvent(State state, int progress, String filename) {
21 | this.state = state;
22 | this.progress = progress;
23 | this.filename = filename;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/mOrgAnd/proguard-rules.txt:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/hdw/Applications/android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the ProGuard
5 | # include property in project.properties.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/gui/edit/controller/AddController.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.gui.edit.controller;
2 |
3 | import com.hdweiss.morgand.Application;
4 | import com.hdweiss.morgand.data.dao.OrgNode;
5 | import com.hdweiss.morgand.data.dao.OrgNodeRepository;
6 | import com.hdweiss.morgand.events.DataUpdatedEvent;
7 |
8 | public class AddController extends BaseEditController {
9 |
10 | public AddController(OrgNode parent, OrgNode.Type type) {
11 | mode = EditController.EditMode.Add;
12 | this.node = parent.addChild(type);
13 | }
14 |
15 | @Override
16 | public void save(OrgNode node) {
17 | OrgNodeRepository.create(node);
18 | Application.getBus().post(new DataUpdatedEvent());
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/layout/fragment_main.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
20 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Settings specified in this file will override any Gradle settings
5 | # configured through the IDE.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/mOrgAnd/src/androidTest/java/com/hdweiss/morgand/test/OrgNodeStubbed.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.test;
2 |
3 | import com.hdweiss.morgand.data.dao.OrgNode;
4 |
5 | public class OrgNodeStubbed extends OrgNode {
6 |
7 | public int nextNodeLineNumber;
8 | public int siblingLineNumber;
9 |
10 | public OrgNodeStubbed(int lineNumber) {
11 | this.lineNumber = lineNumber;
12 | }
13 |
14 | public OrgNodeStubbed(int lineNumber, int nextNodeLineNumber, int siblingLineNumber) {
15 | super();
16 | this.lineNumber = lineNumber;
17 | this.nextNodeLineNumber = nextNodeLineNumber;
18 | this.siblingLineNumber = siblingLineNumber;
19 | }
20 |
21 | @Override
22 | public int getNextNodeLineNumber() {
23 | return nextNodeLineNumber;
24 | }
25 |
26 | @Override
27 | public int getSiblingLineNumber() {
28 | return siblingLineNumber;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/layout/file_dialog_row.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
9 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - 100000
5 | - 300000
6 | - 600000
7 | - 900000
8 | - 1800000
9 | - 2700000
10 | - 3600000
11 | - 10800000
12 | - 21600000
13 | - 43200000
14 |
15 |
16 |
17 | - theirs
18 | - ours
19 |
20 |
21 |
22 | - Git
23 | - Update files
24 |
25 |
26 |
27 | - git
28 | - none
29 |
30 |
31 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/xml/pref_headers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
10 |
11 |
15 |
16 |
20 |
21 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/xml/pref_interface.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
18 |
19 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/gui/theme/MonoTheme.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.gui.theme;
2 |
3 | import android.graphics.Color;
4 |
5 | public class MonoTheme extends DefaultTheme {
6 |
7 | public MonoTheme() {
8 | super();
9 | c0Black = Color.rgb(0xff, 0xff, 0xff);
10 | c1Red = Color.rgb(0xd0, 0x00, 0x00);
11 | c2Green = Color.rgb(0x00, 0x00, 0x00);
12 | c3Yellow = Color.rgb(0x00, 0x00, 0x00);
13 | c4Blue = Color.rgb(0x00, 0x00, 0x00);
14 | c5Purple = Color.rgb(0x00, 0x00, 0x00);
15 | c6Cyan = Color.rgb(0x00, 0x00, 0x00);
16 | c7White = Color.rgb(0x00, 0x00, 0x00);
17 |
18 | c9LRed = Color.rgb(0x00, 0x00, 0x00);
19 | caLGreen = Color.rgb(0x77, 0xff, 0x77);
20 | cbLYellow = Color.rgb(0x00, 0x00, 0x00);
21 | ccLBlue = Color.rgb(0x00, 0x00, 0x00);
22 | cdLPurple = Color.rgb(0x00, 0x00, 0x00);
23 | ceLCyan = Color.rgb(0x00, 0x00, 0x00);
24 | cfLWhite = Color.rgb(0x00, 0x00, 0x00);
25 |
26 | levelColors = new int[] { cfLWhite };
27 |
28 | defaultFontColor = "black";
29 | defaultBackground = Color.rgb(0xff, 0xff, 0xff);
30 | defaultForeground = Color.rgb(0x10, 0x10, 0x10);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/gui/theme/WhiteTheme.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.gui.theme;
2 |
3 | import android.graphics.Color;
4 |
5 | public class WhiteTheme extends DefaultTheme {
6 |
7 | public WhiteTheme() {
8 | super();
9 | c0Black = Color.rgb(0xff, 0xff, 0xff);
10 | c1Red = Color.rgb(0x20, 0x00, 0x00);
11 | c2Green = Color.rgb(0x00, 0x20, 0x00);
12 | c3Yellow = Color.rgb(0x20, 0x20, 0x00);
13 | c4Blue = Color.rgb(0x0, 0x0, 0x20);
14 | c5Purple = Color.rgb(0x20, 0x00, 0x20);
15 | c6Cyan = Color.rgb(0x00, 0x20, 0x20);
16 | c7White = Color.rgb(0x10, 0x10, 0x10);
17 |
18 | c9LRed = Color.rgb(0xa0, 0x0, 0x0);
19 | caLGreen = Color.rgb(0x20, 0xa0, 0x20);
20 | cbLYellow = Color.rgb(0x80, 0x80, 0x00);
21 | ccLBlue = Color.rgb(0x00, 0x00, 0x80);
22 | cdLPurple = Color.rgb(0x80, 0x00, 0x80);
23 | ceLCyan = Color.rgb(0x00, 0x80, 0x80);
24 | cfLWhite = Color.rgb(0x00, 0x00, 0x00);
25 |
26 | levelColors = new int[] { ccLBlue, c3Yellow, ceLCyan, c2Green,
27 | c5Purple, ccLBlue, c2Green, ccLBlue, c3Yellow, ceLCyan };
28 |
29 | defaultFontColor = "black";
30 | defaultBackground = Color.rgb(0xff, 0xff, 0xff);
31 | defaultForeground = Color.rgb(0x10, 0x10, 0x10);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/utils/MultiMap.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.utils;
2 |
3 | import java.util.ArrayList;
4 | import java.util.HashMap;
5 | import java.util.Set;
6 |
7 | public class MultiMap {
8 |
9 | private HashMap> entryMap = new HashMap>();
10 |
11 | public void put(Long key, T value) {
12 | ArrayList valueList = entryMap.get(key);
13 |
14 | if(valueList == null) {
15 | valueList = new ArrayList();
16 | entryMap.put(key, valueList);
17 | }
18 |
19 | valueList.add(value);
20 | }
21 |
22 | public ArrayList get(Long key) {
23 | return entryMap.get(key);
24 | }
25 |
26 | public void remove(long key, T value) {
27 | ArrayList valueList = entryMap.get(key);
28 |
29 | if(valueList != null) {
30 | valueList.remove(value);
31 | }
32 | }
33 |
34 | public Set keySet() {
35 | return entryMap.keySet();
36 | }
37 |
38 | public T findValue(long key, Object object) throws IllegalArgumentException {
39 | ArrayList matches = entryMap.get(key);
40 |
41 | if (matches == null)
42 | return null;
43 |
44 | for (T match : matches) {
45 | if (match.equals(object))
46 | return match;
47 | }
48 |
49 | return null;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/mOrgAnd/src/androidTest/java/com/hdweiss/morgand/test/TestUtils.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.test;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.BufferedWriter;
5 | import java.io.File;
6 | import java.io.FileNotFoundException;
7 | import java.io.FileReader;
8 | import java.io.FileWriter;
9 | import java.io.IOException;
10 |
11 | public class TestUtils {
12 |
13 | public static void writeStringAsFile(final String fileContents, String fileName) {
14 | try {
15 | BufferedWriter writer = new BufferedWriter(new FileWriter(fileName));
16 | writer.write(fileContents);
17 | writer.close();
18 | } catch (IOException e) {
19 | }
20 | }
21 |
22 | public static String readFileAsString(String fileName) {
23 | StringBuilder stringBuilder = new StringBuilder();
24 | String line;
25 | BufferedReader in = null;
26 |
27 | try {
28 | in = new BufferedReader(new FileReader(new File(fileName)));
29 | while ((line = in.readLine()) != null) stringBuilder.append(line).append("\n");
30 |
31 | } catch (FileNotFoundException e) {
32 | } catch (IOException e) {
33 | }
34 |
35 | return stringBuilder.toString();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/data/dao/OrgAgenda.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.data.dao;
2 |
3 | import com.j256.ormlite.field.DatabaseField;
4 | import com.j256.ormlite.table.DatabaseTable;
5 |
6 | import java.sql.SQLException;
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | @DatabaseTable(tableName = "OrgAgendas")
11 | public class OrgAgenda {
12 |
13 | @DatabaseField(generatedId = true)
14 | public int Id;
15 |
16 | public static final String TITLE_FIELD_NAME = "title";
17 | @DatabaseField(columnName = TITLE_FIELD_NAME)
18 | public String title;
19 |
20 | @DatabaseField
21 | public String files;
22 |
23 | @DatabaseField
24 | public String tags;
25 |
26 | @DatabaseField
27 | public String priorities;
28 |
29 | @DatabaseField
30 | public String todos;
31 |
32 | @DatabaseField
33 | public boolean includeHabits;
34 |
35 | @DatabaseField
36 | public boolean includeInactiveTodos;
37 |
38 |
39 | public List getNodes() {
40 | try {
41 | return OrgNodeRepository.queryBuilder().query();
42 | } catch (SQLException e) {
43 | e.printStackTrace();
44 | return new ArrayList();
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/utils/FileUtils.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.utils;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.File;
5 | import java.io.FileReader;
6 | import java.io.IOException;
7 | import java.util.ArrayList;
8 |
9 | public class FileUtils {
10 |
11 | public static boolean deleteDirectory(File path) {
12 | if( path.exists() ) {
13 | File[] files = path.listFiles();
14 | if (files == null) {
15 | return true;
16 | }
17 | for(int i=0; i fileToArrayList(String fileName) throws IOException {
31 | String line;
32 | BufferedReader in = new BufferedReader(new FileReader(new File(fileName)));
33 | ArrayList fileContent = new ArrayList();
34 | while ((line = in.readLine()) != null)
35 | fileContent.add(line);
36 |
37 | return fileContent;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/layout/outline_item.xml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
19 |
20 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/mOrgAnd/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'android'
2 |
3 | def getVersionName = { ->
4 | def stdout = new ByteArrayOutputStream()
5 | exec {
6 | commandLine 'git', 'describe', '--tags'
7 | standardOutput = stdout
8 | }
9 | return stdout.toString().trim()
10 | }
11 |
12 | android {
13 | compileSdkVersion 20
14 | buildToolsVersion '20'
15 |
16 | defaultConfig {
17 | minSdkVersion 14
18 | targetSdkVersion 16
19 | versionCode 1
20 | versionName getVersionName() + "-alpha"
21 | }
22 | buildTypes {
23 | debug {
24 | applicationIdSuffix ".debug"
25 | versionNameSuffix "debug"
26 | }
27 | release {
28 | runProguard false
29 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
30 | // applicationVariants.all { variant ->
31 | // def file = variant.outputFile
32 | // variant.outputFile = new File(file.parent, file.name.replace(".apk", "-" + defaultConfig.versionName + ".apk"))
33 | // }
34 | }
35 | }
36 | }
37 |
38 | dependencies {
39 | compile 'com.android.support:support-v4:20.0.0'
40 | compile 'com.j256.ormlite:ormlite-android:4.48'
41 | compile 'org.eclipse.jgit:org.eclipse.jgit:3.4.1.201406201815-r'
42 | compile 'com.squareup:otto:1.3.5'
43 | compile fileTree(dir: 'libs', include: ['*.jar'])
44 | }
45 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/settings/LocalPathSettingsActivity.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.settings;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.content.SharedPreferences;
6 | import android.os.Bundle;
7 | import android.preference.PreferenceManager;
8 |
9 | import com.lamerman.FileDialog;
10 | import com.lamerman.SelectionMode;
11 |
12 | public class LocalPathSettingsActivity extends Activity {
13 |
14 | @Override
15 | protected void onCreate(Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 |
18 | Intent intent = new Intent(getBaseContext(), FileDialog.class);
19 | intent.putExtra(FileDialog.START_PATH, "/sdcard");
20 | intent.putExtra(FileDialog.CAN_SELECT_DIR, true);
21 | intent.putExtra(FileDialog.SELECTION_MODE, SelectionMode.MODE_CREATE);
22 |
23 | startActivityForResult(intent, 0);
24 | }
25 |
26 | @Override
27 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
28 | if (resultCode == Activity.RESULT_OK) {
29 | String filePath = data.getStringExtra(FileDialog.RESULT_PATH);
30 |
31 | SharedPreferences.Editor edit = PreferenceManager.getDefaultSharedPreferences(this).edit();
32 | edit.putString("git_local_path", filePath);
33 | edit.commit();
34 |
35 | } else if (resultCode == Activity.RESULT_CANCELED) {
36 | }
37 | finish();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/gui/edit/EditTextFragment.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.gui.edit;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.EditText;
8 |
9 | import com.hdweiss.morgand.R;
10 | import com.hdweiss.morgand.data.dao.OrgNode;
11 |
12 | public class EditTextFragment extends BaseEditFragment {
13 |
14 | private EditText editText;
15 |
16 | @Override
17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
18 | View view = inflater.inflate(R.layout.edit_text_fragment, container, false);
19 |
20 | editText = (EditText) view.findViewById(R.id.editText);
21 |
22 | return view;
23 | }
24 |
25 | @Override
26 | public void onViewCreated(View view, Bundle savedInstanceState) {
27 | super.onViewCreated(view, savedInstanceState);
28 |
29 | if (controller != null) {
30 | String text = controller.getNode().title;
31 | populateView(text);
32 | }
33 | }
34 |
35 | private void populateView(String text) {
36 | if (text != null)
37 | editText.setText(text);
38 |
39 | getDialog().setTitle(R.string.action_edit);
40 | }
41 |
42 | @Override
43 | public OrgNode getEditedNode() {
44 | OrgNode editNode = controller.getNode();
45 | editNode.title = editText.getText().toString();
46 | return editNode;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/synchronizer/calendar/CalendarEntry.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.synchronizer.calendar;
2 |
3 | import android.text.TextUtils;
4 |
5 | import com.hdweiss.morgand.data.CalendarUtils;
6 | import com.hdweiss.morgand.data.OrgCalendarEntry;
7 | import com.hdweiss.morgand.data.dao.OrgNode;
8 |
9 | public class CalendarEntry {
10 | public String title = "";
11 | public String description = "";
12 | public String location = "";
13 | public long id = -1;
14 | public long dtStart = 0;
15 | public long dtEnd = 0;
16 | public int allDay = 0;
17 |
18 | @Override
19 | public boolean equals(Object o) {
20 | if (o instanceof OrgCalendarEntry) {
21 | OrgCalendarEntry entry = (OrgCalendarEntry) o;
22 | return this.dtStart == entry.beginTime
23 | && this.dtEnd == entry.endTime
24 | && entry.getCalendarTitle().startsWith(this.title);
25 | }
26 |
27 | return super.equals(o);
28 | }
29 |
30 | public OrgNode writeToOrgNodes(OrgNode parentNode) {
31 | OrgNode headingNode = parentNode.addChild(OrgNode.Type.Headline, this.title);
32 |
33 | boolean isAllDay = allDay > 0;
34 | String date = CalendarUtils.formatDate(this.dtStart, this.dtEnd, isAllDay);
35 |
36 | headingNode.addChild(OrgNode.Type.Date, date);
37 | headingNode.addChild(OrgNode.Type.Body, this.description);
38 |
39 | if (TextUtils.isEmpty(this.location) == false)
40 | headingNode.addChild(OrgNode.Type.Drawer, ":LOCATION: " + this.location);
41 |
42 | return headingNode;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/Application.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand;
2 |
3 | import android.content.SharedPreferences;
4 | import android.preference.PreferenceManager;
5 |
6 | import com.hdweiss.morgand.events.SyncEvent;
7 | import com.hdweiss.morgand.synchronizer.SyncService;
8 | import com.squareup.otto.Bus;
9 | import com.squareup.otto.Produce;
10 | import com.squareup.otto.Subscribe;
11 |
12 | public class Application extends android.app.Application {
13 |
14 | private static Application instace;
15 | public static Application getInstace() {
16 | return instace;
17 | }
18 |
19 | private static Bus bus;
20 | public static Bus getBus() {
21 | if (bus == null)
22 | bus = new Bus();
23 | return bus;
24 | }
25 |
26 | private SyncEvent syncEvent = new SyncEvent(SyncEvent.State.Done);
27 |
28 | @Produce public SyncEvent produceSyncEvent() {
29 | return this.syncEvent;
30 | }
31 |
32 | @Subscribe public void syncEvent(SyncEvent event) {
33 | this.syncEvent = event;
34 | }
35 |
36 | public static SharedPreferences getPreferences() {
37 | return PreferenceManager.getDefaultSharedPreferences(instace);
38 | }
39 |
40 |
41 | @Override
42 | public void onCreate() {
43 | super.onCreate();
44 | instace = this;
45 | SyncService.startAlarm(this);
46 | getBus().register(this);
47 | }
48 |
49 | @Override
50 | public void onTerminate() {
51 | super.onTerminate();
52 | instace = null;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/layout/edit_heading_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
16 |
17 |
22 |
23 |
29 |
30 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/gui/AgendaFragment.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.gui;
2 |
3 | import android.view.Menu;
4 | import android.view.MenuInflater;
5 |
6 | import com.hdweiss.morgand.data.dao.OrgNode;
7 | import com.hdweiss.morgand.data.dao.OrgNodeRepository;
8 | import com.hdweiss.morgand.events.DataUpdatedEvent;
9 | import com.hdweiss.morgand.gui.outline.OutlineAdapter;
10 | import com.hdweiss.morgand.gui.outline.OutlineFragment;
11 | import com.squareup.otto.Subscribe;
12 |
13 | import java.sql.SQLException;
14 | import java.util.List;
15 |
16 | public class AgendaFragment extends OutlineFragment {
17 |
18 | @Override
19 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
20 | // Empty options menu for now.
21 | }
22 |
23 | @Override
24 | public void onPrepareOptionsMenu(Menu menu) {
25 | // Empty options menu for now.
26 | }
27 |
28 | @Subscribe
29 | public void refreshView(DataUpdatedEvent event) {
30 | refreshView();
31 | }
32 |
33 | @Override
34 | protected void refreshView() {
35 | try {
36 | String query = getArguments().getString("query", "TODO%");
37 | List orgNodes = OrgNodeRepository.queryBuilder().where().like(OrgNode.TITLE_FIELD_NAME, query)
38 | .and().not().like(OrgNode.FILE_FIELD_NAME, "%mOrgAnd.wiki/Development/Todo.org").query();
39 | listView.setData(orgNodes);
40 | ((OutlineAdapter) listView.getAdapter()).setAgendaMode(true);
41 | } catch (SQLException e) {
42 | e.printStackTrace();
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/synchronizer/calendar/CalendarEntriesParser.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.synchronizer.calendar;
2 |
3 | import android.database.Cursor;
4 | import android.provider.CalendarContract;
5 |
6 | public class CalendarEntriesParser {
7 |
8 | private int idColumn;
9 | private int dtStartColumn;
10 | private int dtEndColumn;
11 | private int titleColumn;
12 | private int descriptionColumn;
13 | private int locationColumn;
14 | private int allDayColumn;
15 |
16 | public CalendarEntriesParser(Cursor cursor) {
17 | dtStartColumn = cursor.getColumnIndexOrThrow(CalendarContract.Events.DTSTART);
18 | dtEndColumn = cursor.getColumnIndexOrThrow(CalendarContract.Events.DTEND);
19 | titleColumn = cursor.getColumnIndexOrThrow(CalendarContract.Events.TITLE);
20 | idColumn = cursor.getColumnIndexOrThrow(CalendarContract.Events._ID);
21 | descriptionColumn = cursor.getColumnIndexOrThrow(CalendarContract.Events.DESCRIPTION);
22 | locationColumn = cursor.getColumnIndexOrThrow(CalendarContract.Events.EVENT_LOCATION);
23 | allDayColumn = cursor.getColumnIndexOrThrow(CalendarContract.Events.ALL_DAY);
24 | }
25 |
26 | public CalendarEntry getEntryFromCursor(Cursor cursor) {
27 | CalendarEntry entry = new CalendarEntry();
28 |
29 | entry.dtStart = cursor.getLong(dtStartColumn);
30 | entry.dtEnd = cursor.getLong(dtEndColumn);
31 | entry.title = cursor.getString(titleColumn);
32 | entry.id = cursor.getLong(idColumn);
33 | entry.description = cursor.getString(descriptionColumn);
34 | entry.location = cursor.getString(locationColumn);
35 | entry.allDay = cursor.getInt(allDayColumn);
36 |
37 | return entry;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/mOrgAnd/src/androidTest/java/com/hdweiss/morgand/test/JGitWrapperTests.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.test;
2 |
3 | import android.content.SharedPreferences;
4 | import android.preference.PreferenceManager;
5 | import android.test.AndroidTestCase;
6 |
7 | import com.hdweiss.morgand.synchronizer.git.JGitWrapper;
8 |
9 | import java.io.File;
10 |
11 | public class JGitWrapperTests extends AndroidTestCase {
12 |
13 | private String localPath;
14 |
15 | private final String testFile = "README.md";
16 |
17 | private JGitWrapper jGitWrapper;
18 |
19 | @Override
20 | protected void setUp() throws Exception {
21 | super.setUp();
22 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext());
23 | this.localPath = preferences.getString("git_local_path", "");
24 | jGitWrapper = new JGitWrapper(preferences);
25 | }
26 |
27 | @Override
28 | protected void tearDown() throws Exception {
29 | super.tearDown();
30 | jGitWrapper.getGit(null).close();
31 | }
32 |
33 |
34 | public void testGitSetup() throws Exception {
35 | assertTrue(new File(localPath).exists());
36 | assertTrue(new File(localPath + "/.git").exists());
37 | assertTrue(jGitWrapper.getGit(null).branchList().call().size() > 0);
38 | }
39 |
40 | public void testCommitAndPush() throws Exception {
41 | String orgContents = TestUtils.readFileAsString(localPath + "/" + testFile);
42 | TestUtils.writeStringAsFile(orgContents + "\nmorgand", localPath + "/" + testFile);
43 | jGitWrapper.commitAllChanges("Automatic commit");
44 | jGitWrapper.updateChanges(null);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/data/CalendarUtils.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.data;
2 |
3 | import android.text.format.DateUtils;
4 |
5 | import java.text.SimpleDateFormat;
6 | import java.util.Calendar;
7 | import java.util.Date;
8 | import java.util.TimeZone;
9 |
10 | public class CalendarUtils {
11 |
12 | public static final SimpleDateFormat dateTimeformatter = new SimpleDateFormat("yyyy-MM-dd HH:mm");
13 | public static final SimpleDateFormat dateformatter = new SimpleDateFormat("yyyy-MM-dd");
14 |
15 |
16 | public static String formatDate(long dtStart, long dtEnd, boolean allDay) {
17 | String date;
18 |
19 | if (allDay)
20 | date = dateformatter.format(new Date(dtStart));
21 | else
22 | date = dateTimeformatter.format(new Date(dtStart));
23 |
24 | if (dtEnd > 0 && dtStart != dtEnd) {
25 | long timeDiff = dtEnd - dtStart;
26 |
27 | if(timeDiff <= DateUtils.DAY_IN_MILLIS) {
28 | SimpleDateFormat timeformatter = new SimpleDateFormat("HH:mm");
29 | String endTime = timeformatter.format(new Date(dtEnd));
30 |
31 | date += "-" + endTime;
32 | }
33 | }
34 |
35 | return "<" + date + ">";
36 | }
37 |
38 | public static long getDayInUTC(long time) {
39 | Calendar cal = Calendar.getInstance();
40 | cal.setTimeInMillis(time);
41 | cal.set(Calendar.HOUR, 0);
42 | cal.set(Calendar.MINUTE, 0);
43 | cal.set(Calendar.SECOND, 0);
44 | cal.set(Calendar.MILLISECOND, 0);
45 | cal.setTimeZone(TimeZone.getTimeZone("UTC"));
46 | return cal.getTimeInMillis();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/data/dao/OrgFile.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.data.dao;
2 |
3 | import android.content.Context;
4 |
5 | import com.hdweiss.morgand.Application;
6 | import com.j256.ormlite.android.apptools.OpenHelperManager;
7 | import com.j256.ormlite.dao.RuntimeExceptionDao;
8 | import com.j256.ormlite.field.DatabaseField;
9 | import com.j256.ormlite.table.DatabaseTable;
10 |
11 | import java.sql.SQLException;
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | @DatabaseTable(tableName = "OrgFiles")
16 | public class OrgFile {
17 |
18 | public static final String AGENDA_FILE_ALIAS = "Agenda Views";
19 |
20 | @DatabaseField(id = true)
21 | public String path = "";
22 |
23 | @DatabaseField
24 | public long lastModified;
25 |
26 | public static final String NODE_FIELD_NAME = "node";
27 | @DatabaseField(foreign = true, columnName = NODE_FIELD_NAME)
28 | public OrgNode node;
29 |
30 | public static RuntimeExceptionDao getDao() {
31 | Context context = Application.getInstace();
32 | return OpenHelperManager.getHelper(context, DatabaseHelper.class).getRuntimeExceptionDao(OrgFile.class);
33 | }
34 |
35 | public static List getAllFiles() {
36 | try {
37 | return getDao().queryBuilder().query();
38 | } catch (SQLException e) {
39 | e.printStackTrace();
40 | }
41 |
42 | return new ArrayList();
43 | }
44 |
45 | public static void deleteAll() {
46 | try {
47 | getDao().deleteBuilder().delete();
48 | } catch (SQLException e) {
49 | e.printStackTrace();
50 | }
51 | }
52 |
53 | public boolean isEditable() {
54 | return true;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/synchronizer/git/JGitConfigSessionFactory.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.synchronizer.git;
2 |
3 |
4 | import com.jcraft.jsch.JSch;
5 | import com.jcraft.jsch.JSchException;
6 | import com.jcraft.jsch.Session;
7 |
8 | import org.eclipse.jgit.transport.CredentialsProvider;
9 | import org.eclipse.jgit.transport.CredentialsProviderUserInfo;
10 | import org.eclipse.jgit.transport.JschConfigSessionFactory;
11 | import org.eclipse.jgit.transport.OpenSshConfig;
12 | import org.eclipse.jgit.util.FS;
13 |
14 | public class JGitConfigSessionFactory extends JschConfigSessionFactory {
15 | private final String username;
16 | private final String password;
17 | private final String keyLocation;
18 |
19 | public JGitConfigSessionFactory(String username, String password, String keyLocation) {
20 | super();
21 | this.username = username;
22 | this.password = password;
23 | this.keyLocation = keyLocation;
24 | }
25 |
26 | @Override
27 | protected void configure(OpenSshConfig.Host host, Session session) {
28 | session.setConfig("StrictHostKeyChecking", "no"); // TODO Find out how to enable strict host checking
29 |
30 | // TODO Delete me
31 | // String knownHostsLocation = "/sdcard/morg/known_hosts";
32 | // jSch.setKnownHosts(knownHostsLocation);
33 |
34 | CredentialsProvider provider = new JGitCredentialsProvider(username, password);
35 | session.setUserInfo(new CredentialsProviderUserInfo(session, provider));
36 | }
37 |
38 | @Override
39 | protected JSch getJSch(OpenSshConfig.Host hc, FS fs) throws JSchException {
40 | JSch jSch = super.getJSch(hc, fs);
41 | jSch.removeAllIdentity();
42 | if (!keyLocation.isEmpty())
43 | jSch.addIdentity(keyLocation, password);
44 | return jSch;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | mOrgAnd
5 |
6 |
7 | Location
8 | folder can\'t be read!
9 | New
10 | Select
11 | File name:
12 | Cancel
13 | Save
14 | No Data
15 | #ffff0000
16 | Error
17 |
18 |
19 | mOrgAnd
20 | Agenda
21 | Outline
22 | Synchronizing changes
23 |
24 | Settings
25 | Synchronize
26 | Save
27 | Set time
28 |
29 | Downloading wiki
30 |
31 | Synchronization failed
32 | Error copying key file to internal storage
33 | Error getting fingerprint from key file
34 | This key requires a passphrase
35 | View
36 | Capture
37 | Edit
38 | Delete node
39 | Clock in
40 | Archive
41 | No calendar
42 |
43 |
44 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/synchronizer/git/JGitCredentialsProvider.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.synchronizer.git;
2 |
3 | import org.eclipse.jgit.errors.UnsupportedCredentialItem;
4 | import org.eclipse.jgit.transport.CredentialItem;
5 | import org.eclipse.jgit.transport.CredentialsProvider;
6 | import org.eclipse.jgit.transport.URIish;
7 |
8 | public class JGitCredentialsProvider extends CredentialsProvider {
9 | private String username;
10 | private String password;
11 |
12 | public JGitCredentialsProvider(String username, String password) {
13 | this.username = username;
14 | this.password = password;
15 | }
16 |
17 | @Override
18 | public boolean isInteractive() {
19 | return false;
20 | }
21 |
22 | @Override // never gets called
23 | public boolean supports(CredentialItem... items) {
24 | return true;
25 | }
26 |
27 | @Override
28 | public boolean get(URIish uri, CredentialItem... items)
29 | throws UnsupportedCredentialItem {
30 | for (CredentialItem item : items) {
31 | if (item instanceof CredentialItem.Username) {
32 | ((CredentialItem.Username) item).setValue(username);
33 | } else if (item instanceof CredentialItem.Password) {
34 | ((CredentialItem.Password) item).setValue(password.toCharArray());
35 | } else if (item instanceof CredentialItem.StringType) {
36 | ((CredentialItem.StringType) item).setValue(password);
37 | } else if (item instanceof CredentialItem.InformationalMessage) {
38 | throw new UnsupportedCredentialItem(uri, "Not supported");
39 | } else if (item instanceof CredentialItem.YesNoType) {
40 | // TODO handle strict host key checking here
41 | throw new UnsupportedCredentialItem(uri, "Not supported");
42 | } else {
43 | throw new UnsupportedCredentialItem(uri, "Not supported");
44 | }
45 | }
46 | return true;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/gui/MainPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.gui;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.support.v4.app.Fragment;
6 | import android.support.v4.app.FragmentManager;
7 | import android.support.v4.app.FragmentPagerAdapter;
8 |
9 | import com.hdweiss.morgand.Application;
10 | import com.hdweiss.morgand.R;
11 | import com.hdweiss.morgand.gui.outline.OutlineFragment;
12 |
13 | import java.util.Locale;
14 |
15 | public class MainPagerAdapter extends FragmentPagerAdapter {
16 |
17 | private Context context;
18 |
19 | public MainPagerAdapter(FragmentManager fm) {
20 | super(fm);
21 | this.context = Application.getInstace();
22 | }
23 |
24 | @Override
25 | public Fragment getItem(int position) {
26 | Fragment fragment;
27 | Bundle argumentBundle = new Bundle();
28 |
29 | switch (position) {
30 | case 0:
31 | fragment = new OutlineFragment();
32 | break;
33 |
34 | case 1:
35 | fragment = new AgendaFragment();
36 | argumentBundle.putString("query", "NEXT%");
37 | break;
38 |
39 | case 2:
40 | fragment = new AgendaFragment();
41 | argumentBundle.putString("query", "TODO%");
42 | break;
43 |
44 | default:
45 | fragment = new OutlineFragment();
46 | break;
47 | }
48 |
49 | fragment.setArguments(argumentBundle);
50 | return fragment;
51 | }
52 |
53 | @Override
54 | public int getCount() {
55 | return 3;
56 | }
57 |
58 | @Override
59 | public CharSequence getPageTitle(int position) {
60 | Locale l = Locale.getDefault();
61 | switch (position) {
62 | case 0:
63 | return context.getString(R.string.title_outline).toUpperCase(l);
64 | case 1:
65 | return "NEXTs";
66 | case 2:
67 | return "TODOs";
68 | }
69 | return null;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/layout/edit_date_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
12 |
13 |
18 |
19 |
24 |
25 |
32 |
33 |
37 |
38 |
39 |
40 |
45 |
46 |
53 |
54 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/gui/theme/DefaultTheme.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.gui.theme;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 |
6 | import com.hdweiss.morgand.settings.PreferenceUtils;
7 |
8 | public class DefaultTheme {
9 |
10 | public int gray = Color.GRAY;
11 |
12 | public int c0Black = Color.rgb(0x00, 0x00, 0x00);
13 | public int c1Red = Color.rgb(0xd0, 0x00, 0x00);
14 | public int c2Green = Color.rgb(0x00, 0xa0, 0x00);
15 | public int c3Yellow = Color.rgb(0xc0, 0x80, 0x00);
16 | public int c4Blue = Color.rgb(0x22, 0x22, 0xf0);
17 | public int c5Purple = Color.rgb(0xa0, 0x00, 0xa0);
18 | public int c6Cyan = Color.rgb(0x00, 0x80, 0x80);
19 | public int c7White = Color.rgb(0xc0, 0xc0, 0xc0);
20 |
21 | public int c9LRed = Color.rgb(0xff, 0x77, 0x77);
22 | public int caLGreen = Color.rgb(0x77, 0xff, 0x77);
23 | public int cbLYellow = Color.rgb(0xff, 0xff, 0x00);
24 | public int ccLBlue = Color.rgb(0x88, 0x88, 0xff);
25 | public int cdLPurple = Color.rgb(0xff, 0x00, 0xff);
26 | public int ceLCyan = Color.rgb(0x00, 0xff, 0xff);
27 | public int cfLWhite = Color.rgb(0xff, 0xff, 0xff);
28 |
29 | public int defaultForeground = Color.rgb(0xc0, 0xc0, 0xc0);
30 | public int defaultBackground = Color.rgb(0x00, 0x00, 0x00);
31 | public int settingsForeground = Color.rgb(0x69, 0x6e, 0x52);
32 |
33 | public int directoryForeground = Color.rgb(0x3f, 0x2a, 0xdd);
34 |
35 | public int todoKeyword = Color.rgb(0xd0, 0x00, 0x00);
36 | public int inactiveTodoKeyword = Color.rgb(0x00, 0xa0, 0x00);
37 | public int priority = Color.rgb(0xc0, 0x80, 0x00);
38 |
39 | public int drawer = Color.rgb(0x5a, 0x5a, 0x4b);
40 |
41 | public int[] levelColors;
42 |
43 | public String defaultFontColor = "white";
44 |
45 | public DefaultTheme() {
46 | levelColors = new int[] { ccLBlue, c3Yellow, ceLCyan, c2Green,
47 | c5Purple, ccLBlue, c2Green, ccLBlue, c3Yellow, ceLCyan };
48 | }
49 |
50 |
51 | public static DefaultTheme getTheme(Context context) {
52 | final String themeName = PreferenceUtils.getThemeName();
53 | if(themeName.equals("Light"))
54 | return new WhiteTheme();
55 | else if(themeName.equals("Monochrome"))
56 | return new MonoTheme();
57 | else
58 | return new DefaultTheme();
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/data/dao/DatabaseHelper.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.data.dao;
2 |
3 | import android.content.Context;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.util.Log;
6 |
7 | import com.hdweiss.morgand.Application;
8 | import com.j256.ormlite.android.apptools.OpenHelperManager;
9 | import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
10 | import com.j256.ormlite.dao.RuntimeExceptionDao;
11 | import com.j256.ormlite.support.ConnectionSource;
12 | import com.j256.ormlite.table.TableUtils;
13 |
14 | import java.sql.SQLException;
15 |
16 | public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
17 |
18 | private static final String DATABASE_NAME = "mOrgAnd.db";
19 | private static final int DATABASE_VERSION = 11;
20 |
21 | public DatabaseHelper(Context context) {
22 | super(context, DATABASE_NAME, null, DATABASE_VERSION);
23 | }
24 |
25 | @Override
26 | public void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) {
27 | try {
28 | Log.i(DatabaseHelper.class.getName(), "onCreate");
29 | TableUtils.createTable(connectionSource, OrgNode.class);
30 | TableUtils.createTable(connectionSource, OrgFile.class);
31 | } catch (SQLException e) {
32 | Log.e(DatabaseHelper.class.getName(), "Can't create database", e);
33 | throw new RuntimeException(e);
34 | }
35 | }
36 |
37 |
38 | @Override
39 | public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int oldVersion, int newVersion) {
40 | try {
41 | Log.i(DatabaseHelper.class.getName(), "onUpgrade");
42 | TableUtils.dropTable(connectionSource, OrgNode.class, true);
43 | TableUtils.dropTable(connectionSource, OrgFile.class, true);
44 |
45 | onCreate(db, connectionSource);
46 | } catch (SQLException e) {
47 | Log.e(DatabaseHelper.class.getName(), "Can't drop databases", e);
48 | throw new RuntimeException(e);
49 | }
50 | }
51 |
52 |
53 | public static RuntimeExceptionDao getOrgNodeDao() {
54 | Context context = Application.getInstace();
55 | return OpenHelperManager.getHelper(context, DatabaseHelper.class).getRuntimeExceptionDao(OrgNode.class);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/xml/pref_data_sync.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
17 |
18 |
27 |
28 |
33 |
34 |
35 |
36 |
44 |
45 |
53 |
54 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/mOrgAnd/src/androidTest/java/com/hdweiss/morgand/test/OrgFileWriterTests.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.test;
2 |
3 | import android.test.AndroidTestCase;
4 |
5 | import com.hdweiss.morgand.synchronizer.writer.OrgFileWriter;
6 |
7 | import junit.framework.Assert;
8 |
9 | import java.util.ArrayList;
10 |
11 | public class OrgFileWriterTests extends AndroidTestCase {
12 |
13 | private OrgFileWriter writer;
14 | private OrgFileTestScenario scenario;
15 |
16 | @Override
17 | protected void setUp() throws Exception {
18 | super.setUp();
19 | scenario = new OrgFileTestScenario();
20 | ArrayList fileCopy = new ArrayList(scenario.file);
21 | writer = new OrgFileWriter(fileCopy);
22 | }
23 |
24 | public void testDeleteHeading() {
25 | writer.delete(scenario.heading);
26 |
27 | Assert.assertEquals(debugString(), 2, writer.fileContent.size());
28 | }
29 |
30 |
31 | public void testOverwriteSubheading() {
32 | OrgNodeStubbed subheading = scenario.subheading;
33 | subheading.title = "** new title";
34 | writer.overwrite(subheading);
35 |
36 | Assert.assertEquals(debugString(), scenario.file.size(), writer.fileContent.size());
37 |
38 | String writtenLine = writer.fileContent.get(subheading.lineNumber - 1);
39 | Assert.assertEquals(debugString(), subheading.title, writtenLine);
40 | }
41 |
42 | public void testOverwriteContent() {
43 | OrgNodeStubbed content = scenario.content;
44 | content.title = "test";
45 |
46 | writer.overwrite(content);
47 |
48 | Assert.assertEquals(debugString(), scenario.file.size() - 1, writer.fileContent.size());
49 |
50 | String writtenLine = writer.fileContent.get(content.lineNumber - 1);
51 | Assert.assertEquals(debugString(), content.title, writtenLine);
52 | }
53 |
54 | public void testAddSubheading() {
55 | OrgNodeStubbed parent = scenario.heading;
56 |
57 | OrgNodeStubbed child = new OrgNodeStubbed(-1);
58 | child.title = "** added child";
59 | child.parent = parent;
60 |
61 | writer.add(child);
62 |
63 | Assert.assertEquals(debugString(), scenario.file.size() + 1, writer.fileContent.size());
64 |
65 | int expectedIndex = scenario.heading2.lineNumber - 2;
66 | String writtenLine = writer.fileContent.get(expectedIndex);
67 |
68 | Assert.assertEquals(debugString(), child.title, writtenLine);
69 | }
70 |
71 |
72 | private String debugString() {
73 | String message = "Before:\n" + scenario.file.toString() +
74 | "\nAfter:\n" + writer.fileContent.toString();
75 | return message;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/mOrgAnd/src/androidTest/java/com/hdweiss/morgand/test/OrgFileTestScenario.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.test;
2 |
3 | import java.util.ArrayList;
4 |
5 | public class OrgFileTestScenario {
6 |
7 | public ArrayList file;
8 |
9 | public OrgNodeStubbed heading;
10 | public OrgNodeStubbed subheading;
11 | public OrgNodeStubbed content;
12 | public OrgNodeStubbed subheading2;
13 | public OrgNodeStubbed content2;
14 | public OrgNodeStubbed subsubheading1;
15 | public OrgNodeStubbed subheading3;
16 | public OrgNodeStubbed heading2;
17 | public OrgNodeStubbed content3;
18 |
19 | public OrgFileTestScenario() {
20 | setup();
21 | }
22 |
23 | public void setup() {
24 | file = new ArrayList();
25 |
26 | file.add("* Heading");
27 | heading = new OrgNodeStubbed(file.size());
28 |
29 | file.add("** sub heading 1");
30 | subheading = new OrgNodeStubbed(file.size());
31 | file.add("content 1");
32 | content = new OrgNodeStubbed(file.size());
33 | file.add("content 1");
34 |
35 | file.add("** sub heading 2");
36 | subheading2 = new OrgNodeStubbed(file.size());
37 | file.add("content 2");
38 | content2 = new OrgNodeStubbed(file.size());
39 | file.add("content 2");
40 |
41 | file.add("*** sub sub heading 1");
42 | subsubheading1 = new OrgNodeStubbed(file.size());
43 |
44 | file.add("** sub heading 3");
45 | subheading3 = new OrgNodeStubbed(file.size());
46 |
47 | file.add("* heading 2");
48 | heading2 = new OrgNodeStubbed(file.size());
49 | file.add("contents 3");
50 | content3 = new OrgNodeStubbed(file.size());
51 |
52 | heading.nextNodeLineNumber = subheading.lineNumber;
53 | heading.siblingLineNumber = heading2.lineNumber;
54 |
55 | subheading.nextNodeLineNumber = content.lineNumber;
56 | subheading.siblingLineNumber = subheading2.lineNumber;
57 |
58 | content.nextNodeLineNumber = subheading2.lineNumber;
59 | content.siblingLineNumber = subheading2.lineNumber;
60 |
61 | subheading2.nextNodeLineNumber = content2.lineNumber;
62 | subheading2.siblingLineNumber = subheading3.lineNumber;
63 |
64 | content2.nextNodeLineNumber = subsubheading1.lineNumber;
65 | content2.siblingLineNumber = subsubheading1.lineNumber;
66 |
67 | subsubheading1.nextNodeLineNumber = subheading3.lineNumber;
68 | subsubheading1.siblingLineNumber = subheading3.lineNumber;
69 |
70 | heading2.nextNodeLineNumber = content3.lineNumber;
71 | heading2.siblingLineNumber = Integer.MAX_VALUE;
72 |
73 | content3.nextNodeLineNumber = Integer.MAX_VALUE;
74 | content3.siblingLineNumber = Integer.MAX_VALUE;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/data/OrgNodeUtils.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.data;
2 |
3 | import android.text.TextUtils;
4 |
5 | import com.hdweiss.morgand.data.dao.OrgNode;
6 | import com.hdweiss.morgand.data.dao.OrgNodeRepository;
7 |
8 | import java.util.HashSet;
9 | import java.util.regex.Matcher;
10 | import java.util.regex.Pattern;
11 |
12 | public class OrgNodeUtils {
13 |
14 | public static final Pattern urlPattern = Pattern.compile("(?:\\[\\[([^\\]]+)\\](?:\\[([^\\]]+)\\])?\\])|(http(?:s?)://\\S+)"); // Match [[url]], [[url][alias]] and http(s)://url
15 | public static final Pattern dateMatcher = Pattern.compile("((?:SCHEDULED:|DEADLINE:)\\s?)?<([^>]+)>" + "(?:\\s*--\\s*<([^>]+)>)?");
16 | public static final Pattern headingPattern = Pattern.compile("([A-Z]+)(:?\\s(.+))?");
17 | public static final Pattern prioritiesPattern = Pattern.compile("\\[#([^\\]]*)\\]");
18 |
19 | public static String combineTags(String tags, String inheritedTags, HashSet excludedTags) {
20 | String combinedTags = "";
21 | if (TextUtils.isEmpty(tags) == false)
22 | combinedTags += tags;
23 |
24 | if (TextUtils.isEmpty(inheritedTags) == false)
25 | combinedTags += inheritedTags;
26 |
27 | if (excludedTags == null || TextUtils.isEmpty(combinedTags))
28 | return combinedTags;
29 |
30 | StringBuilder result = new StringBuilder();
31 | for (String tag : combinedTags.split(":")) {
32 | if (excludedTags.contains(tag) == false && TextUtils.isEmpty(tag) == false) {
33 | result.append(tag);
34 | result.append(":");
35 | }
36 | }
37 |
38 | if (!TextUtils.isEmpty(result))
39 | result.deleteCharAt(result.lastIndexOf(":"));
40 |
41 | return result.toString();
42 | }
43 |
44 | public static void toggleCheckbox(OrgNode node) {
45 | boolean checkedOff = node.title.contains("- [ ]");
46 | if (checkedOff) {
47 | node.title = node.title.replaceFirst("-\\s\\[\\s\\]", "- [X]");
48 | } else
49 | node.title = node.title.replaceFirst("-\\s\\[X\\]", "- [ ]");
50 |
51 | OrgNodeRepository.update(node);
52 |
53 | if (node.parent == null)
54 | return;
55 |
56 | updateCheckboxCookie(node.parent, checkedOff);
57 | }
58 |
59 | private static void updateCheckboxCookie(OrgNode node, boolean increment) {
60 | try {
61 | Matcher matcher = Pattern.compile("\\[(\\d+)/(\\d+)\\]").matcher(node.title);
62 | if (matcher.find()) {
63 | int currentAmount = Integer.parseInt(matcher.group(1));
64 | int total = Integer.parseInt(matcher.group(2));
65 | currentAmount = increment ? currentAmount + 1 : currentAmount - 1;
66 |
67 | if (currentAmount < 0)
68 | return;
69 |
70 | node.title = node.title.replace(matcher.group(), "[" + currentAmount + "/" + total + "]");
71 | OrgNodeRepository.update(node);
72 | }
73 | } catch (Exception ex) {
74 | ex.printStackTrace();
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/utils/Utils.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.utils;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.net.ConnectivityManager;
6 | import android.net.NetworkInfo;
7 | import android.preference.PreferenceManager;
8 |
9 | import java.io.PrintWriter;
10 | import java.io.StringWriter;
11 | import java.util.ArrayList;
12 | import java.util.HashSet;
13 | import java.util.Iterator;
14 | import java.util.List;
15 |
16 | public class Utils {
17 | public static String ExceptionTraceToString(Exception exception) {
18 | StringWriter sw = new StringWriter();
19 | exception.printStackTrace(new PrintWriter(sw));
20 | return sw.toString();
21 | }
22 |
23 | public static boolean isWifiOnline(Context context) {
24 | try {
25 | ConnectivityManager conMan = (ConnectivityManager) context
26 | .getSystemService(Context.CONNECTIVITY_SERVICE);
27 |
28 | NetworkInfo.State wifi = conMan.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
29 | .getState();
30 |
31 | if (wifi == NetworkInfo.State.CONNECTED)
32 | return true;
33 | } catch (Exception ex) {
34 | ex.printStackTrace();
35 | }
36 | return false;
37 | }
38 |
39 | public static boolean isMobileOnline(Context context) {
40 | try {
41 | ConnectivityManager conMan = (ConnectivityManager) context
42 | .getSystemService(Context.CONNECTIVITY_SERVICE);
43 |
44 | NetworkInfo.State mobile = conMan.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
45 | .getState();
46 |
47 | if (mobile == NetworkInfo.State.CONNECTED)
48 | return true;
49 | } catch (Exception ex) {
50 | ex.printStackTrace();
51 | }
52 | return false;
53 | }
54 |
55 |
56 | public static boolean isNetworkOnline(Context context) {
57 | SharedPreferences prefs = PreferenceManager
58 | .getDefaultSharedPreferences(context);
59 | boolean wifiOnly = prefs.getBoolean("sync_wifi_only", false);
60 |
61 | if (wifiOnly)
62 | return isWifiOnline(context);
63 | else
64 | return isWifiOnline(context)
65 | || isMobileOnline(context);
66 | }
67 |
68 | public static boolean[] toPrimitiveArray(final List booleanList) {
69 | final boolean[] primitives = new boolean[booleanList.size()];
70 | int index = 0;
71 | for (Boolean object : booleanList) {
72 | primitives[index++] = object;
73 | }
74 | return primitives;
75 | }
76 |
77 | public static List toList(HashSet set) {
78 | ArrayList list = new ArrayList();
79 | if (set == null)
80 | return list;
81 | list.addAll(set);
82 | return list;
83 | }
84 |
85 |
86 | public static int getIteratorSize(Iterator> iterator) {
87 | int i = 0;
88 | while (iterator.hasNext()) {
89 | iterator.next();
90 | i++;
91 | }
92 |
93 | return i;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/xml/pref_calendar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
16 |
17 |
22 |
23 |
30 |
31 |
32 |
38 |
44 |
50 |
51 |
52 |
58 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/synchronizer/parser/SyncParserTask.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.synchronizer.parser;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.preference.PreferenceManager;
6 | import android.util.Log;
7 |
8 | import com.hdweiss.morgand.Application;
9 | import com.hdweiss.morgand.data.dao.OrgFile;
10 | import com.hdweiss.morgand.events.DataUpdatedEvent;
11 | import com.hdweiss.morgand.events.SyncEvent;
12 | import com.hdweiss.morgand.gui.SynchronizerNotification;
13 | import com.hdweiss.morgand.settings.PreferenceUtils;
14 | import com.hdweiss.morgand.synchronizer.calendar.SyncCalendarTask;
15 | import com.hdweiss.morgand.utils.SafeAsyncTask;
16 | import com.hdweiss.morgand.utils.Utils;
17 |
18 | import java.util.ArrayList;
19 |
20 | public class SyncParserTask extends SafeAsyncTask {
21 |
22 | private ArrayList modifiedFiles;
23 |
24 | public SyncParserTask(Context context) {
25 | super(context, ReportMode.Log);
26 | }
27 |
28 | @Override
29 | protected Void safeDoInBackground(Void... voids) throws Exception {
30 | Log.d("Parser", "Started synchronization");
31 |
32 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
33 | String localRepoPath = preferences.getString("git_local_path", "");
34 |
35 | publishProgress(new SyncEvent(SyncEvent.State.Progress, 0));
36 |
37 | OrgRepository repository = new OrgRepository(localRepoPath);
38 | modifiedFiles = repository.getModifiedFiles();
39 |
40 | if (modifiedFiles.isEmpty()) {
41 | Log.d("Parser", "No modified files");
42 | }
43 |
44 | int fileIndex = 0;
45 | for(OrgFile orgFile: modifiedFiles) {
46 | fileIndex++;
47 |
48 | Log.d("Parser", "Parsing " + orgFile.path);
49 | new OrgFileParser().parse(orgFile);
50 |
51 | int progress = (100 / modifiedFiles.size()) * fileIndex;
52 | publishProgress(new SyncEvent(SyncEvent.State.Progress, progress, orgFile.path));
53 | }
54 |
55 | Log.d("Parser", "Ended synchronization");
56 | return null;
57 | }
58 |
59 | @Override
60 | protected void onProgressUpdate(SyncEvent... events) {
61 | super.onProgressUpdate(events);
62 |
63 | for(SyncEvent event: events)
64 | Application.getBus().post(event);
65 |
66 | Application.getBus().post(new DataUpdatedEvent());
67 | }
68 |
69 | @Override
70 | protected void onSuccess(Void aVoid) {
71 | String[] filenames = new String[modifiedFiles.size()];
72 | for(int i = 0; i < modifiedFiles.size(); i++) {
73 | filenames[i] = modifiedFiles.get(i).path;
74 | }
75 |
76 | if (PreferenceUtils.syncCalendar())
77 | new SyncCalendarTask(context).execute(filenames);
78 | }
79 |
80 | @Override
81 | protected void onCleanup() {
82 | Application.getBus().post(new SyncEvent(SyncEvent.State.Done));
83 | }
84 |
85 | @Override
86 | protected void onError() {
87 | SynchronizerNotification notification = new SynchronizerNotification(context);
88 | notification.errorNotification(exception.getMessage() + "\n" + Utils.ExceptionTraceToString(exception));
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/data/OrgCalendarEntry.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.data;
2 |
3 | import android.text.TextUtils;
4 | import android.text.format.DateUtils;
5 | import android.util.Log;
6 |
7 | import java.text.ParseException;
8 | import java.util.regex.Matcher;
9 | import java.util.regex.Pattern;
10 |
11 | public class OrgCalendarEntry {
12 |
13 | public long beginTime = 0;
14 | public long endTime = 0;
15 | public int allDay = 0;
16 | public String type = "";
17 | public String title = "";
18 |
19 |
20 | private static final String datePattern = "(\\d{1,2}\\:\\d{2})"; // d:dd or dd:dd
21 | private static final Pattern schedulePattern = Pattern
22 | .compile("(\\d{4}-\\d{2}-\\d{2})" // YYYY-MM-DD
23 | + "(?:[^\\d]*)" // Strip out month
24 | + datePattern + "?" // Begin time
25 | + "(?:\\-" + datePattern + ")?"); // "-" followed by end time
26 |
27 | private static final int DATE = 1;
28 | private static final int BEGIN_TIME = 2;
29 | private static final int END_TIME = 3;
30 |
31 |
32 | public OrgCalendarEntry(String date) throws IllegalArgumentException {
33 | Matcher schedule = schedulePattern.matcher(date);
34 |
35 | if (schedule.find()) {
36 | try {
37 | if(schedule.group(BEGIN_TIME) == null) { // event is an entire day event
38 | this.beginTime = CalendarUtils.dateformatter.parse(schedule.group(DATE)).getTime();
39 |
40 | // All day events need to be in UTC and end time is exactly one day after
41 | this.beginTime = CalendarUtils.getDayInUTC(beginTime);
42 | this.endTime = this.beginTime + DateUtils.DAY_IN_MILLIS;
43 | this.allDay = 1;
44 | }
45 | else if (schedule.group(BEGIN_TIME) != null && schedule.group(END_TIME) != null) {
46 | this.beginTime = CalendarUtils.dateTimeformatter.parse(schedule.group(DATE) + " " + schedule.group(BEGIN_TIME)).getTime();
47 | this.endTime = CalendarUtils.dateTimeformatter.parse(schedule.group(DATE) + " " + schedule.group(END_TIME)).getTime();
48 | this.allDay = 0;
49 | } else if(schedule.group(BEGIN_TIME) != null) {
50 | this.beginTime = CalendarUtils.dateTimeformatter.parse(schedule.group(DATE) + " " + schedule.group(BEGIN_TIME)).getTime();
51 | this.endTime = beginTime + DateUtils.HOUR_IN_MILLIS;
52 | this.allDay = 0;
53 | }
54 |
55 | return;
56 | } catch (ParseException e) {
57 | Log.w("MobileOrg", "Unable to parse schedule: " + date);
58 | }
59 | } else
60 | throw new IllegalArgumentException("Could not create date out of entry");
61 | }
62 |
63 |
64 |
65 | /**
66 | * Whether an event is in the past. True if event ended 24 hours ago or
67 | * sometime in the future.
68 | */
69 | public boolean isInPast() {
70 | return System.currentTimeMillis() - DateUtils.DAY_IN_MILLIS >= endTime;
71 | }
72 |
73 | public void setTitle(String title) {
74 | this.title = title;
75 | }
76 |
77 |
78 | public String getCalendarTitle() {
79 | String formatedType = this.type;
80 | if (type.startsWith("SCHEDULED"))
81 | formatedType = "SC";
82 | else if (type.startsWith("DEADLINE"))
83 | formatedType = "DL";
84 |
85 | if (TextUtils.isEmpty(formatedType))
86 | return this.title;
87 | else
88 | return formatedType + ": " + this.title;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/synchronizer/writer/SyncWriterTask.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.synchronizer.writer;
2 |
3 | import android.content.Context;
4 | import android.util.Log;
5 |
6 | import com.hdweiss.morgand.data.dao.OrgFile;
7 | import com.hdweiss.morgand.data.dao.OrgNode;
8 | import com.hdweiss.morgand.data.dao.OrgNodeRepository;
9 | import com.hdweiss.morgand.events.SyncEvent;
10 | import com.hdweiss.morgand.gui.SynchronizerNotification;
11 | import com.hdweiss.morgand.settings.PreferenceUtils;
12 | import com.hdweiss.morgand.synchronizer.git.SyncGitTask;
13 | import com.hdweiss.morgand.utils.SafeAsyncTask;
14 | import com.hdweiss.morgand.utils.Utils;
15 |
16 | import java.util.List;
17 |
18 | public class SyncWriterTask extends SafeAsyncTask {
19 |
20 | public SyncWriterTask(Context context) {
21 | super(context, ReportMode.Log);
22 | }
23 |
24 | @Override
25 | protected Void safeDoInBackground(OrgFile... files) throws Exception {
26 | Log.d("Writer", "Started synchronization");
27 |
28 | if (files.length > 0) {
29 | for (OrgFile file : files)
30 | writeChanges(file);
31 | } else {
32 | for(OrgFile file : OrgFile.getAllFiles())
33 | writeChanges(file);
34 | }
35 |
36 | Log.d("Writer", "Ended synchronization");
37 | return null;
38 | }
39 |
40 | private void writeChanges(OrgFile file) throws Exception {
41 | OrgFileWriter writer = new OrgFileWriter(file);
42 |
43 | List dirtyNodes = OrgNodeRepository.getDirtyNodes(file);
44 |
45 | if (dirtyNodes.isEmpty())
46 | return;
47 |
48 | Log.d("Writer", "Writing changes to " + file.path);
49 |
50 | for(OrgNode node: dirtyNodes)
51 | applyChanges(writer, node);
52 |
53 | writer.write();
54 |
55 | for(OrgNode node: dirtyNodes) {
56 | node.state = OrgNode.State.Clean;
57 | OrgNodeRepository.update(node);
58 | }
59 | }
60 |
61 | private void applyChanges(OrgFileWriter writer, OrgNode node) {
62 | if (node.isNodeWritable() == false) {
63 | Log.d("Writer", "Node not writable " + node.getTitle());
64 | return;
65 | }
66 |
67 | if (node.type == OrgNode.Type.File || node.type == OrgNode.Type.Directory)
68 | return; // We don't handle deletion of files or directories
69 |
70 | switch (node.state) {
71 | case Added:
72 | writer.add(node);
73 | break;
74 |
75 | case Deleted:
76 | writer.delete(node);
77 | break;
78 |
79 | case Updated:
80 | writer.overwrite(node);
81 | break;
82 |
83 | default:
84 | break;
85 | }
86 | }
87 |
88 | @Override
89 | protected void onSuccess(Void aVoid) {
90 | if (PreferenceUtils.syncMode().equals("git"))
91 | new SyncGitTask(context).execute();
92 | }
93 |
94 | @Override
95 | protected void onError() {
96 | SynchronizerNotification notification = new SynchronizerNotification(context);
97 | notification.errorNotification(exception.getMessage() + "\n" + Utils.ExceptionTraceToString(exception));
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/synchronizer/writer/OrgFileWriter.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.synchronizer.writer;
2 |
3 | import com.hdweiss.morgand.data.dao.OrgFile;
4 | import com.hdweiss.morgand.data.dao.OrgNode;
5 | import com.hdweiss.morgand.utils.FileUtils;
6 |
7 | import java.io.BufferedWriter;
8 | import java.io.FileWriter;
9 | import java.io.IOException;
10 | import java.util.ArrayList;
11 |
12 | public class OrgFileWriter {
13 |
14 | private final OrgFile orgFile;
15 | public ArrayList fileContent;
16 |
17 | public OrgFileWriter(OrgFile orgFile) throws IOException {
18 | this.orgFile = orgFile;
19 | fileContent = FileUtils.fileToArrayList(orgFile.path);
20 | }
21 |
22 | /**
23 | * Constructor for unit testing.
24 | */
25 | public OrgFileWriter(ArrayList fileContent) {
26 | this.orgFile = null;
27 | this.fileContent = fileContent;
28 | }
29 |
30 |
31 | public void write() throws IOException {
32 | BufferedWriter writer = new BufferedWriter(new FileWriter(orgFile.path, false));
33 | for(String line: fileContent)
34 | writer.write(line + "\n");
35 | writer.close();
36 | }
37 |
38 |
39 | public void add(OrgNode node) {
40 | if (node == null) throw new IllegalArgumentException("Got null node as argument");
41 | if (node.parent == null) throw new IllegalArgumentException("Got node with null parent as argument: " + node.title);
42 | if (node.parent.type == OrgNode.Type.Directory) throw new IllegalArgumentException("Got node with invalid parent type");
43 |
44 | int index = node.parent.getSiblingLineNumber() - 1;
45 | if (index < 0) throw new IllegalArgumentException("Got node with parent lineNumber less than 0: " + node.parent.title);
46 |
47 | add(index, node.toStringRecursively());
48 | }
49 |
50 | public void delete(OrgNode node) {
51 | if (node == null) throw new IllegalArgumentException("Got null node as argument");
52 | if (node.lineNumber < 0) throw new IllegalArgumentException("Node's lineNumber can't be less than 0: " + node.title);
53 |
54 | int startIndex = node.lineNumber - 1;
55 | int endIndex = node.getSiblingLineNumber() - 1;
56 | removeRange(startIndex, endIndex);
57 | }
58 |
59 | public void overwrite(OrgNode node) {
60 | int startIndex = node.lineNumber - 1;
61 | int endIndex = node.getNextNodeLineNumber() - 1;
62 | removeRange(startIndex, endIndex);
63 | add(startIndex, node.toString());
64 | }
65 |
66 |
67 | private void removeRange(final int from, final int to) {
68 | if (from < 0 || from > to) throw new IllegalArgumentException("Can't remove range from=" + from + " to=" + to + " fileContent.size()=" + fileContent.size());
69 |
70 | for (int linesToDelete = to - from; linesToDelete > 0 && from < fileContent.size(); linesToDelete--)
71 | fileContent.remove(from);
72 | }
73 |
74 | private void add(final int index, final String content) {
75 | if (index < 0) throw new IllegalArgumentException("Can't add contents with negative index index=" + index + ", content=" + content);
76 |
77 | if (index <= fileContent.size())
78 | fileContent.add(index, content);
79 | else
80 | fileContent.add(content);
81 | }
82 |
83 | public String toString() {
84 | return fileContent.toString();
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/xml/pref_git.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
32 |
33 |
42 |
43 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
62 |
63 |
72 |
73 |
82 |
83 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/data/OrgNodeTimeDate.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.data;
2 |
3 | import android.text.TextUtils;
4 |
5 | import java.util.Calendar;
6 | import java.util.regex.Matcher;
7 | import java.util.regex.Pattern;
8 |
9 | public class OrgNodeTimeDate {
10 | private TYPE type = TYPE.Scheduled;
11 |
12 | private int year = -1;
13 | private int monthOfYear = -1;
14 | private int dayOfMonth = -1;
15 | private int startTimeOfDay = -1;
16 | private int startMinute = -1;
17 | private int endTimeOfDay = -1;
18 | private int endMinute = -1;
19 |
20 | private enum TYPE {
21 | Scheduled,
22 | Deadline,
23 | Timestamp,
24 | InactiveTimestamp
25 | };
26 |
27 | private OrgNodeTimeDate(TYPE type) {
28 | this.type = type;
29 | }
30 |
31 |
32 | private void setToCurrentDate() {
33 | final Calendar c = Calendar.getInstance();
34 | this.year = c.get(Calendar.YEAR);
35 | this.monthOfYear = c.get(Calendar.MONTH) + 1;
36 | this.dayOfMonth = c.get(Calendar.DAY_OF_MONTH);
37 | }
38 |
39 | private static final Pattern schedulePattern = Pattern
40 | .compile("((\\d{4})-(\\d{1,2})-(\\d{1,2}))(?:[^\\d]*)"
41 | + "((\\d{1,2})\\:(\\d{2}))?(-((\\d{1,2})\\:(\\d{2})))?");
42 | private void parseDate(String date) {
43 | if(date == null)
44 | return;
45 |
46 | Matcher propm = schedulePattern.matcher(date);
47 |
48 | if (propm.find()) {
49 | try {
50 | year = Integer.parseInt(propm.group(2));
51 | monthOfYear = Integer.parseInt(propm.group(3));
52 | dayOfMonth = Integer.parseInt(propm.group(4));
53 |
54 | startTimeOfDay = Integer.parseInt(propm.group(6));
55 | startMinute = Integer.parseInt(propm.group(7));
56 |
57 | endTimeOfDay = Integer.parseInt(propm.group(10));
58 | endMinute = Integer.parseInt(propm.group(11));
59 | } catch (NumberFormatException e) {
60 | e.printStackTrace();
61 | }
62 | }
63 | }
64 |
65 |
66 | private String getDate() {
67 | return String.format("%d-%02d-%02d", year, monthOfYear, dayOfMonth);
68 | }
69 |
70 | private String getStartTime() {
71 | return String.format("%02d:%02d", startTimeOfDay, startMinute);
72 | }
73 |
74 | private String getEndTime() {
75 | return String.format("%02d:%02d", endTimeOfDay, endMinute);
76 | }
77 |
78 |
79 | private String toString2() {
80 | return getDate().toString() + getStartTimeFormated() + getEndTimeFormated();
81 | }
82 |
83 | public String toFormatedString() {
84 | return formatDate(type, getDate());
85 | }
86 |
87 |
88 | private String getStartTimeFormated() {
89 | String time = getStartTime().toString();
90 |
91 | if (startTimeOfDay == -1
92 | || startMinute == -1 || TextUtils.isEmpty(time))
93 | return "";
94 | else
95 | return " " + time;
96 | }
97 |
98 | private String getEndTimeFormated() {
99 | String time = getEndTime().toString();
100 |
101 | if (endTimeOfDay == -1
102 | || endMinute == -1 || TextUtils.isEmpty(time))
103 | return "";
104 | else
105 | return "-" + time;
106 | }
107 |
108 |
109 | private static String typeToFormated(TYPE type) {
110 | switch (type) {
111 | case Scheduled:
112 | return "SCHEDULED: ";
113 | case Deadline:
114 | return "DEADLINE: ";
115 | case Timestamp:
116 | return "";
117 | default:
118 | return "";
119 | }
120 | }
121 |
122 | private String formatDate(TYPE type, String timestamp) {
123 | if (TextUtils.isEmpty(timestamp))
124 | return "";
125 | else {
126 | return OrgNodeTimeDate.typeToFormated(type) + "<" + timestamp + ">";
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/gui/edit/EditHeadingFragment.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.gui.edit;
2 |
3 | import android.os.Bundle;
4 | import android.text.TextUtils;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.view.WindowManager;
9 | import android.widget.ArrayAdapter;
10 | import android.widget.AutoCompleteTextView;
11 | import android.widget.TextView;
12 |
13 | import com.hdweiss.morgand.R;
14 | import com.hdweiss.morgand.data.dao.OrgNode;
15 | import com.hdweiss.morgand.settings.PreferenceUtils;
16 | import com.hdweiss.morgand.utils.Utils;
17 |
18 | import java.util.HashSet;
19 |
20 | public class EditHeadingFragment extends BaseEditFragment {
21 |
22 | private AutoCompleteTextView headingView;
23 | private TextView inheritedTagsView;
24 | private AutoCompleteTextView tagsView;
25 |
26 | @Override
27 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
28 | View view = inflater.inflate(R.layout.edit_heading_fragment, container, false);
29 |
30 | tagsView = (AutoCompleteTextView) view.findViewById(R.id.tags);
31 | inheritedTagsView = (TextView) view.findViewById(R.id.inheritedTags);
32 |
33 | headingView = (AutoCompleteTextView) view.findViewById(R.id.heading);
34 | headingView.setOnEditorActionListener(this);
35 | headingView.setThreshold(0);
36 | headingView.requestFocus();
37 | getDialog().getWindow().setSoftInputMode(
38 | WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
39 |
40 | return view;
41 | }
42 |
43 | @Override
44 | public void onViewCreated(View view, Bundle savedInstanceState) {
45 | super.onViewCreated(view, savedInstanceState);
46 |
47 | if (controller == null)
48 | return;
49 |
50 | OrgNode node = controller.getNode();
51 | populateView(node.getTitle(), node.tags, node.inheritedTags);
52 | populateAutocompletion();
53 |
54 | switch (controller.getMode()) {
55 | case Add:
56 | getDialog().setTitle(R.string.action_capture);
57 | break;
58 |
59 | case Edit:
60 | getDialog().setTitle(R.string.action_edit);
61 | break;
62 | }
63 | }
64 |
65 | private void populateView(String heading, String tags, String inheritedTags) {
66 | if (heading != null) {
67 | headingView.setText(heading);
68 | headingView.setSelection(headingView.getText().length());
69 | }
70 |
71 | if (TextUtils.isEmpty(inheritedTags))
72 | inheritedTagsView.setVisibility(View.GONE);
73 | else {
74 | inheritedTagsView.setVisibility(View.VISIBLE);
75 | inheritedTagsView.setText(inheritedTags);
76 | }
77 |
78 | if (tags != null)
79 | tagsView.setText(tags);
80 | }
81 |
82 | private void populateAutocompletion() {
83 | HashSet todoKeywords = PreferenceUtils.getAllTodoKeywords();
84 | if (todoKeywords.size() == 0)
85 | return;
86 |
87 | ArrayAdapter adapter = new ArrayAdapter(getActivity(),
88 | android.R.layout.simple_dropdown_item_1line, Utils.toList(todoKeywords));
89 | headingView.setAdapter(adapter);
90 | }
91 |
92 | @Override
93 | public OrgNode getEditedNode() {
94 | OrgNode editNode = controller.getNode();
95 | editNode.title = headingView.getText().toString();
96 | editNode.tags = tagsView.getText().toString();
97 | return editNode;
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/settings/PreferenceUtils.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.settings;
2 |
3 | import android.content.SharedPreferences;
4 | import android.preference.PreferenceManager;
5 | import android.text.TextUtils;
6 |
7 | import com.hdweiss.morgand.Application;
8 | import com.hdweiss.morgand.utils.FileUtils;
9 |
10 | import java.io.File;
11 | import java.util.HashSet;
12 |
13 | public class PreferenceUtils {
14 |
15 | private static SharedPreferences getPrefs() {
16 | return PreferenceManager.getDefaultSharedPreferences(Application.getInstace());
17 | }
18 |
19 | public static void set(String key, String value) {
20 | SharedPreferences.Editor editor = getPrefs().edit();
21 | editor.putString(key, value);
22 | editor.commit();
23 | }
24 |
25 | public static String getThemeName() {
26 | return "Light";
27 | }
28 |
29 | public static HashSet getExcludedTags() {
30 | return new HashSet();
31 | }
32 |
33 |
34 | public static HashSet getInactiveTodoKeywords() {
35 | return getHashSetFromPreferenceString("todo_inactive", "DONE", ":");
36 | }
37 |
38 | public static HashSet getActiveTodoKeywords() {
39 | return getHashSetFromPreferenceString("todo_active", "TODO:NEXT", ":");
40 | }
41 |
42 | public static HashSet getAllTodoKeywords() {
43 | HashSet todoKeywords = getActiveTodoKeywords();
44 | todoKeywords.addAll(getInactiveTodoKeywords());
45 | return todoKeywords;
46 | }
47 |
48 | public static HashSet getPriorties() {
49 | return getHashSetFromPreferenceString("priorities", "A:B:C", ":");
50 | }
51 |
52 | private static HashSet getHashSetFromPreferenceString(final String key, final String defaultValue, final String delimiter) {
53 | HashSet keywordHashset = new HashSet();
54 |
55 | String activeKeywords = getPrefs().getString(key, defaultValue);
56 | String[] keywords = activeKeywords.split(delimiter);
57 | for(String keyword: keywords) {
58 | if (TextUtils.isEmpty(keyword) == false)
59 | keywordHashset.add(keyword);
60 | }
61 | return keywordHashset;
62 | }
63 |
64 | public static boolean syncCalendar() {
65 | return getPrefs().getBoolean("calendar_enabled", false);
66 | }
67 |
68 | public static boolean showDrawers() {
69 | return getPrefs().getBoolean("show_drawers", false);
70 | }
71 |
72 | public static boolean showSettings() {
73 | return getPrefs().getBoolean("show_settings", false);
74 | }
75 |
76 | public static boolean outlineExpandAll() {
77 | return getPrefs().getBoolean("outline_expandall", false);
78 | }
79 |
80 | public static String syncMode() {
81 | return getPrefs().getString("sync_mode", "git");
82 | }
83 |
84 | public static void setupGitToWiki() {
85 | SharedPreferences.Editor editor = getPrefs().edit();
86 | editor.remove("git_username");
87 | editor.remove("git_password");
88 | editor.remove("git_key_path");
89 |
90 | File externalDir = Application.getInstace().getExternalFilesDir(null);
91 | File file = new File(externalDir, "mOrgAnd.wiki");
92 |
93 | if (file.exists())
94 | FileUtils.deleteDirectory(file);
95 |
96 | editor.putString("sync_mode", "git");
97 | editor.putString("git_local_path", file.getAbsolutePath());
98 | editor.putString("git_url", "git://github.com/hdweiss/mOrgAnd.wiki");
99 | editor.putString("git_branch", "master");
100 | editor.commit();
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/gui/outline/OutlineActionMode.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.gui.outline;
2 |
3 | import android.content.Context;
4 | import android.view.ActionMode;
5 | import android.view.Menu;
6 | import android.view.MenuInflater;
7 | import android.view.MenuItem;
8 | import android.widget.ListView;
9 |
10 | import com.hdweiss.morgand.data.dao.OrgNode;
11 |
12 |
13 | public class OutlineActionMode implements ActionMode.Callback {
14 |
15 | private Context context;
16 |
17 | private ListView list;
18 | private OutlineAdapter adapter;
19 | private int listPosition;
20 | private OrgNode node;
21 |
22 | public OutlineActionMode(Context context) {
23 | super();
24 | this.context = context;
25 | }
26 |
27 | public void initActionMode(ListView list, int position, int restorePosition) {
28 | initActionMode(list, position);
29 | this.listPosition = restorePosition;
30 | }
31 |
32 | public void initActionMode(ListView list, int position) {
33 | list.setItemChecked(position, true);
34 | this.list = list;
35 | this.adapter = (OutlineAdapter) list.getAdapter();
36 | this.listPosition = position;
37 | this.node = adapter.getItem(position);
38 | }
39 |
40 | @Override
41 | public void onDestroyActionMode(ActionMode mode) {
42 | this.list.setItemChecked(this.listPosition, true);
43 | }
44 |
45 | @Override
46 | public boolean onCreateActionMode(ActionMode mode, Menu menu) {
47 | MenuInflater inflater = mode.getMenuInflater();
48 |
49 | // if (this.node != null && this.node.Id >= 0 && node.isEditable()) {
50 | // inflater.inflate(R.menu.outline_node, menu);
51 | // }
52 | // else if(this.node != null && this.node.type == OrgNode.Type.File) {
53 | // if(this.node.title.equals(OrgFile.AGENDA_FILE_ALIAS))
54 | // inflater.inflate(R.menu.outline_file_uneditable, menu);
55 | // else
56 | // inflater.inflate(R.menu.outline_file, menu);
57 | // } else
58 | // inflater.inflate(R.menu.outline_node_uneditable, menu);
59 | //
60 | return true;
61 | }
62 |
63 | @Override
64 | public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
65 | return false;
66 | }
67 |
68 | @Override
69 | public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
70 | switch (item.getItemId()) {
71 |
72 | // case R.id.menu_edit:
73 | // runEditNodeActivity(node.Id, context);
74 | // break;
75 | // case R.id.menu_delete:
76 | // runDeleteNode();
77 | // break;
78 | // case R.id.menu_delete_file:
79 | // runDeleteFileNode();
80 | // break;
81 | // case R.id.menu_clockin:
82 | // runTimeClockingService();
83 | // break;
84 | // case R.id.menu_archive:
85 | // runArchiveNode(false);
86 | // break;
87 | // case R.id.menu_view:
88 | // runViewNodeActivity();
89 | // break;
90 | //
91 | // case R.id.menu_capturechild:
92 | // runCaptureActivity(node.Id, context);
93 | // break;
94 | //
95 | // default:
96 | // mode.finish();
97 | // return false;
98 | }
99 |
100 | mode.finish();
101 | return true;
102 | }
103 |
104 |
105 | public static void runEditNodeActivity(long nodeId, Context context) {
106 |
107 | }
108 |
109 | public static void runCaptureActivity(long id, Context context) {
110 |
111 | }
112 |
113 | private void runDeleteNode() {
114 |
115 | }
116 |
117 | private void runArchiveNode(final boolean archiveToSibling) {
118 |
119 | }
120 |
121 | private void archiveNode(boolean archiveToSibling) {
122 |
123 | }
124 |
125 | private void runDeleteFileNode() {
126 |
127 | }
128 |
129 | private void deleteFileNode() {
130 |
131 | }
132 |
133 | public static void runViewNodeActivity(long nodeId, Context context) {
134 |
135 | }
136 |
137 | private void runViewNodeActivity() {
138 | }
139 |
140 | private void runTimeClockingService() {
141 |
142 | }
143 |
144 | private void runRecover() {
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/layout/file_dialog_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
17 |
19 |
22 |
25 |
26 |
27 |
28 |
33 |
35 |
37 |
38 |
40 |
43 |
46 |
47 |
48 |
49 |
50 |
51 |
54 |
56 |
58 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/gui/edit/BaseEditFragment.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.gui.edit;
2 |
3 | import android.app.Activity;
4 | import android.app.DialogFragment;
5 | import android.app.FragmentTransaction;
6 | import android.os.Bundle;
7 | import android.view.KeyEvent;
8 | import android.view.inputmethod.EditorInfo;
9 | import android.widget.TextView;
10 |
11 | import com.hdweiss.morgand.Application;
12 | import com.hdweiss.morgand.data.dao.OrgNode;
13 | import com.hdweiss.morgand.data.dao.OrgNodeRepository;
14 | import com.hdweiss.morgand.events.DataUpdatedEvent;
15 | import com.hdweiss.morgand.gui.edit.controller.AddController;
16 | import com.hdweiss.morgand.gui.edit.controller.BaseEditController;
17 | import com.hdweiss.morgand.gui.edit.controller.EditController;
18 |
19 | public abstract class BaseEditFragment extends DialogFragment implements TextView.OnEditorActionListener {
20 |
21 | public static BaseEditFragment getEditFragment(OrgNode node) {
22 | BaseEditFragment fragment;
23 | switch (node.type) {
24 | case Headline:
25 | fragment = new EditHeadingFragment();
26 | break;
27 |
28 | case Date:
29 | fragment = new EditDateFragment();
30 | break;
31 |
32 | default:
33 | fragment = new EditTextFragment();
34 | break;
35 | }
36 |
37 | setFragmentArguments(fragment, node.Id, BaseEditController.EditMode.Edit);
38 | return fragment;
39 | }
40 |
41 | public static BaseEditFragment getAddFragment(OrgNode node) {
42 | BaseEditFragment fragment = new EditHeadingFragment();
43 | setFragmentArguments(fragment, node.Id, BaseEditController.EditMode.Add);
44 | return fragment;
45 | }
46 |
47 | private static void setFragmentArguments(BaseEditFragment fragment, int nodeId, BaseEditController.EditMode mode) {
48 | Bundle argumentBundle = new Bundle();
49 | argumentBundle.putInt("nodeId", nodeId);
50 | argumentBundle.putString("mode", mode.name());
51 |
52 | fragment.setArguments(argumentBundle);
53 | }
54 |
55 |
56 | protected BaseEditController controller;
57 |
58 | @Override
59 | public void onCreate(Bundle savedInstanceState) {
60 | super.onCreate(savedInstanceState);
61 |
62 | int nodeId = getArguments().getInt("nodeId", -1);
63 | if (nodeId == -1)
64 | throw new IllegalArgumentException("No nodeId given");
65 |
66 | OrgNode node = OrgNodeRepository.queryForId(nodeId);
67 |
68 | String editModeString = getArguments().getString("mode", "edit");
69 | BaseEditController.EditMode mode = BaseEditController.EditMode.valueOf(editModeString);
70 |
71 | switch (mode) {
72 | case Add:
73 | this.controller = new AddController(node, OrgNode.Type.Headline);
74 | break;
75 |
76 | case Edit:
77 | default:
78 | this.controller = new EditController(node);
79 | break;
80 | }
81 | }
82 |
83 | public abstract OrgNode getEditedNode();
84 |
85 |
86 | public void show(Activity activity) {
87 | FragmentTransaction fragmentTransaction = activity.getFragmentManager().beginTransaction();
88 | fragmentTransaction.add(this, "dialog");
89 | fragmentTransaction.commit();
90 | }
91 |
92 | @Override
93 | public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
94 | if (EditorInfo.IME_ACTION_DONE == actionId) {
95 | if (controller != null) {
96 | OrgNode editedNode = getEditedNode();
97 | controller.save(editedNode);
98 | Application.getBus().post(new DataUpdatedEvent());
99 | }
100 | dismiss();
101 | return true;
102 | }
103 |
104 | return false;
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/synchronizer/git/SyncGitTask.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.synchronizer.git;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.os.Build;
6 | import android.preference.PreferenceManager;
7 | import android.util.Log;
8 |
9 | import com.hdweiss.morgand.Application;
10 | import com.hdweiss.morgand.events.SyncEvent;
11 | import com.hdweiss.morgand.gui.SynchronizerNotification;
12 | import com.hdweiss.morgand.synchronizer.parser.SyncParserTask;
13 | import com.hdweiss.morgand.utils.SafeAsyncTask;
14 | import com.hdweiss.morgand.utils.Utils;
15 |
16 | import org.eclipse.jgit.lib.ProgressMonitor;
17 |
18 | public class SyncGitTask extends SafeAsyncTask {
19 |
20 | private JGitWrapper jGitWrapper;
21 |
22 | public SyncGitTask(Context context) {
23 | super(context, ReportMode.Toast);
24 | }
25 |
26 | @Override
27 | protected Void safeDoInBackground(Void... params) throws Exception {
28 | Log.d("Git", "Started synchronization");
29 |
30 | if (Utils.isNetworkOnline(context) == false) {
31 | Log.d("Git", "Network is offline, aborting git synchronization");
32 | return null;
33 | }
34 |
35 | publishProgress(new SyncEvent(SyncEvent.State.Intermediate));
36 |
37 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
38 | jGitWrapper = new JGitWrapper(preferences);
39 | jGitWrapper.commitAllChanges(Build.MODEL + ": Automatic commit");
40 | jGitWrapper.updateChanges(monitor);
41 |
42 | Log.d("Git", "Ended synchronization");
43 | return null;
44 | }
45 |
46 | @Override
47 | protected void onProgressUpdate(SyncEvent... events) {
48 | super.onProgressUpdate(events);
49 | for(SyncEvent event: events)
50 | Application.getBus().post(event);
51 | }
52 |
53 | @Override
54 | protected void onSuccess(Void aVoid) {
55 | Application.getBus().post(new SyncEvent(SyncEvent.State.SecondaryProgress, 100));
56 | new SyncParserTask(context).execute();
57 | }
58 |
59 | @Override
60 | protected void onError() {
61 | Application.getBus().post(new SyncEvent(SyncEvent.State.Done));
62 | SynchronizerNotification notification = new SynchronizerNotification(context);
63 | notification.errorNotification(exception.getLocalizedMessage() + "\n" + Utils.ExceptionTraceToString(exception));
64 | }
65 |
66 | @Override
67 | protected void onCleanup() {
68 | if (jGitWrapper != null)
69 | jGitWrapper.cleanup();
70 | }
71 |
72 |
73 | private ProgressMonitor monitor = new ProgressMonitor() {
74 |
75 | private int progress = 0;
76 | private int totalWork = 0;
77 | private int workCompleted = 0;
78 |
79 | public void start(int totalTasks) {
80 | }
81 |
82 | public void beginTask(String title, int totalWork) {
83 | this.totalWork = totalWork;
84 | this.workCompleted = 0;
85 | publishProgress(new SyncEvent(SyncEvent.State.SecondaryProgress, 0));
86 | }
87 |
88 | public void update(int completed) {
89 | this.workCompleted += completed;
90 | int newProgress = getProgress();
91 |
92 | if(this.progress != newProgress) {
93 | this.progress = newProgress;
94 | publishProgress(new SyncEvent(SyncEvent.State.SecondaryProgress, newProgress));
95 | }
96 | }
97 |
98 | private int getProgress() {
99 | if(totalWork == 0)
100 | return 0;
101 |
102 | final int taskWorkProgress = (int) ((100.0 / totalWork)
103 | * workCompleted);
104 | return taskWorkProgress;
105 | }
106 |
107 | public void endTask() {
108 | }
109 |
110 | public boolean isCancelled() {
111 | return false;
112 | }
113 | };
114 | }
115 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/utils/SafeAsyncTask.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.utils;
2 |
3 | import android.content.Context;
4 | import android.os.AsyncTask;
5 | import android.util.Log;
6 | import android.widget.Toast;
7 |
8 | /**
9 | * Wrapper for {@link android.os.AsyncTask} that allows exceptions to be caught and presented to the
10 | * user in a meaningful way.
11 | *
12 | * It is required to override {@link #safeDoInBackground(Object[])}, which will be executed within
13 | * {@link android.os.AsyncTask#execute(Object[])}. If an exception is caught it will be sent to
14 | * {@link #onCancelled(Object)}, which will extract a meaningful message from an exception. The
15 | * message will be reported to the user with {@link #reportError(String)}, which will either display a toast, log the error
16 | * message to Logcat or do nothing. The reporting behaviour is controlled by {@link #mode}.
17 | *
18 | * When an exception is caught {@link #onError()} will be called, otherwise {@link
19 | * #onSuccess(Object)} is called. Finally {@link #onCleanup()} will always be called.
20 | *
21 | */
22 | public abstract class SafeAsyncTask extends AsyncTask {
23 | public enum ReportMode {
24 | Toast, Log, Silent
25 | }
26 |
27 | final private ReportMode mode;
28 | final protected Context context;
29 |
30 | protected Exception exception = null;
31 |
32 | /**
33 | * Main worker method. It is run within a {@link android.os.AsyncTask#doInBackground(Object[])}.
34 | * Any exception this method throws is caught and reported according to the given {@link
35 | * #mode}.
36 | */
37 | abstract protected Result safeDoInBackground(Params... params) throws Exception;
38 |
39 | /** Run after {@link #safeDoInBackground(Object[])} doesn't throw exception. */
40 | protected void onSuccess(Result result) {}
41 |
42 | /** Run after {@link #safeDoInBackground(Object[])} throws an exception. */
43 | protected void onError() {}
44 |
45 | /** Guaranteed to run after either {@link #onSuccess(Object)} or {@link #onError()} is run. */
46 | protected void onCleanup() {}
47 |
48 | public SafeAsyncTask(Context context, ReportMode mode) {
49 | this.context = context;
50 | this.mode = mode;
51 | }
52 |
53 | @Override
54 | final protected Result doInBackground(Params... params) {
55 | try {
56 | return safeDoInBackground(params);
57 | }
58 | catch (Exception e) {
59 | exception = e;
60 | cancel(true);
61 | return null;
62 | }
63 | }
64 |
65 | @Override
66 | protected void onPostExecute(Result result) {
67 | super.onPostExecute(result);
68 | onSuccess(result);
69 | onCleanup();
70 | }
71 |
72 |
73 | @Override
74 | final protected void onCancelled() {
75 | if (exception != null) {
76 | if (exception instanceof ReportableException)
77 | reportError(exception.getLocalizedMessage());
78 | else
79 | reportError(exception.getLocalizedMessage());
80 | Log.e("SafeAsyncTask", "safeDoInBackground() threw exception", exception);
81 | }
82 |
83 | onError();
84 | onCleanup();
85 | }
86 |
87 | @Override
88 | final protected void onCancelled(Result result) {
89 | onCancelled();
90 | }
91 |
92 | /** Reports the error according to {@link #mode}. */
93 | protected void reportError(String error) {
94 | if (error == null || error.isEmpty())
95 | return;
96 |
97 | if (mode == ReportMode.Toast && context != null)
98 | Toast.makeText(context, error, Toast.LENGTH_LONG).show();
99 | if (mode != ReportMode.Silent)
100 | Log.d("SafeAsyncTask", error);
101 | }
102 |
103 |
104 | public static class ReportableException extends Exception {
105 | public ReportableException(String message) {
106 | super(message);
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/data/dao/OrgNodeRepository.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.data.dao;
2 |
3 | import com.j256.ormlite.stmt.DeleteBuilder;
4 | import com.j256.ormlite.stmt.QueryBuilder;
5 | import com.j256.ormlite.stmt.Where;
6 |
7 | import java.sql.SQLException;
8 | import java.util.ArrayList;
9 | import java.util.Collections;
10 | import java.util.List;
11 |
12 | public class OrgNodeRepository {
13 |
14 | public static OrgNode queryForId(Integer id) {
15 | return DatabaseHelper.getOrgNodeDao().queryForId(id);
16 | }
17 |
18 | public static void update(OrgNode node) {
19 | if (node.state != OrgNode.State.Added) // Keep the added state when updating nodes
20 | node.state = OrgNode.State.Updated;
21 |
22 | DatabaseHelper.getOrgNodeDao().update(node);
23 | }
24 |
25 | public static void create(OrgNode node) {
26 | if (node.type != OrgNode.Type.Directory) // Directories should always have state=clean
27 | node.state = OrgNode.State.Added;
28 |
29 | DatabaseHelper.getOrgNodeDao().create(node);
30 | }
31 |
32 | public static void delete(OrgNode node) {
33 | if (node.type == OrgNode.Type.File || node.type == OrgNode.Type.Directory)
34 | deleteWithoutUpdate(node);
35 | else
36 | deleteWithUpdate(node);
37 | }
38 |
39 | private static void deleteWithUpdate(OrgNode node) {
40 | node.state = OrgNode.State.Deleted;
41 | DatabaseHelper.getOrgNodeDao().update(node);
42 |
43 | for(OrgNode child: node.children)
44 | deleteWithUpdate(child);
45 | }
46 |
47 | private static void deleteWithoutUpdate(OrgNode node) {
48 | for(OrgNode child: node.children)
49 | deleteWithoutUpdate(child);
50 |
51 | DatabaseHelper.getOrgNodeDao().delete(node);
52 | }
53 |
54 | public static QueryBuilder queryBuilder() {
55 | return DatabaseHelper.getOrgNodeDao().queryBuilder();
56 | }
57 |
58 | public static DeleteBuilder deleteBuilder() {
59 | return DatabaseHelper.getOrgNodeDao().deleteBuilder();
60 | }
61 |
62 |
63 | public static void deleteAll() {
64 | try {
65 | deleteBuilder().delete();
66 | } catch (SQLException e) {
67 | e.printStackTrace();
68 | }
69 | }
70 |
71 | public static int delete(OrgFile orgFile) throws SQLException {
72 | DeleteBuilder deleteBuilder = deleteBuilder();
73 | deleteBuilder.where().eq(OrgNode.FILE_FIELD_NAME, orgFile);
74 | return deleteBuilder.delete();
75 | }
76 |
77 | public static List getRootNodes() {
78 | try {
79 | List children = queryBuilder().where().isNull(OrgNode.PARENT_FIELD_NAME).and().ne(OrgNode.STATE_FIELD_NAME, OrgNode.State.Deleted).query();
80 | Collections.sort(children, new OrgNode.OrgNodeCompare());
81 | return children;
82 | } catch (SQLException e) {
83 | e.printStackTrace();
84 | }
85 |
86 | return new ArrayList();
87 | }
88 |
89 | public static List getScheduledNodes(String filename, boolean showHabits) {
90 | try {
91 | Where query = queryBuilder().where().eq(OrgNode.FILE_FIELD_NAME, filename);
92 | query.and().like(OrgNode.TITLE_FIELD_NAME, "%<%>%");
93 |
94 | if (showHabits == false)
95 | query.and().not().like(OrgNode.TITLE_FIELD_NAME, "%:STYLE: habit%");
96 |
97 | return query.query();
98 | } catch (SQLException e) {
99 | e.printStackTrace();
100 | }
101 |
102 | return new ArrayList();
103 | }
104 |
105 | public static List getDirtyNodes(OrgFile file) throws SQLException {
106 | Where builder = queryBuilder().orderBy(OrgNode.LINENUMBER_FIELD_NAME, false).where();
107 | builder.eq(OrgNode.FILE_FIELD_NAME, file);
108 | builder.and().ne(OrgNode.STATE_FIELD_NAME, OrgNode.State.Clean);
109 | return builder.query();
110 | }
111 |
112 | public static OrgNode getDefaultCaptureNode() {
113 | return new OrgNode(); // TODO
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/settings/KeySettingActivity.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.settings;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.content.SharedPreferences;
6 | import android.os.Bundle;
7 | import android.os.Environment;
8 | import android.preference.PreferenceManager;
9 | import android.text.TextUtils;
10 | import android.widget.Toast;
11 |
12 | import com.hdweiss.morgand.R;
13 | import com.jcraft.jsch.JSch;
14 | import com.jcraft.jsch.KeyPair;
15 | import com.lamerman.FileDialog;
16 | import com.lamerman.SelectionMode;
17 |
18 | import java.io.FileInputStream;
19 | import java.io.FileOutputStream;
20 | import java.io.IOException;
21 |
22 | public class KeySettingActivity extends Activity {
23 |
24 | public final static String KeyfileName = "keyfile";
25 |
26 | @Override
27 | protected void onCreate(Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 |
30 | Intent intent = new Intent(getBaseContext(), FileDialog.class);
31 | intent.putExtra(FileDialog.START_PATH, Environment.getExternalStorageDirectory().getPath());
32 | intent.putExtra(FileDialog.CAN_SELECT_DIR, false);
33 | //intent.putExtra(FileDialog.FORMAT_FILTER, new String[] { "_rsa" });
34 | intent.putExtra(FileDialog.SELECTION_MODE, SelectionMode.MODE_OPEN);
35 |
36 | startActivityForResult(intent, 0);
37 | }
38 |
39 | @Override
40 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
41 | if (resultCode == Activity.RESULT_OK) {
42 | String filePath = data.getStringExtra(FileDialog.RESULT_PATH);
43 |
44 | SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
45 | String passphrase = prefs.getString("git_password", "");
46 | if (CopyKeyToStorage(filePath, passphrase)) {
47 | SharedPreferences.Editor edit = prefs.edit();
48 | edit.putString("git_key_info", GetKeyprint(GetInternalKeyPath(), passphrase));
49 | edit.putString("git_key_path", GetInternalKeyPath());
50 | edit.commit();
51 | }
52 | } else if (resultCode == Activity.RESULT_CANCELED) {
53 | }
54 | finish();
55 | }
56 |
57 | private String GetKeyprint(String keyfilePath, String passphrase) {
58 | try {
59 | KeyPair keyPair = KeyPair.load(new JSch(), keyfilePath);
60 | if (!passphrase.isEmpty() && keyPair.isEncrypted())
61 | keyPair.decrypt(passphrase);
62 | else if (passphrase.isEmpty() && keyPair.isEncrypted()) {
63 | Toast.makeText(this, R.string.error_key_need_pass, Toast.LENGTH_LONG).show();
64 | return "";
65 | }
66 | String fingerprint = keyPair.getFingerPrint();
67 | keyPair.dispose();
68 | return fingerprint;
69 | } catch (Exception e) {
70 | e.printStackTrace();
71 | }
72 | return "";
73 | }
74 |
75 | private boolean CopyKeyToStorage(String filePath, String passphrase) {
76 | String fingerprint = GetKeyprint(filePath, passphrase);
77 | if (TextUtils.isEmpty(fingerprint)) {
78 | Toast.makeText(this, R.string.error_key_file_info, Toast.LENGTH_LONG).show();
79 | return false;
80 | }
81 |
82 | try {
83 | FileInputStream fis = new FileInputStream(filePath);
84 | FileOutputStream fos = openFileOutput(KeyfileName, MODE_PRIVATE);
85 |
86 | byte[] buffer = new byte[1444];
87 | int byteread = 0;
88 | int bytesum = 0;
89 | while ((byteread = fis.read(buffer)) != -1) {
90 | bytesum += byteread;
91 | fos.write(buffer, 0, byteread);
92 | }
93 | fos.close();
94 | fis.close();
95 | return true;
96 | } catch (IOException e) {
97 | e.printStackTrace();
98 | Toast.makeText(this, getText(R.string.error_key_file_copy), Toast.LENGTH_LONG);
99 | }
100 |
101 | return false;
102 | }
103 |
104 | private String GetInternalKeyPath() {
105 | return getFilesDir() + "/" + KeyfileName;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/gui/SynchronizerNotification.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.gui;
2 |
3 | import android.annotation.TargetApi;
4 | import android.app.Notification;
5 | import android.app.NotificationManager;
6 | import android.app.PendingIntent;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.os.Build;
10 |
11 | import com.hdweiss.morgand.R;
12 |
13 | public class SynchronizerNotification {
14 | private NotificationManager notificationManager;
15 | private Notification notification;
16 | private int notifyRef = 1;
17 | private Context context;
18 |
19 | public SynchronizerNotification(Context context) {
20 | this.context = context;
21 | }
22 |
23 | public void errorNotification(String errorMsg) {
24 | this.notificationManager = (NotificationManager) context
25 | .getSystemService(Context.NOTIFICATION_SERVICE);
26 | Intent notifyIntent = new Intent(context, MainActivity.class);
27 | notifyIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
28 | | Intent.FLAG_ACTIVITY_SINGLE_TOP);
29 |
30 | PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
31 | notifyIntent, 0);
32 |
33 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
34 | notification = getBigstyleNotification(errorMsg, contentIntent);
35 | } else {
36 | notification = getSimpleNotification(errorMsg, contentIntent);
37 | }
38 | notificationManager.notify(notifyRef, notification);
39 | }
40 |
41 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
42 | private Notification getBigstyleNotification(String message, PendingIntent contentIntent) {
43 | Notification notification = new Notification.BigTextStyle(
44 | new Notification.Builder(context)
45 | .setContentIntent(contentIntent)
46 | .setContentTitle(context.getString(R.string.error_sync))
47 | .setContentText("Error")
48 | .setSmallIcon(R.drawable.ic_launcher))
49 | .bigText(message)
50 | .build();
51 | return notification;
52 | }
53 |
54 |
55 | private Notification getSimpleNotification(String message, PendingIntent contentIntent) {
56 | Notification.Builder builder = new Notification.Builder(context);
57 | builder.setContentIntent(contentIntent);
58 | builder.setSmallIcon(R.drawable.ic_launcher);
59 | builder.setContentText(message);
60 | return builder.getNotification();
61 | }
62 |
63 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
64 | public void setupNotification() {
65 | this.notificationManager = (NotificationManager) context
66 | .getSystemService(Context.NOTIFICATION_SERVICE);
67 | Intent notifyIntent = new Intent(context, MainActivity.class);
68 | notifyIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
69 | | Intent.FLAG_ACTIVITY_SINGLE_TOP);
70 |
71 | PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
72 | notifyIntent, 0);
73 |
74 | Notification.Builder builder = new Notification.Builder(context);
75 | builder.setContentIntent(contentIntent);
76 | builder.setSmallIcon(R.drawable.ic_launcher);
77 | builder.setOngoing(true);
78 | builder.setContentTitle(context.getString(R.string.title_synchronizing_changes));
79 | builder.setProgress(100, 0, true);
80 | notification = builder.getNotification();
81 |
82 | notificationManager.notify(notifyRef, notification);
83 | }
84 |
85 | public void updateNotification(String message) {
86 | if(notification == null)
87 | return;
88 |
89 | if(message != null) {
90 | notificationManager.notify(notifyRef, notification);
91 | }
92 | }
93 |
94 | public void updateNotification(int progress) {
95 | updateNotification(progress, null);
96 | }
97 |
98 | public void updateNotification(int progress, String message) {
99 | if(notification == null)
100 | return;
101 |
102 | notification.contentView.setProgressBar(android.R.id.progress, 100,
103 | progress, false);
104 |
105 | notificationManager.notify(notifyRef, notification);
106 | }
107 |
108 | public void finalizeNotification() {
109 | notificationManager.cancel(notifyRef);
110 | }
111 | }
112 |
113 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/synchronizer/SyncService.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.synchronizer;
2 |
3 | import android.app.AlarmManager;
4 | import android.app.PendingIntent;
5 | import android.app.Service;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.SharedPreferences;
9 | import android.os.AsyncTask;
10 | import android.os.IBinder;
11 | import android.preference.PreferenceManager;
12 |
13 | import com.hdweiss.morgand.Application;
14 | import com.hdweiss.morgand.synchronizer.writer.SyncWriterTask;
15 |
16 | public class SyncService extends Service implements
17 | SharedPreferences.OnSharedPreferenceChangeListener {
18 | private static final String ACTION = "action";
19 | private static final String START_ALARM = "START_ALARM";
20 | private static final String STOP_ALARM = "STOP_ALARM";
21 |
22 | private SharedPreferences appSettings;
23 |
24 | private AlarmManager alarmManager;
25 | private PendingIntent alarmIntent;
26 | private boolean alarmScheduled = false;
27 | private AsyncTask syncTask;
28 |
29 | @Override
30 | public void onCreate() {
31 | super.onCreate();
32 | this.appSettings = PreferenceManager
33 | .getDefaultSharedPreferences(getApplicationContext());
34 | this.appSettings.registerOnSharedPreferenceChangeListener(this);
35 | this.alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
36 | }
37 |
38 | @Override
39 | public void onDestroy() {
40 | unsetAlarm();
41 | this.appSettings.unregisterOnSharedPreferenceChangeListener(this);
42 | super.onDestroy();
43 | }
44 |
45 | public static void stopAlarm(Context context) {
46 | Intent intent = new Intent(context, SyncService.class);
47 | intent.putExtra(ACTION, SyncService.STOP_ALARM);
48 | context.startService(intent);
49 | }
50 |
51 | public static void startAlarm(Context context) {
52 | Intent intent = new Intent(context, SyncService.class);
53 | intent.putExtra(ACTION, SyncService.START_ALARM);
54 | context.startService(intent);
55 | }
56 |
57 | @Override
58 | public int onStartCommand(Intent intent, int flags, int startId) {
59 | if (intent == null)
60 | return 0;
61 | String action = intent.getStringExtra(ACTION);
62 | if (action != null && action.equals(START_ALARM))
63 | setAlarm();
64 | else if (action != null && action.equals(STOP_ALARM))
65 | unsetAlarm();
66 | else if (syncTask == null || syncTask.getStatus() == AsyncTask.Status.FINISHED)
67 | runSynchronizerAsync();
68 | return 0;
69 | }
70 |
71 | private void runSynchronizerAsync() {
72 | unsetAlarm();
73 | syncTask = new SyncWriterTask(getBaseContext()).execute();
74 | setAlarm();
75 | }
76 |
77 |
78 | private void setAlarm() {
79 | boolean doAutoSync = this.appSettings.getBoolean("sync_auto", false);
80 | if (!this.alarmScheduled && doAutoSync) {
81 |
82 | int interval = Integer.parseInt(
83 | this.appSettings.getString("sync_frequency", "1800000"),
84 | 10);
85 |
86 | this.alarmIntent = PendingIntent.getService(Application.getInstace(), 0, new Intent(
87 | this, SyncService.class), 0);
88 | alarmManager.setInexactRepeating(AlarmManager.RTC,
89 | System.currentTimeMillis() + interval, interval,
90 | alarmIntent);
91 |
92 | this.alarmScheduled = true;
93 | }
94 | }
95 |
96 | private void unsetAlarm() {
97 | if (this.alarmScheduled) {
98 | this.alarmManager.cancel(this.alarmIntent);
99 | this.alarmScheduled = false;
100 | }
101 | }
102 |
103 | private void resetAlarm() {
104 | unsetAlarm();
105 | setAlarm();
106 | }
107 |
108 | @Override
109 | public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
110 | if (key.equals("sync_auto")) {
111 | boolean syncAuto = preferences.getBoolean("sync_auto", false);
112 | if (syncAuto && !this.alarmScheduled)
113 | setAlarm();
114 | else if (syncAuto == false && this.alarmScheduled)
115 | unsetAlarm();
116 | } else if (key.equals("sync_frequency"))
117 | resetAlarm();
118 | }
119 |
120 | @Override
121 | public IBinder onBind(Intent intent) {
122 | return null;
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/gui/outline/OutlineFragment.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.gui.outline;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.view.LayoutInflater;
6 | import android.view.Menu;
7 | import android.view.MenuInflater;
8 | import android.view.MenuItem;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 |
12 | import com.hdweiss.morgand.Application;
13 | import com.hdweiss.morgand.R;
14 | import com.hdweiss.morgand.data.dao.OrgNode;
15 | import com.hdweiss.morgand.data.dao.OrgNodeRepository;
16 | import com.hdweiss.morgand.events.DataUpdatedEvent;
17 | import com.hdweiss.morgand.gui.edit.BaseEditFragment;
18 | import com.j256.ormlite.android.apptools.OpenHelperManager;
19 | import com.squareup.otto.Subscribe;
20 |
21 | public class OutlineFragment extends Fragment {
22 |
23 | protected OutlineListView listView;
24 |
25 | @Override
26 | public void onCreate(Bundle savedInstanceState) {
27 | super.onCreate(savedInstanceState);
28 | Application.getBus().register(this);
29 | setHasOptionsMenu(true);
30 | }
31 |
32 | @Override
33 | public void onDestroy() {
34 | Application.getBus().unregister(this);
35 | super.onDestroy();
36 | OpenHelperManager.releaseHelper();
37 | }
38 |
39 | @Override
40 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
41 | Bundle savedInstanceState) {
42 | View rootView = inflater.inflate(R.layout.fragment_outline, container, false);
43 | listView = (OutlineListView) rootView.findViewById(R.id.list);
44 | listView.setEmptyView(rootView.findViewById(R.id.outline_list_empty));
45 | return rootView;
46 | }
47 |
48 |
49 | @Override
50 | public void onActivityCreated(Bundle savedInstanceState) {
51 | super.onActivityCreated(savedInstanceState);
52 |
53 | listView.setActivity(getActivity());
54 | refreshView();
55 | }
56 |
57 |
58 | @Override
59 | public void onViewStateRestored(Bundle savedInstanceState) {
60 | super.onViewStateRestored(savedInstanceState);
61 |
62 | if (savedInstanceState == null)
63 | return;
64 |
65 | if (listView != null)
66 | listView.loadState(savedInstanceState);
67 | }
68 |
69 | @Override
70 | public void onSaveInstanceState(Bundle outState) {
71 | super.onSaveInstanceState(outState);
72 |
73 | if (listView != null)
74 | listView.saveState(outState);
75 | }
76 |
77 | @Override
78 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
79 | inflater.inflate(R.menu.outline, menu);
80 | }
81 |
82 | @Override
83 | public void onPrepareOptionsMenu(Menu menu) {
84 | super.onPrepareOptionsMenu(menu);
85 |
86 | if (listView == null || listView.getAdapter().isEmpty()) {
87 | menu.findItem(R.id.delete).setEnabled(false);
88 | menu.findItem(R.id.add_child).setEnabled(false);
89 | } else {
90 | menu.findItem(R.id.delete).setEnabled(true);
91 | menu.findItem(R.id.add_child).setEnabled(true);
92 | }
93 | }
94 |
95 | @Override
96 | public boolean onOptionsItemSelected(MenuItem item) {
97 | int position = listView.getCheckedItemPosition();
98 | switch(item.getItemId()) {
99 | case android.R.id.home:
100 | if (listView != null)
101 | listView.collapseCurrent();
102 | break;
103 |
104 | case R.id.add_child:
105 | showAddDialog(position);
106 | break;
107 |
108 | case R.id.delete:
109 | showDeleteDialog(position);
110 | break;
111 |
112 | default:
113 | return super.onOptionsItemSelected(item);
114 | }
115 |
116 | return true;
117 | }
118 |
119 | private void showDeleteDialog(int position) {
120 | if (position < 0)
121 | return;
122 |
123 | OrgNode node = (OrgNode) listView.getAdapter().getItem(position);
124 | OrgNodeRepository.delete(node);
125 | Application.getBus().post(new DataUpdatedEvent());
126 | }
127 |
128 | private void showAddDialog(int position) {
129 | if (position < 0)
130 | return;
131 |
132 | OrgNode node = (OrgNode) listView.getAdapter().getItem(position);
133 | BaseEditFragment fragment = BaseEditFragment.getAddFragment(node);
134 | fragment.show(getActivity());
135 | }
136 |
137 |
138 | @Subscribe
139 | public void refreshView(DataUpdatedEvent event) {
140 | refreshView();
141 | }
142 | protected void refreshView() {
143 | listView.refresh();
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/layout/fragment_outline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
13 |
14 |
21 |
22 |
31 |
32 |
40 |
41 |
47 |
48 |
53 |
54 |
60 |
61 |
69 |
70 |
77 |
78 |
79 |
80 |
86 |
87 |
95 |
96 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/synchronizer/parser/OrgRepository.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.synchronizer.parser;
2 |
3 | import android.text.TextUtils;
4 |
5 | import com.hdweiss.morgand.data.dao.OrgFile;
6 | import com.hdweiss.morgand.data.dao.OrgNode;
7 | import com.hdweiss.morgand.data.dao.OrgNodeRepository;
8 | import com.j256.ormlite.dao.RuntimeExceptionDao;
9 | import com.j256.ormlite.stmt.Where;
10 |
11 | import java.io.File;
12 | import java.io.FileFilter;
13 | import java.sql.SQLException;
14 | import java.util.ArrayList;
15 |
16 | public class OrgRepository {
17 |
18 | private String path;
19 | private OrgNodeRepository nodeDao;
20 | private RuntimeExceptionDao fileDao;
21 |
22 | public OrgRepository(String path) {
23 | if (TextUtils.isEmpty(path))
24 | throw new IllegalArgumentException("Path can't be empty");
25 |
26 | this.path = path;
27 | this.nodeDao = new OrgNodeRepository();
28 | this.fileDao = OrgFile.getDao();
29 | }
30 |
31 | /**
32 | * @return List of OrgFiles that have been modified. Both file and file.node need to be updated/created.
33 | */
34 | public ArrayList getModifiedFiles() {
35 | File rootFolder = new File(path);
36 |
37 | if (rootFolder.exists() == false)
38 | throw new IllegalArgumentException("Folder " + path + " does not exist");
39 |
40 | if (rootFolder.canRead() == false)
41 | throw new IllegalArgumentException("Can't parse " + path);
42 |
43 | ArrayList modifiedOrgFiles = new ArrayList();
44 | getModifiedFiles(rootFolder, null, modifiedOrgFiles);
45 | return modifiedOrgFiles;
46 | }
47 |
48 | private void getModifiedFiles(File parentFile, OrgNode parent, ArrayList modifiedOrgFiles) {
49 | for (File file : parentFile.listFiles()) {
50 | if (file.isDirectory() && file.isHidden() == false && hasOrgFiles(file)) {
51 | OrgNode directoryNode = findOrCreateDirectoryNode(file, parent);
52 | getModifiedFiles(file, directoryNode, modifiedOrgFiles);
53 | } else if (file.isFile() && file.getName().endsWith(".org")) {
54 | OrgFile orgFile = getOrCreateOrgFile(file, parent);
55 | if (orgFile != null)
56 | modifiedOrgFiles.add(orgFile);
57 | }
58 | }
59 | }
60 |
61 |
62 | private boolean hasOrgFiles(File file) {
63 | if (file.listFiles() == null)
64 | return false;
65 |
66 | for(File subFile: file.listFiles()) {
67 | if (file.isDirectory()) {
68 | if (hasOrgFiles(subFile))
69 | return true;
70 | }
71 | }
72 |
73 | File[] files = file.listFiles(new FileFilter() {
74 | @Override
75 | public boolean accept(File file) {
76 | return file.isFile() && file.getName().endsWith(".org");
77 | }
78 | });
79 |
80 | return files.length > 0;
81 | }
82 |
83 | private OrgNode findOrCreateDirectoryNode(File file, OrgNode parent) {
84 | try {
85 |
86 | Where query = nodeDao.queryBuilder().where();
87 | if (parent != null)
88 | query.eq(OrgNode.PARENT_FIELD_NAME, parent).and();
89 | else
90 | query.isNull(OrgNode.PARENT_FIELD_NAME).and();
91 | query.eq(OrgNode.TITLE_FIELD_NAME, file.getName());
92 | OrgNode node = query.queryForFirst();
93 | if (node != null)
94 | return node;
95 | } catch (SQLException e) {
96 | e.printStackTrace();
97 | }
98 |
99 | OrgNode node = new OrgNode();
100 | node.type = OrgNode.Type.Directory;
101 | node.parent = parent;
102 | node.title = file.getName();
103 | node.level = 0;
104 | nodeDao.create(node);
105 | return node;
106 | }
107 |
108 | private OrgFile getOrCreateOrgFile(File file, OrgNode parent) {
109 | OrgFile orgFile = fileDao.queryForId(file.getAbsolutePath());
110 |
111 | if (orgFile == null) {
112 | orgFile = new OrgFile();
113 | orgFile.path = file.getAbsolutePath();
114 | } else {
115 | if (file.lastModified() <= orgFile.lastModified)
116 | return null;
117 |
118 | try {
119 | nodeDao.delete(orgFile);
120 | } catch (SQLException e) {
121 | e.printStackTrace();
122 | }
123 | }
124 |
125 | orgFile.node = getRootNode(file, orgFile, parent);
126 | return orgFile;
127 | }
128 |
129 | private OrgNode getRootNode(File file, OrgFile orgFile, OrgNode parent) {
130 | OrgNode rootNode = new OrgNode();
131 | rootNode.type = OrgNode.Type.File;
132 | rootNode.title = file.getName();
133 | rootNode.file = orgFile;
134 | rootNode.parent = parent;
135 | rootNode.level = 0;
136 | return rootNode;
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/res/values/strings_settings.xml:
--------------------------------------------------------------------------------
1 |
2 | Settings
3 |
4 | General
5 | Advanced
6 |
7 |
8 | General
9 | Version
10 |
11 |
12 | Interface
13 | Outline
14 |
15 | Show drawers
16 | Show drawers in outline
17 |
18 | Show settings
19 | Show file settings in outline
20 |
21 | Allow subtree expansion
22 | Allow outline to mimic org-mode\'s visibility cycling of headlines
23 |
24 |
25 |
26 | Data & sync
27 | Sync frequency
28 | Background sync
29 | Automatically synchronize in background
30 | Sync mode
31 | Sync with Wifi only
32 | Only try to synchronize when Wireless is up
33 |
34 | Active todo keywords
35 | Inactive todo keywords
36 | Priorities
37 |
38 |
39 | - 1 min
40 | - 5 min
41 | - 10 min
42 | - 15 min
43 | - 30 min
44 | - 45 min
45 | - 1 hour
46 | - 3 hours
47 | - 6 hours
48 | - 12 hours
49 |
50 |
51 |
52 |
53 | Git
54 | Authentication
55 | Git Url
56 | Git branch
57 | Git commit author
58 | Git commit email
59 | Private ssh key file
60 | Git (or key) password
61 | Git Username
62 | Git local repository path
63 | Conflict merge strategy
64 |
65 | - Prefer remote changes (theirs)
66 | - Prefer local changes (ours)
67 |
68 |
69 |
70 | Calendar
71 | Display
72 | Clear phone calendar
73 | Clears the phones\' calendar of all entries inserted by MobileOrg
74 | Synchronize scheduled items with the system calendar
75 | Synchronize with calendar
76 | Choose calendar MobileOrg will use
77 | Calendar name
78 | Assimilate calendar entries not inserted by MobileOrg and add them to capture file. EXPERIMENTAL!
79 | Assimilate calendar entries
80 | Delete entries that have been assimilated from the calendar
81 | Delete on assimilation
82 | Clear phone calendar
83 | Are you sure you want to clear the phones\' calendar?
84 | Add reminders for scheduled items to calendar
85 | Reminders
86 | Sets the interval when an alarm is triggered
87 | Reminder interval (minutes)
88 | Shows habits in the calendar
89 | Show habits
90 | Show items with done TODO keywords the calendar
91 | Show done events
92 | Show past items in the calendar
93 | Show past events
94 |
95 |
96 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/gui/edit/EditDateFragment.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.gui.edit;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.CheckBox;
8 | import android.widget.CompoundButton;
9 | import android.widget.DatePicker;
10 | import android.widget.TimePicker;
11 |
12 | import com.hdweiss.morgand.R;
13 | import com.hdweiss.morgand.data.dao.OrgNode;
14 |
15 | import java.util.Calendar;
16 |
17 | public class EditDateFragment extends BaseEditFragment {
18 |
19 | private DatePicker datePicker;
20 | private CheckBox timeStartCheckbox;
21 | private TimePicker timeStartPicker;
22 | private CheckBox timeEndCheckbox;
23 | private TimePicker timeEndPicker;
24 |
25 | @Override
26 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
27 | View view = inflater.inflate(R.layout.edit_date_fragment, container, false);
28 |
29 | datePicker = (DatePicker) view.findViewById(R.id.date);
30 | datePicker.setCalendarViewShown(false);
31 | datePicker.setSpinnersShown(true);
32 |
33 | timeStartPicker = (TimePicker) view.findViewById(R.id.time_start);
34 | timeStartPicker.setIs24HourView(true);
35 | timeStartCheckbox = (CheckBox) view.findViewById(R.id.time_start_check);
36 |
37 | timeEndPicker = (TimePicker) view.findViewById(R.id.time_end);
38 | timeEndPicker.setIs24HourView(true);
39 | timeEndCheckbox = (CheckBox) view.findViewById(R.id.time_end_check);
40 |
41 | timeStartCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
42 | @Override
43 | public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
44 | if (checked) {
45 | timeStartPicker.setVisibility(View.VISIBLE);
46 | timeEndCheckbox.setEnabled(true);
47 | }
48 | else {
49 | timeStartPicker.setVisibility(View.INVISIBLE);
50 | timeEndCheckbox.setChecked(false);
51 | timeEndCheckbox.setEnabled(false);
52 | }
53 | }
54 | });
55 |
56 | timeEndCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
57 | @Override
58 | public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
59 | if (checked)
60 | timeEndPicker.setVisibility(View.VISIBLE);
61 | else
62 | timeEndPicker.setVisibility(View.INVISIBLE);
63 | }
64 | });
65 |
66 | return view;
67 | }
68 |
69 | @Override
70 | public void onViewCreated(View view, Bundle savedInstanceState) {
71 | super.onViewCreated(view, savedInstanceState);
72 |
73 |
74 | // OrgNodeTimeDate timeDate = null; // TODO Complete
75 | controller.getNode().getTitle();
76 | // if (timeDate != null)
77 | // type = timeDate.type;
78 | // else
79 | // type = OrgNodeTimeDate.TYPE.Scheduled;
80 |
81 | // getDialog().setTitle(getResources().getString(R.string.action_set_time) + " - " + type.toString());
82 |
83 | // if (timeDate != null)
84 | // populateView(timeDate);
85 | // else
86 | // populateView();
87 | }
88 |
89 | private void populateView() {
90 | Calendar c = Calendar.getInstance();
91 | datePicker.updateDate(c.get(Calendar.YEAR) - 1, c.get(Calendar.MONTH) - 1, c.get(Calendar.DAY_OF_MONTH) - 1);
92 |
93 | timeStartCheckbox.setChecked(false);
94 | timeStartPicker.setVisibility(View.INVISIBLE);
95 |
96 | timeEndCheckbox.setChecked(false);
97 | timeEndCheckbox.setEnabled(false);
98 | timeEndPicker.setVisibility(View.INVISIBLE);
99 | }
100 |
101 | // private void populateView(OrgNodeTimeDate timeDate) {
102 | // if (timeDate.year >= 0 && timeDate.monthOfYear >= 0 && timeDate.dayOfMonth >= 0)
103 | // datePicker.updateDate(timeDate.year - 1, timeDate.monthOfYear - 1, timeDate.dayOfMonth - 1);
104 | //
105 | // if (timeDate.startTimeOfDay >= 0 && timeDate.startMinute >= 0) {
106 | // timeStartPicker.setCurrentHour(timeDate.startTimeOfDay);
107 | // timeStartPicker.setCurrentMinute(timeDate.startMinute);
108 | // timeStartCheckbox.setChecked(true);
109 | // } else
110 | // timeStartCheckbox.setChecked(false);
111 | //
112 | // if (timeDate.endTimeOfDay >= 0 && timeDate.endMinute >= 0) {
113 | // timeEndPicker.setCurrentHour(timeDate.endTimeOfDay);
114 | // timeEndPicker.setCurrentMinute(timeDate.endMinute);
115 | // timeEndCheckbox.setChecked(true);
116 | // } else
117 | // timeEndCheckbox.setChecked(false);
118 | // }
119 | //
120 | //
121 | // private OrgNodeTimeDate getTimeDate() {
122 | // OrgNodeTimeDate resultTimeDate = new OrgNodeTimeDate(type);
123 | //
124 | // resultTimeDate.year = datePicker.getYear() + 1;
125 | // resultTimeDate.monthOfYear = datePicker.getMonth() + 1;
126 | // resultTimeDate.dayOfMonth = datePicker.getDayOfMonth() + 1;
127 | //
128 | // if (timeStartCheckbox.isChecked()) {
129 | // resultTimeDate.startTimeOfDay = timeStartPicker.getCurrentHour();
130 | // resultTimeDate.startMinute = timeStartPicker.getCurrentMinute();
131 | //
132 | // if (timeEndCheckbox.isChecked()) {
133 | // resultTimeDate.endTimeOfDay = timeEndPicker.getCurrentHour();
134 | // resultTimeDate.endMinute = timeEndPicker.getCurrentMinute();
135 | // }
136 | // }
137 | //
138 | // return resultTimeDate;
139 | // }
140 |
141 | @Override
142 | public OrgNode getEditedNode() {
143 | return controller.getNode();
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/gui/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.gui;
2 |
3 | import android.app.ActionBar;
4 | import android.content.Intent;
5 | import android.net.Uri;
6 | import android.os.Bundle;
7 | import android.support.v4.app.FragmentActivity;
8 | import android.support.v4.view.ViewPager;
9 | import android.view.Menu;
10 | import android.view.MenuItem;
11 | import android.view.View;
12 | import android.view.Window;
13 | import android.widget.Toast;
14 |
15 | import com.hdweiss.morgand.Application;
16 | import com.hdweiss.morgand.R;
17 | import com.hdweiss.morgand.data.dao.OrgFile;
18 | import com.hdweiss.morgand.data.dao.OrgNodeRepository;
19 | import com.hdweiss.morgand.events.DataUpdatedEvent;
20 | import com.hdweiss.morgand.events.SyncEvent;
21 | import com.hdweiss.morgand.settings.PreferenceUtils;
22 | import com.hdweiss.morgand.settings.SettingsActivity;
23 | import com.hdweiss.morgand.synchronizer.calendar.CalendarWrapper;
24 | import com.hdweiss.morgand.synchronizer.writer.SyncWriterTask;
25 | import com.squareup.otto.Subscribe;
26 |
27 | public class MainActivity extends FragmentActivity implements ActionBar.TabListener {
28 |
29 | private MainPagerAdapter mSectionsPagerAdapter;
30 | private ViewPager mViewPager;
31 |
32 | @Override
33 | protected void onCreate(Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 |
36 | requestWindowFeature(Window.FEATURE_PROGRESS);
37 | setContentView(R.layout.activity_main);
38 | ActionBar actionBar = initActionbar();
39 | initViewPager(actionBar);
40 | }
41 |
42 | private ActionBar initActionbar() {
43 | final ActionBar actionBar = getActionBar();
44 | actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
45 | //actionBar.setDisplayShowTitleEnabled(false);
46 | actionBar.setHomeButtonEnabled(true);
47 | //actionBar.setDisplayHomeAsUpEnabled(false);
48 | return actionBar;
49 | }
50 |
51 | private void initViewPager(final ActionBar actionBar) {
52 | mSectionsPagerAdapter = new MainPagerAdapter(getSupportFragmentManager());
53 | mViewPager = (ViewPager) findViewById(R.id.pager);
54 | mViewPager.setAdapter(mSectionsPagerAdapter);
55 |
56 | mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
57 | @Override
58 | public void onPageSelected(int position) {
59 | actionBar.setSelectedNavigationItem(position);
60 | }
61 | });
62 |
63 | for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
64 | actionBar.addTab(
65 | actionBar.newTab()
66 | .setText(mSectionsPagerAdapter.getPageTitle(i))
67 | .setTabListener(this));
68 | }
69 | }
70 |
71 |
72 | @Override
73 | protected void onResume() {
74 | super.onResume();
75 | Application.getBus().register(this);
76 | }
77 |
78 | @Override
79 | protected void onPause() {
80 | Application.getBus().unregister(this);
81 | super.onPause();
82 | }
83 |
84 |
85 | @Override
86 | public void onTabSelected(ActionBar.Tab tab, android.app.FragmentTransaction fragmentTransaction) {
87 | mViewPager.setCurrentItem(tab.getPosition());
88 | }
89 |
90 | @Override
91 | public void onTabUnselected(ActionBar.Tab tab, android.app.FragmentTransaction fragmentTransaction) {
92 | }
93 |
94 | @Override
95 | public void onTabReselected(ActionBar.Tab tab, android.app.FragmentTransaction fragmentTransaction) {
96 | }
97 |
98 |
99 | @Override
100 | public boolean onCreateOptionsMenu(Menu menu) {
101 | getMenuInflater().inflate(R.menu.main, menu);
102 | return true;
103 | }
104 |
105 | @Override
106 | public boolean onOptionsItemSelected(MenuItem item) {
107 | switch (item.getItemId()) {
108 | case R.id.action_settings:
109 | Intent intent = new Intent(this, SettingsActivity.class);
110 | startActivity(intent);
111 | break;
112 |
113 | case R.id.action_sync:
114 | SyncWriterTask synchronizerTask = new SyncWriterTask(this);
115 | synchronizerTask.execute();
116 | break;
117 |
118 | case R.id.action_clearDB:
119 | OrgNodeRepository.deleteAll();
120 | OrgFile.deleteAll();
121 | Application.getBus().post(new DataUpdatedEvent());
122 | new CalendarWrapper(this).deleteEntries();
123 | break;
124 | }
125 | return super.onOptionsItemSelected(item);
126 | }
127 |
128 |
129 | @Subscribe
130 | public void updateSyncProgress(SyncEvent event) {
131 | if (event.state == SyncEvent.State.Done) {
132 | setProgress(Window.PROGRESS_END);
133 | return;
134 | }
135 |
136 | switch (event.state) {
137 | case Intermediate:
138 | setProgressBarVisibility(true);
139 | setProgressBarIndeterminate(true);
140 | break;
141 |
142 | case Progress:
143 | setProgressBarIndeterminate(false);
144 | int progress = (Window.PROGRESS_END - Window.PROGRESS_START) / 100 * event.progress;
145 | setProgress(progress);
146 | break;
147 |
148 | case SecondaryProgress:
149 | setProgressBarIndeterminate(false);
150 | int secondaryProgress = (Window.PROGRESS_END - Window.PROGRESS_START) / 100 * event.progress;
151 | setSecondaryProgress(secondaryProgress);
152 | break;
153 | }
154 | }
155 |
156 | public void runShowWiki(View view) {
157 | Intent intent = new Intent(Intent.ACTION_VIEW,
158 | Uri.parse("https://github.com/hdweiss/mOrgAnd.wiki"));
159 | startActivity(intent);
160 | }
161 |
162 | public void runDownloadWiki(View view) {
163 | Toast.makeText(this, R.string.action_downloadwiki, Toast.LENGTH_SHORT).show();
164 | PreferenceUtils.setupGitToWiki();
165 | new SyncWriterTask(this).execute();
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/synchronizer/calendar/SyncCalendarTask.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.synchronizer.calendar;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.database.Cursor;
6 | import android.preference.PreferenceManager;
7 | import android.text.TextUtils;
8 | import android.util.Log;
9 |
10 | import com.hdweiss.morgand.Application;
11 | import com.hdweiss.morgand.data.OrgCalendarEntry;
12 | import com.hdweiss.morgand.data.dao.OrgNode;
13 | import com.hdweiss.morgand.data.dao.OrgNodeRepository;
14 | import com.hdweiss.morgand.events.DataUpdatedEvent;
15 | import com.hdweiss.morgand.settings.PreferenceUtils;
16 | import com.hdweiss.morgand.utils.MultiMap;
17 | import com.hdweiss.morgand.utils.SafeAsyncTask;
18 |
19 | import java.util.HashSet;
20 | import java.util.List;
21 |
22 | public class SyncCalendarTask extends SafeAsyncTask {
23 |
24 | private CalendarWrapper calendarWrapper;
25 |
26 | private HashSet inactiveTodoKeywords = new HashSet();
27 | private boolean showDone = true;
28 | private boolean showPast = true;
29 | private boolean showHabits = true;
30 | private boolean pullEnabled = false;
31 | private boolean pullDelete = false;
32 |
33 | private int inserted = 0;
34 | private int deleted = 0;
35 | private int unchanged = 0;
36 |
37 | public SyncCalendarTask(Context context) {
38 | super(context, ReportMode.Log);
39 |
40 | this.calendarWrapper = new CalendarWrapper(context);
41 | refreshPreferences();
42 | }
43 |
44 | @Override
45 | protected Void safeDoInBackground(String... files) throws Exception {
46 | Log.d("Calendar", "Started synchronization");
47 | if (files.length == 0) {
48 | Log.d("Calendar", "No modified files");
49 | }
50 |
51 | for(String file: files)
52 | syncFileSchedule(file);
53 |
54 | if (pullEnabled) // TODO complete assimilate Calendar (implement function that delivers default capture node)
55 | ;//assimilateCalendar();
56 |
57 | Log.d("Calendar", "Ended synchronization");
58 | return null;
59 | }
60 |
61 | @Override
62 | protected void onProgressUpdate(DataUpdatedEvent... events) {
63 | for(DataUpdatedEvent event: events)
64 | Application.getBus().post(event);
65 | }
66 |
67 | private void syncFileSchedule(String filename) {
68 | inserted = 0;
69 | deleted = 0;
70 | unchanged = 0;
71 |
72 | MultiMap entries = getCalendarEntries(filename);
73 | List nodes = OrgNodeRepository.getScheduledNodes(filename, showHabits);
74 |
75 | Log.d("Calendar", filename + " has " + nodes.size() + " calendar entries");
76 |
77 | for(OrgNode node: nodes) {
78 | for(OrgCalendarEntry date: node.getOrgNodeDates()) {
79 | if (shouldInsertEntry(date, node))
80 | createOrUpdateEntry(entries, date, filename, node);
81 | }
82 | }
83 |
84 | removeCalendarEntries(entries);
85 |
86 | Log.d("Calendar", "Calendar (" + filename + ") Inserted: " + inserted
87 | + " and deleted: " + deleted + ", unchanged: " + unchanged);
88 | }
89 |
90 | private void createOrUpdateEntry(MultiMap entries,
91 | OrgCalendarEntry date, String filename, OrgNode node) {
92 | CalendarEntry insertedEntry = entries.findValue(date.beginTime, date);
93 |
94 | if (insertedEntry != null && insertedEntry.title.equals(date.getCalendarTitle())) {
95 | entries.remove(date.beginTime, insertedEntry);
96 | unchanged++;
97 | } else {
98 | calendarWrapper.insertEntry(date, node.getBody(), filename,
99 | node.getProperty("LOCATION"), node.getProperty("BUSY"));
100 | inserted++;
101 | }
102 | }
103 |
104 | private boolean shouldInsertEntry(OrgCalendarEntry date, OrgNode node) {
105 | String todo = node.getTodo();
106 | if (this.showDone == false && TextUtils.isEmpty(todo) == false && inactiveTodoKeywords.contains(todo))
107 | return false;
108 |
109 | if (this.showPast == false && date.isInPast())
110 | return false;
111 |
112 | if (this.showHabits == false && "habit".equals(node.getProperty("STYLE")))
113 | return false;
114 |
115 | return true;
116 | }
117 |
118 | private MultiMap getCalendarEntries(String filename) {
119 | Cursor query = calendarWrapper.getCalendarCursor(filename);
120 | CalendarEntriesParser entriesParser = new CalendarEntriesParser(query);
121 |
122 | MultiMap map = new MultiMap();
123 | while (query.isAfterLast() == false) {
124 | CalendarEntry entry = entriesParser.getEntryFromCursor(query);
125 | map.put(entry.dtStart, entry);
126 |
127 | query.moveToNext();
128 | }
129 |
130 | query.close();
131 | return map;
132 | }
133 |
134 | private void removeCalendarEntries(MultiMap entries) {
135 | for (Long entryKey : entries.keySet()) {
136 | for (CalendarEntry entry : entries.get(entryKey)) {
137 | calendarWrapper.deleteEntry(entry);
138 | deleted++;
139 | }
140 | }
141 | }
142 |
143 | private void assimilateCalendar() {
144 | Cursor query = calendarWrapper.getUnassimilatedCalendarCursor();
145 |
146 | CalendarEntriesParser entriesParser = new CalendarEntriesParser(query);
147 |
148 | while(query.isAfterLast() == false) {
149 | CalendarEntry entry = entriesParser.getEntryFromCursor(query);
150 |
151 | OrgNode captureNode = OrgNodeRepository.getDefaultCaptureNode();
152 | entry.writeToOrgNodes(captureNode);
153 |
154 | if (this.pullDelete)
155 | calendarWrapper.deleteEntry(entry);
156 |
157 | query.moveToNext();
158 | }
159 |
160 | query.close();
161 | publishProgress(new DataUpdatedEvent());
162 | }
163 |
164 | private void refreshPreferences() {
165 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
166 | this.pullEnabled = sharedPreferences.getBoolean("calendar_pull", false);
167 | this.pullDelete = sharedPreferences.getBoolean("calendar_pull_delete", false);
168 | this.showDone = sharedPreferences.getBoolean("calendar_show_done", true);
169 | this.showPast = sharedPreferences.getBoolean("calendar_show_past", true);
170 | this.showHabits = sharedPreferences.getBoolean("calendar_habits", true);
171 | this.inactiveTodoKeywords = PreferenceUtils.getInactiveTodoKeywords();
172 | this.calendarWrapper.refreshPreferences();
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/gui/outline/OutlineListView.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.gui.outline;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.os.Bundle;
6 | import android.preference.PreferenceManager;
7 | import android.util.AttributeSet;
8 | import android.view.ActionMode;
9 | import android.view.View;
10 | import android.widget.AdapterView;
11 | import android.widget.ListView;
12 |
13 | import com.hdweiss.morgand.data.OrgNodeUtils;
14 | import com.hdweiss.morgand.data.dao.OrgNode;
15 | import com.hdweiss.morgand.gui.edit.BaseEditFragment;
16 | import com.hdweiss.morgand.settings.PreferenceUtils;
17 |
18 | import java.util.ArrayList;
19 | import java.util.List;
20 |
21 | public class OutlineListView extends ListView {
22 |
23 | private final static String OUTLINE_NODES = "nodes";
24 | private final static String OUTLINE_LEVELS = "levels";
25 | private final static String OUTLINE_EXPANDED = "expanded";
26 | private final static String OUTLINE_CHECKED_POS = "selection";
27 | private final static String OUTLINE_SCROLL_POS = "scrollPosition";
28 |
29 | private Context context;
30 | private Activity activity;
31 |
32 | private OutlineAdapter adapter;
33 | private OutlineActionMode actionMode;
34 | private ActionMode activeActionMode = null;
35 |
36 | private int lastPositionClicked = -1;
37 |
38 | public OutlineListView(Context context, AttributeSet atts) {
39 | super(context, atts);
40 | this.context = activity;
41 | setChoiceMode(ListView.CHOICE_MODE_SINGLE);
42 | setOnItemClickListener(outlineClickListener);
43 | setOnItemLongClickListener(outlineLongClickListener);
44 | this.actionMode = new OutlineActionMode(context);
45 | setAdapter(new OutlineAdapter(context));
46 | }
47 |
48 | public void setAdapter(OutlineAdapter adapter) {
49 | this.adapter = adapter;
50 | super.setAdapter(adapter);
51 | }
52 |
53 |
54 | public void setActivity(Activity activity) {
55 | this.activity = activity;
56 | this.context = activity;
57 | }
58 |
59 |
60 | public void saveState(Bundle outState) {
61 | outState.putLongArray(OUTLINE_NODES, adapter.getNodeState());
62 | outState.putIntegerArrayList(OUTLINE_LEVELS, adapter.getLevelState());
63 | outState.putBooleanArray(OUTLINE_EXPANDED, adapter.getExpandedState());
64 | outState.putInt(OUTLINE_CHECKED_POS, getCheckedItemPosition());
65 | outState.putInt(OUTLINE_SCROLL_POS, getFirstVisiblePosition());
66 | }
67 |
68 | public void loadState(Bundle savedInstanceState) {
69 | long[] state = savedInstanceState.getLongArray(OUTLINE_NODES);
70 | ArrayList levels = savedInstanceState.getIntegerArrayList(OUTLINE_LEVELS);
71 | boolean[] expanded = savedInstanceState.getBooleanArray(OUTLINE_EXPANDED);
72 |
73 | if(state != null) {
74 | try {
75 | this.adapter.setState(state, levels, expanded);
76 | } catch (IllegalStateException ex) {
77 | this.adapter.init();
78 | }
79 | }
80 |
81 | int checkedPos= savedInstanceState.getInt(OUTLINE_CHECKED_POS, 0);
82 | setItemChecked(checkedPos, true);
83 |
84 | int scrollPos = savedInstanceState.getInt(OUTLINE_SCROLL_POS, 0);
85 | setSelection(scrollPos);
86 | }
87 |
88 |
89 | public void refresh() {
90 | int position = getFirstVisiblePosition();
91 | this.adapter.refresh();
92 | setSelection(position);
93 | }
94 |
95 | public long getCheckedNodeId() {
96 | if(getCheckedItemPosition() == ListView.INVALID_POSITION)
97 | return -1;
98 | else {
99 | int position = getCheckedItemPosition();
100 | return adapter.getItemId(position);
101 | }
102 | }
103 |
104 | public void setData(List nodes) {
105 | adapter.clear();
106 | if (nodes.size() > 0)
107 | adapter.insertAll(nodes, 0);
108 | }
109 |
110 | private OnItemClickListener outlineClickListener = new OnItemClickListener() {
111 | @Override
112 | public void onItemClick(AdapterView> parent, View v, int position,
113 | long id) {
114 | if(activeActionMode != null)
115 | activeActionMode.finish();
116 |
117 | OrgNode node = adapter.getItem(position);
118 | if(node.getDisplayChildren().size() > 0) {
119 | if (PreferenceUtils.outlineExpandAll()) {
120 | boolean doubleClicked = lastPositionClicked == position;
121 | boolean collapsed = adapter.collapseExpandExpandAll(position, doubleClicked);
122 | if (collapsed) {
123 | lastPositionClicked = -1;
124 | return;
125 | }
126 | }
127 | else
128 | adapter.collapseExpand(position);
129 | }
130 | else {
131 | boolean viewOnClick = PreferenceManager
132 | .getDefaultSharedPreferences(context).getBoolean(
133 | "viewOnClick", false);
134 |
135 | if (node.type == OrgNode.Type.Checkbox) {
136 | OrgNodeUtils.toggleCheckbox(node);
137 | adapter.notifyDataSetInvalidated();
138 | return;
139 | }
140 |
141 |
142 | if (viewOnClick)
143 | OutlineActionMode.runViewNodeActivity(node.Id, context);
144 | else
145 | OutlineActionMode.runEditNodeActivity(node.Id, context);
146 | //setParentChecked(position);
147 | }
148 |
149 | lastPositionClicked = position;
150 | }
151 | };
152 |
153 | private OnItemLongClickListener outlineLongClickListener = new OnItemLongClickListener() {
154 | @Override
155 | public boolean onItemLongClick(AdapterView> parent, View v, int position,
156 | long id) {
157 |
158 | showEditDialog(position);
159 | // if(activity != null) {
160 | // actionMode.initActionMode(OutlineListView.this, position);
161 | // activeActionMode = activity.startActionMode(actionMode);
162 | // }
163 | return true;
164 | }
165 | };
166 |
167 | private void showEditDialog(int position) {
168 | if (position < 0)
169 | return;
170 |
171 | OrgNode node = (OrgNode) getAdapter().getItem(position);
172 | if (node == null)
173 | return;
174 |
175 | BaseEditFragment fragment = BaseEditFragment.getEditFragment(node);
176 | fragment.show(activity);
177 | }
178 |
179 | @SuppressWarnings("unused")
180 | private void setParentChecked(int position) {
181 | int parentPos = adapter.findParent(position);
182 | if(parentPos >= 0)
183 | setItemChecked(parentPos, true);
184 | }
185 |
186 | public void collapseCurrent() {
187 | int position = getCheckedItemPosition();
188 |
189 | if (position == ListView.INVALID_POSITION)
190 | return;
191 |
192 | if (adapter.getExpanded(position)) // Item is expanded, collapse it
193 | adapter.collapseExpand(position);
194 | else {
195 | if(adapter.getLevel(position) == 0) { // Top level, collapse all entries
196 | adapter.collapseAll();
197 | setItemChecked(position, false);
198 | } else { // Collapse parent
199 | int parent = adapter.findParent(position);
200 |
201 | if (parent >= 0) {
202 | adapter.collapseExpand(parent);
203 | setItemChecked(parent, true);
204 | }
205 | }
206 | }
207 |
208 | ensureCheckedItemVisible();
209 | }
210 |
211 | public void ensureCheckedItemVisible() {
212 | int position = getCheckedItemPosition();
213 | if(position == ListView.INVALID_POSITION)
214 | return;
215 |
216 | if(!(getLastVisiblePosition() >= position && getFirstVisiblePosition() <= position))
217 | setSelection(position - 2);
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/gui/outline/OutlineAdapter.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.gui.outline;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.ArrayAdapter;
7 |
8 | import com.hdweiss.morgand.R;
9 | import com.hdweiss.morgand.data.dao.OrgNode;
10 | import com.hdweiss.morgand.data.dao.OrgNodeRepository;
11 | import com.hdweiss.morgand.gui.theme.DefaultTheme;
12 | import com.hdweiss.morgand.utils.Utils;
13 |
14 | import java.util.ArrayList;
15 | import java.util.Collection;
16 | import java.util.Collections;
17 |
18 | public class OutlineAdapter extends ArrayAdapter {
19 |
20 | private ArrayList expanded = new ArrayList();
21 | private ArrayList level = new ArrayList();
22 |
23 | private DefaultTheme theme;
24 |
25 | private boolean agendaMode = false;
26 |
27 | public OutlineAdapter(Context context) {
28 | super(context, R.layout.outline_item);
29 |
30 | this.theme = DefaultTheme.getTheme(context);
31 | init();
32 | }
33 |
34 | public void init() {
35 | clear();
36 |
37 | for (OrgNode node : OrgNodeRepository.getRootNodes())
38 | add(node);
39 |
40 | notifyDataSetInvalidated();
41 | }
42 |
43 |
44 | public long[] getNodeState() {
45 | int count = getCount();
46 | long[] state = new long[count];
47 |
48 | for(int i = 0; i < count; i++)
49 | state[i] = getItem(i).Id;
50 |
51 | return state;
52 | }
53 |
54 | public ArrayList getLevelState() {
55 | return this.level;
56 | }
57 |
58 | public boolean[] getExpandedState() {
59 | return Utils.toPrimitiveArray(this.expanded);
60 | }
61 |
62 | public void setState(long[] state, ArrayList levels, boolean[] expanded) {
63 | clear();
64 |
65 | for(int i = 0; i < state.length; i++) {
66 | try {
67 | OrgNode node = OrgNodeRepository.queryForId((int) state[i]);
68 | if (node == null)
69 | throw new IllegalStateException("Give OutlineAdapter state is invalid, node with id " + state[i] + " not found");
70 |
71 | add(node);
72 | } catch(Exception ex) {}
73 | }
74 |
75 | this.expanded.clear();
76 | for(boolean expand: expanded)
77 | this.expanded.add(expand);
78 | this.level = levels;
79 | }
80 |
81 | public void refresh() {
82 | ArrayList expandedNodeIds = new ArrayList();
83 | int size = this.expanded.size();
84 | for(int i = 0; i < size; i++) {
85 | if(this.expanded.get(i))
86 | expandedNodeIds.add(getItemId(i));
87 | }
88 |
89 | init();
90 |
91 | expandNodes(expandedNodeIds);
92 | }
93 |
94 | private void expandNodes(ArrayList nodeIds) {
95 | while (nodeIds.size() != 0) {
96 | Long nodeId = nodeIds.get(0);
97 | for (int nodesPosition = 0; nodesPosition < getCount(); nodesPosition++) {
98 | if (getItemId(nodesPosition) == nodeId) {
99 | expand(nodesPosition);
100 | break;
101 | }
102 | }
103 | nodeIds.remove(0);
104 | }
105 | }
106 |
107 | @Override
108 | public View getView(int position, View convertView, ViewGroup parent) {
109 | OutlineItemView outlineItemView = (OutlineItemView) convertView;
110 | if (convertView == null)
111 | outlineItemView = new OutlineItemView(getContext());
112 |
113 | outlineItemView.setAgendaMode(agendaMode);
114 |
115 | OrgNode node = getItem(position);
116 |
117 | if (node != null)
118 | outlineItemView.setup(node, getExpanded(position), getLevel(position), theme);
119 |
120 | return outlineItemView;
121 | }
122 |
123 | public void setAgendaMode(boolean agendaMode) {
124 | this.agendaMode = agendaMode;
125 | }
126 |
127 | @Override
128 | public void clear() {
129 | super.clear();
130 | this.expanded.clear();
131 | this.level.clear();
132 | }
133 |
134 | @Override
135 | public void add(OrgNode node) {
136 | super.add(node);
137 | this.expanded.add(false);
138 | this.level.add(0);
139 | }
140 |
141 | @Override
142 | public void insert(OrgNode node, int index) {
143 | super.insert(node, index);
144 | this.expanded.add(index, false);
145 |
146 | int level = index > 0 ? this.level.get(index - 1) + 1 : 0;
147 | this.level.add(index, level);
148 | }
149 |
150 | public void insertAll(Collection nodes, int position) {
151 | ArrayList orgNodes = new ArrayList(nodes);
152 | Collections.reverse(orgNodes);
153 | for(OrgNode node: orgNodes)
154 | insert(node, position);
155 | notifyDataSetInvalidated();
156 | }
157 |
158 | @Override
159 | public void remove(OrgNode node) {
160 | int position = getPosition(node);
161 | this.expanded.remove(position);
162 | this.level.remove(position);
163 | super.remove(node);
164 | }
165 |
166 | public boolean getExpanded(int position) {
167 | if(position < 0 || position > this.expanded.size())
168 | return false;
169 |
170 | return this.expanded.get(position);
171 | }
172 |
173 | public int getLevel(int position) {
174 | if (position < 0 || position > this.level.size())
175 | return 0;
176 |
177 | return this.level.get(position);
178 | }
179 |
180 | public void collapseExpand(int position) {
181 | if(position >= getCount() || position >= this.expanded.size() || position < 0)
182 | return;
183 |
184 | if(this.expanded.get(position))
185 | collapse(position);
186 | else
187 | expand(position);
188 | }
189 |
190 | /**
191 | * @param doubleClicked Whether user clicked node the second time
192 | * @return true expandAll was called
193 | */
194 | public boolean collapseExpandExpandAll(int position, boolean doubleClicked) {
195 | if(position >= getCount() || position >= this.expanded.size() || position < 0)
196 | return false;
197 |
198 | if(this.expanded.get(position)) {
199 | if (doubleClicked) {
200 | expandAll(position);
201 | return true;
202 | } else {
203 | collapse(position);
204 | return false;
205 | }
206 | }
207 | else {
208 | expand(position);
209 | return false;
210 | }
211 | }
212 |
213 | public void collapse(int position) {
214 | int activePos = position + 1;
215 | while(activePos < this.expanded.size()) {
216 | if(getLevel(activePos) <= getLevel(position))
217 | break;
218 | collapse(activePos);
219 | remove(getItem(activePos));
220 | }
221 | this.expanded.set(position, false);
222 | }
223 |
224 | public void collapseAll() {
225 | for(int activePos = 0; activePos < expanded.size(); activePos++) {
226 | if (expanded.get(activePos))
227 | collapse(activePos);
228 | }
229 | }
230 |
231 |
232 | public ArrayList expand(int position) {
233 | OrgNode node = getItem(position);
234 | ArrayList children = node.getDisplayChildren();
235 | if (node.type == OrgNode.Type.Directory)
236 | Collections.sort(children, new OrgNode.OrgNodeCompare());
237 |
238 | insertAll(children, position + 1);
239 | this.expanded.set(position, true);
240 | return children;
241 | }
242 |
243 | public void expandAll(int position) {
244 | collapse(position); // TODO Hack
245 |
246 | ArrayList expandedChildren = expand(position);
247 |
248 | for(OrgNode node: expandedChildren) {
249 | int nodePosition = getPosition(node);
250 | expandAll(nodePosition);
251 | }
252 | }
253 |
254 | @Override
255 | public long getItemId(int position) {
256 | return getItem(position).Id;
257 | }
258 |
259 | public int findParent(int position) {
260 | if(position >= getCount() || position < 0)
261 | return -1;
262 |
263 | for(int activePos = position - 1; activePos >= 0; activePos--) {
264 | if(getLevel(activePos) < getLevel(position))
265 | return activePos;
266 | }
267 |
268 | return -1;
269 | }
270 | }
271 |
--------------------------------------------------------------------------------
/mOrgAnd/src/main/java/com/hdweiss/morgand/settings/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | package com.hdweiss.morgand.settings;
2 |
3 | import android.content.SharedPreferences;
4 | import android.content.pm.PackageManager;
5 | import android.os.Bundle;
6 | import android.preference.ListPreference;
7 | import android.preference.Preference;
8 | import android.preference.PreferenceActivity;
9 | import android.preference.PreferenceFragment;
10 | import android.preference.PreferenceManager;
11 |
12 | import com.hdweiss.morgand.R;
13 | import com.hdweiss.morgand.synchronizer.calendar.CalendarWrapper;
14 |
15 | import java.util.List;
16 |
17 | public class SettingsActivity extends PreferenceActivity {
18 |
19 | @Override
20 | public void onBuildHeaders(List target) {
21 | loadHeadersFromResource(R.xml.pref_headers, target);
22 | }
23 |
24 |
25 | public static class GeneralPreferenceFragment extends PreferenceFragment {
26 | @Override
27 | public void onCreate(Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 | addPreferencesFromResource(R.xml.pref_general);
30 | }
31 |
32 | @Override
33 | public void onResume() {
34 | super.onResume();
35 | try {
36 | String versionName = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0).versionName;
37 | findPreference("version").setSummary(versionName);
38 | } catch (PackageManager.NameNotFoundException ex) {
39 | }
40 | }
41 | }
42 |
43 | public static class InterfacePreferenceFragment extends PreferenceFragment {
44 | @Override
45 | public void onCreate(Bundle savedInstanceState) {
46 | super.onCreate(savedInstanceState);
47 | addPreferencesFromResource(R.xml.pref_interface);
48 | }
49 | }
50 |
51 | public static class DataSyncPreferenceFragment extends PreferenceFragment {
52 | @Override
53 | public void onCreate(Bundle savedInstanceState) {
54 | super.onCreate(savedInstanceState);
55 | addPreferencesFromResource(R.xml.pref_data_sync);
56 |
57 | bindPreferenceSummaryToValue(findPreference("sync_mode"));
58 | bindPreferenceSummaryToValue(findPreference("sync_frequency"));
59 | bindPreferenceSummaryToValue(findPreference("todo_active"));
60 | bindPreferenceSummaryToValue(findPreference("todo_inactive"));
61 | bindPreferenceSummaryToValue(findPreference("priorities"));
62 | }
63 | }
64 |
65 |
66 | public static class GitPreferenceFragment extends PreferenceFragment {
67 | @Override
68 | public void onCreate(Bundle savedInstanceState) {
69 | super.onCreate(savedInstanceState);
70 | addPreferencesFromResource(R.xml.pref_git);
71 |
72 | bindPreferenceSummaryToValue(findPreference("git_commit_author"));
73 | bindPreferenceSummaryToValue(findPreference("git_commit_email"));
74 | bindPreferenceSummaryToValue(findPreference("git_key_info"));
75 | bindPreferenceSummaryToValue(findPreference("git_username"));
76 | bindPreferenceSummaryToValue(findPreference("git_local_path"));
77 | bindPreferenceSummaryToValue(findPreference("git_merge_strategy"));
78 | bindPreferenceSummaryToValue(findPreference("git_branch"));
79 |
80 | bindPreferenceSummaryToValue(findPreference("git_url"));
81 | findPreference("git_url").setOnPreferenceChangeListener(sResetGitLocalPathListener);
82 | }
83 |
84 | @Override
85 | public void onResume() {
86 | super.onResume();
87 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
88 |
89 | // Update setting keys that are modified by starting another activity
90 | findPreference("git_local_path").setSummary(preferences.getString("git_local_path", ""));
91 | findPreference("git_key_info").setSummary(preferences.getString("git_key_info", ""));
92 | }
93 | }
94 |
95 |
96 | public static class CalendarPreferenceFragment extends PreferenceFragment {
97 | @Override
98 | public void onCreate(Bundle savedInstanceState) {
99 | super.onCreate(savedInstanceState);
100 | addPreferencesFromResource(R.xml.pref_calendar);
101 |
102 | populateCalendarNames();
103 |
104 | bindPreferenceSummaryToValue(findPreference("calendar_name"));
105 | bindPreferenceSummaryToValue(findPreference("calendar_reminder"));
106 | bindPreferenceSummaryToValue(findPreference("calendar_reminder_interval"));
107 | }
108 |
109 | private void populateCalendarNames() {
110 | try {
111 | ListPreference calendarName = (ListPreference) findPreference("calendar_name");
112 |
113 | CharSequence[] calendars = CalendarWrapper
114 | .getCalendars(getActivity());
115 |
116 | calendarName.setEntries(calendars);
117 | calendarName.setEntryValues(calendars);
118 | } catch (Exception e) {
119 | e.printStackTrace();
120 | // Don't crash because of anything in calendar
121 | }
122 | }
123 | }
124 |
125 | private static Preference.OnPreferenceChangeListener sResetGitLocalPathListener = new Preference.OnPreferenceChangeListener() {
126 | @Override
127 | public boolean onPreferenceChange(Preference preference, Object value) {
128 | preference.setSummary(value.toString());
129 |
130 | PreferenceUtils.set("git_local_path", "");
131 | preference.getPreferenceManager().findPreference("git_local_path").setSummary("");
132 |
133 | return true;
134 | }
135 | };
136 |
137 | /**
138 | * A preference value change listener that updates the preference's summary to reflect its new
139 | * value.
140 | */
141 | private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
142 | @Override
143 | public boolean onPreferenceChange(Preference preference, Object value) {
144 | String stringValue = value.toString();
145 |
146 | if (preference instanceof ListPreference) {
147 | // For list preferences, look up the correct display value in
148 | // the preference's 'entries' list.
149 | ListPreference listPreference = (ListPreference) preference;
150 | int index = listPreference.findIndexOfValue(stringValue);
151 |
152 | // Set the summary to reflect the new value.
153 | preference.setSummary(
154 | index >= 0
155 | ? listPreference.getEntries()[index]
156 | : null
157 | );
158 | } else {
159 | // For all other preferences, set the summary to the value's
160 | // simple string representation.
161 | preference.setSummary(stringValue);
162 | }
163 | return true;
164 | }
165 | };
166 |
167 | /**
168 | * Binds a preference's summary to its value. More specifically, when the preference's value is
169 | * changed, its summary (line of text below the preference title) is updated to reflect the
170 | * value. The summary is also immediately updated upon calling this method. The exact display
171 | * format is dependent on the type of preference.
172 | *
173 | * @see #sBindPreferenceSummaryToValueListener
174 | */
175 | private static void bindPreferenceSummaryToValue(Preference preference) {
176 | if (preference == null)
177 | return;
178 |
179 | // Set the listener to watch for value changes.
180 | preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
181 |
182 | // Trigger the listener immediately with the preference's
183 | // current value.
184 |
185 | if (preference.getKey().equals("calendar_reminder")) {
186 | sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
187 | PreferenceManager
188 | .getDefaultSharedPreferences(preference.getContext())
189 | .getBoolean(preference.getKey(), false)
190 | );
191 | } else {
192 | sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
193 | PreferenceManager
194 | .getDefaultSharedPreferences(preference.getContext())
195 | .getString(preference.getKey(), "")
196 | );
197 | }
198 | }
199 | }
200 |
--------------------------------------------------------------------------------