diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c47e5f92..6c3a4fc1 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -181,6 +181,7 @@
android:name=".ui.AccountActivity"
android:parentActivityName=".ui.AccountsActivity">
+
diff --git a/app/src/main/java/com/etesync/syncadapter/model/ServiceDB.java b/app/src/main/java/com/etesync/syncadapter/model/ServiceDB.java
index b9dceea8..6059b745 100644
--- a/app/src/main/java/com/etesync/syncadapter/model/ServiceDB.java
+++ b/app/src/main/java/com/etesync/syncadapter/model/ServiceDB.java
@@ -182,6 +182,12 @@ public class ServiceDB {
else
return null;
}
+
+ @Nullable
+ public Long getService(@NonNull Account account, String service) {
+ @Cleanup SQLiteDatabase db = getReadableDatabase();
+ return getService(db, account, service);
+ }
}
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/AccountActivity.java b/app/src/main/java/com/etesync/syncadapter/ui/AccountActivity.java
index f87930e0..40df4b37 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/AccountActivity.java
+++ b/app/src/main/java/com/etesync/syncadapter/ui/AccountActivity.java
@@ -50,12 +50,6 @@ import android.widget.PopupMenu;
import android.widget.ProgressBar;
import android.widget.TextView;
-import java.io.IOException;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.logging.Level;
-
-import at.bitfire.cert4android.CustomCertManager;
import com.etesync.syncadapter.AccountUpdateService;
import com.etesync.syncadapter.App;
import com.etesync.syncadapter.Constants;
@@ -65,6 +59,13 @@ import com.etesync.syncadapter.model.JournalEntity;
import com.etesync.syncadapter.model.ServiceDB.OpenHelper;
import com.etesync.syncadapter.model.ServiceDB.Services;
import com.etesync.syncadapter.resource.LocalCalendar;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Level;
+
+import at.bitfire.cert4android.CustomCertManager;
import at.bitfire.ical4android.TaskProvider;
import io.requery.Persistable;
import io.requery.sql.EntityDataStore;
@@ -205,6 +206,11 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu
}
};
+ public void onChangeJournalClick(View view) {
+ Intent intent = new Intent(this, JournalViewerActivity.class);
+ intent.putExtra(JournalViewerActivity.EXTRA_ACCOUNT, account);
+ startActivity(intent);
+ }
/* LOADERS AND LOADED DATA */
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/JournalViewerActivity.java b/app/src/main/java/com/etesync/syncadapter/ui/JournalViewerActivity.java
new file mode 100644
index 00000000..74215855
--- /dev/null
+++ b/app/src/main/java/com/etesync/syncadapter/ui/JournalViewerActivity.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering).
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Public License v3.0
+ * which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+package com.etesync.syncadapter.ui;
+
+import android.accounts.Account;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.NavUtils;
+import android.support.v7.app.AppCompatActivity;
+import android.view.MenuItem;
+
+import com.etesync.syncadapter.App;
+import com.etesync.syncadapter.ui.journalviewer.ListJournalsFragment;
+
+public class JournalViewerActivity extends AppCompatActivity {
+ public final static String EXTRA_ACCOUNT = "account";
+
+ private Account account;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+
+ if (savedInstanceState == null) {
+ account = getIntent().getExtras().getParcelable(EXTRA_ACCOUNT);
+ // first call, add fragment
+ getSupportFragmentManager().beginTransaction()
+ .replace(android.R.id.content, ListJournalsFragment.newInstance(account))
+ .commit();
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ if (!getSupportFragmentManager().popBackStackImmediate()) {
+ finish();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ App app = (App)getApplicationContext();
+ if (app.getCertManager() != null)
+ app.getCertManager().appInForeground = true;
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ App app = (App)getApplicationContext();
+ if (app.getCertManager() != null)
+ app.getCertManager().appInForeground = false;
+ }
+}
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/journalviewer/ListEntriesFragment.java b/app/src/main/java/com/etesync/syncadapter/ui/journalviewer/ListEntriesFragment.java
new file mode 100644
index 00000000..3bcef1e1
--- /dev/null
+++ b/app/src/main/java/com/etesync/syncadapter/ui/journalviewer/ListEntriesFragment.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering).
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Public License v3.0
+ * which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+package com.etesync.syncadapter.ui.journalviewer;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.support.v7.app.AlertDialog;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+import com.etesync.syncadapter.App;
+import com.etesync.syncadapter.R;
+import com.etesync.syncadapter.model.EntryEntity;
+import com.etesync.syncadapter.model.JournalEntity;
+import com.etesync.syncadapter.model.JournalModel;
+
+import java.util.Locale;
+
+import io.requery.Persistable;
+import io.requery.sql.EntityDataStore;
+
+public class ListEntriesFragment extends ListFragment implements AdapterView.OnItemClickListener {
+ protected static final String EXTRA_JOURNAL = "journal";
+
+ private EntityDataStore data;
+ private JournalEntity journalEntity;
+
+ public static ListEntriesFragment newInstance(String journal) {
+ ListEntriesFragment frag = new ListEntriesFragment();
+ Bundle args = new Bundle(1);
+ args.putSerializable(EXTRA_JOURNAL, journal);
+ frag.setArguments(args);
+ return frag;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ data = ((App) getContext().getApplicationContext()).getData();
+ String name = getArguments().getString(EXTRA_JOURNAL);
+ journalEntity = JournalModel.Journal.fetch(data, name);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ getActivity().setTitle(String.format(Locale.getDefault(), "%s (%d)", journalEntity.getInfo().displayName, data.count(EntryEntity.class).where(EntryEntity.JOURNAL.eq(journalEntity)).get().value()));
+ return inflater.inflate(R.layout.journal_viewer_list_entries, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ EntriesListAdapter listAdapter = new EntriesListAdapter(getContext());
+ setListAdapter(listAdapter);
+
+ listAdapter.addAll(data.select(EntryEntity.class).where(EntryEntity.JOURNAL.eq(journalEntity)).orderBy(EntryEntity.ID.desc()).get().toList());
+
+ getListView().setOnItemClickListener(this);
+ }
+
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id) {
+ EntryEntity entry = (EntryEntity) getListAdapter().getItem(position);
+ new AlertDialog.Builder(getActivity())
+ .setTitle("Raw dump: " + entry.getUid())
+ .setMessage("Action: " + entry.getContent().getAction().toString() + "\nUid: " + entry.getUid() + "\n" + entry.getContent().getContent()).show();
+ }
+
+ static class EntriesListAdapter extends ArrayAdapter {
+ public EntriesListAdapter(Context context) {
+ super(context, R.layout.journal_viewer_list_journals_item);
+ }
+
+ @Override
+ public View getView(int position, View v, ViewGroup parent) {
+ if (v == null)
+ v = LayoutInflater.from(getContext()).inflate(R.layout.journal_viewer_list_journals_item, parent, false);
+
+ EntryEntity entryEntity = getItem(position);
+
+ TextView tv = (TextView) v.findViewById(R.id.title);
+ tv.setText(String.format(Locale.getDefault(), "%s: %s", entryEntity.getContent().getAction().toString(), entryEntity.getUid()));
+
+ return v;
+ }
+ }
+}
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/journalviewer/ListJournalsFragment.java b/app/src/main/java/com/etesync/syncadapter/ui/journalviewer/ListJournalsFragment.java
new file mode 100644
index 00000000..dd189915
--- /dev/null
+++ b/app/src/main/java/com/etesync/syncadapter/ui/journalviewer/ListJournalsFragment.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering).
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Public License v3.0
+ * which accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+package com.etesync.syncadapter.ui.journalviewer;
+
+import android.accounts.Account;
+import android.content.Context;
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.ListFragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+import com.etesync.syncadapter.App;
+import com.etesync.syncadapter.R;
+import com.etesync.syncadapter.model.CollectionInfo;
+import com.etesync.syncadapter.model.JournalEntity;
+import com.etesync.syncadapter.model.ServiceDB;
+
+import io.requery.Persistable;
+import io.requery.sql.EntityDataStore;
+import lombok.Cleanup;
+
+public class ListJournalsFragment extends ListFragment implements AdapterView.OnItemClickListener {
+ private final static String ARG_ACCOUNT = "account";
+
+ private Account account;
+
+ public static ListJournalsFragment newInstance(Account account) {
+ ListJournalsFragment frag = new ListJournalsFragment();
+ Bundle args = new Bundle(1);
+ args.putParcelable(ARG_ACCOUNT, account);
+ frag.setArguments(args);
+ return frag;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ account = getArguments().getParcelable(ARG_ACCOUNT);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ getActivity().setTitle(R.string.change_journal_title);
+ return inflater.inflate(R.layout.journal_viewer_list_journals, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ CollectionsListAdapter listAdapter = new CollectionsListAdapter(getContext());
+ setListAdapter(listAdapter);
+
+ final EntityDataStore data = ((App) getContext().getApplicationContext()).getData();
+ @Cleanup ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(getContext());
+
+ Long service = dbHelper.getService(account, ServiceDB.Services.SERVICE_CARDDAV);
+ listAdapter.add(new HeaderItem(getString(R.string.settings_carddav)));
+ for (CollectionInfo info : JournalEntity.getCollections(data, service)) {
+ listAdapter.add(new ListItem(info));
+ }
+
+ service = dbHelper.getService(account, ServiceDB.Services.SERVICE_CALDAV);
+ listAdapter.add(new HeaderItem(getString(R.string.settings_caldav)));
+ for (CollectionInfo info : JournalEntity.getCollections(data, service)) {
+ listAdapter.add(new ListItem(info));
+ }
+
+ getListView().setOnItemClickListener(this);
+ }
+
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id) {
+ Item item = (Item) getListAdapter().getItem(position);
+ if (item.getViewType() == 1) {
+ CollectionInfo info = ((ListItem) item).info;
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, ListEntriesFragment.newInstance(info.url))
+ .addToBackStack(null)
+ .commitAllowingStateLoss();
+ }
+ }
+
+ private static class CollectionsListAdapter extends ArrayAdapter- {
+ CollectionsListAdapter(Context context) {
+ super(context, 0);
+ }
+
+ @NonNull
+ @Override
+ public View getView(int position, View v, @NonNull ViewGroup parent) {
+ Item item = getItem(position);
+ LayoutInflater inflater = LayoutInflater.from(getContext());
+
+ if (v == null) {
+ v = item.getView(inflater, v, parent);
+ }
+
+ return v;
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return Item.Type.values().length;
+
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return getItem(position).getViewType();
+ }
+ }
+
+ interface Item {
+ enum Type {
+ Header(0),
+ Item(1);
+
+ private final int value;
+
+ Type(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+ }
+
+ int getViewType();
+
+ View getView(LayoutInflater inflater, View convertView, ViewGroup parent);
+ }
+
+ private static class HeaderItem implements Item {
+ private String header;
+
+ HeaderItem(String header) {
+ this.header = header;
+ }
+
+ @Override
+ public int getViewType() {
+ return Type.Header.getValue();
+ }
+
+ @Override
+ public View getView(LayoutInflater inflater, View v, ViewGroup parent) {
+ if (v == null)
+ v = inflater.inflate(R.layout.journal_viewer_list_journals_header, parent, false);
+
+ TextView tv = (TextView) v.findViewById(R.id.title);
+ tv.setTypeface(null, Typeface.BOLD);
+ tv.setText(header);
+
+ return v;
+ }
+ }
+
+
+ private static class ListItem implements Item {
+ private CollectionInfo info;
+
+ ListItem(CollectionInfo info) {
+ this.info = info;
+ }
+
+ @Override
+ public int getViewType() {
+ return Type.Item.getValue();
+ }
+
+ @Override
+ public View getView(LayoutInflater inflater, View v, ViewGroup parent) {
+ if (v == null)
+ v = inflater.inflate(R.layout.journal_viewer_list_journals_item, parent, false);
+
+ TextView tv = (TextView) v.findViewById(R.id.title);
+ tv.setText(info.displayName);
+
+ return v;
+ }
+ }
+}
diff --git a/app/src/main/res/layout/activity_account.xml b/app/src/main/res/layout/activity_account.xml
index a7f77a96..8afaaf10 100644
--- a/app/src/main/res/layout/activity_account.xml
+++ b/app/src/main/res/layout/activity_account.xml
@@ -118,7 +118,7 @@
android:theme="@style/toolbar_theme"
style="@style/toolbar_style"
app:navigationIcon="@drawable/ic_journal"
- app:title="Change Journal"
+ app:title="@string/change_journal_title"
android:elevation="2dp" tools:ignore="UnusedAttribute"/>
@@ -126,20 +126,22 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="8dp"
android:gravity="center_vertical">
-
+ android:onClick="onChangeJournalClick"
+ android:gravity="left|center_vertical"
+ android:padding="16dp"
+ style="@style/Widget.AppCompat.Button.Borderless"
+ android:text="View (ugly preview-release)"/>
diff --git a/app/src/main/res/layout/journal_viewer_list_entries.xml b/app/src/main/res/layout/journal_viewer_list_entries.xml
new file mode 100644
index 00000000..1d8e24b2
--- /dev/null
+++ b/app/src/main/res/layout/journal_viewer_list_entries.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/journal_viewer_list_journals.xml b/app/src/main/res/layout/journal_viewer_list_journals.xml
new file mode 100644
index 00000000..b48b3a91
--- /dev/null
+++ b/app/src/main/res/layout/journal_viewer_list_journals.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/journal_viewer_list_journals_header.xml b/app/src/main/res/layout/journal_viewer_list_journals_header.xml
new file mode 100644
index 00000000..6a9f39d1
--- /dev/null
+++ b/app/src/main/res/layout/journal_viewer_list_journals_header.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/journal_viewer_list_journals_item.xml b/app/src/main/res/layout/journal_viewer_list_journals_item.xml
new file mode 100644
index 00000000..ab8fd805
--- /dev/null
+++ b/app/src/main/res/layout/journal_viewer_list_journals_item.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 9c18d796..7d77b705 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -90,6 +90,8 @@
Can\'t delete last collection
Deleting the last collection is not allowed, please create a new one if you\'d like to delete this one.
+ Change Journal
+
EteSync permissions
Calendar permissions
@@ -191,6 +193,9 @@
Deleting collection
Stats
+
+ No entries found for this journal
+
An error has occurred.
An HTTP error has occurred.