Skip to content

Commit c535835

Browse files
authored
Merge pull request #183 from ActivityWatch/dev/android-update
2 parents 51bab94 + b215d50 commit c535835

File tree

8 files changed

+214
-332
lines changed

8 files changed

+214
-332
lines changed

src/components/Header.vue

+5-9
Original file line numberDiff line numberDiff line change
@@ -77,28 +77,24 @@ import 'vue-awesome/icons/desktop';
7777
7878
import _ from 'lodash';
7979
80-
// Set this to true to test Android behavior when on a desktop
81-
const testingAndroid = false;
82-
8380
export default {
8481
name: 'Header',
8582
data() {
8683
return {
8784
activityViews: [],
88-
isAndroidApp:
89-
testingAndroid ||
90-
(navigator.userAgent.includes('Android') && navigator.userAgent.includes('wv')), // Checks for Android and WebView
9185
};
9286
},
9387
mounted: async function() {
9488
const buckets = await this.$aw.getBuckets();
9589
const types_by_host = {};
90+
91+
// TODO: Change to use same bucket detection logic as get_buckets/set_available in store/modules/activity.ts
9692
_.each(buckets, v => {
9793
types_by_host[v.hostname] = types_by_host[v.hostname] || {};
9894
// The '&& true;' is just to typecoerce into booleans
9995
types_by_host[v.hostname].afk |= v.type == 'afkstatus';
10096
types_by_host[v.hostname].window |= v.type == 'currentwindow';
101-
types_by_host[v.hostname].android |= v.type == 'currentwindow' && this.isAndroidApp; // Use other bucket type ID in the future
97+
types_by_host[v.hostname].android |= v.type == 'currentwindow' && v.id.includes('android'); // Use other bucket type ID in the future
10298
});
10399
//console.log(types_by_host);
104100
@@ -112,12 +108,12 @@ export default {
112108
icon: 'desktop',
113109
});
114110
}
115-
if (testingAndroid || types.android) {
111+
if (types.android) {
116112
this.activityViews.push({
117113
name: `${hostname} (Android)`,
118114
hostname: hostname,
119115
type: 'android',
120-
pathUrl: '/activity/android',
116+
pathUrl: `/activity/${hostname}`,
121117
icon: 'mobile',
122118
});
123119
}
+68-85
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,30 @@
11
<template lang="pug">
22
div
3-
h5 {{ type_title }}
3+
h5 {{ visualizations[type].title }}
4+
div
5+
b-dropdown.vis-style-dropdown-btn(size="sm" variant="outline-secondary")
6+
template(v-slot:button-content)
7+
icon(name="cog")
8+
b-dropdown-item(v-for="t in types" :key="t" variant="outline-secondary" @click="$emit('onTypeChange', id, t)" v-bind:disabled="!visualizations[t].available")
9+
| {{ visualizations[t].title }}
10+
411
div(v-if="type == 'top_apps'")
5-
aw-summary(:fields="top_apps",
12+
aw-summary(:fields="$store.state.activity.window.top_apps",
613
:namefunc="e => e.data.app",
714
:colorfunc="e => e.data.app",
815
with_limit)
916
div(v-if="type == 'top_titles'")
10-
aw-summary(:fields="top_titles",
17+
aw-summary(:fields="$store.state.activity.window.top_titles",
1118
:namefunc="e => e.data.title",
1219
:colorfunc="e => e.data.app",
1320
with_limit)
1421
div(v-if="type == 'top_domains'")
15-
aw-summary(:fields="top_domains",
22+
aw-summary(:fields="$store.state.activity.browser.top_domains",
1623
:namefunc="e => e.data.$domain",
1724
:colorfunc="e => e.data.$domain",
1825
with_limit)
1926
div(v-if="type == 'top_urls'")
20-
aw-summary(:fields="top_urls",
27+
aw-summary(:fields="$store.state.activity.browser.top_urls",
2128
:namefunc="e => e.data.url",
2229
:colorfunc="e => e.data.$domain",
2330
with_limit)
@@ -37,29 +44,26 @@ div
3744
:colorfunc="e => e.data.language",
3845
with_limit)
3946
div(v-if="type == 'top_categories'")
40-
aw-summary(:fields="top_categories",
47+
aw-summary(:fields="$store.state.activity.category.top",
4148
:namefunc="e => e.data['$category'].join(' > ')",
4249
:colorfunc="e => e.data['$category'].join(' > ')",
4350
with_limit)
4451
div(v-if="type == 'category_tree'")
45-
aw-categorytree(:events="top_categories")
52+
aw-categorytree(:events="$store.state.activity.category.top")
4653
div(v-if="type == 'category_sunburst'")
4754
aw-sunburst-categories(:data="top_categories_hierarchy", style="height: 20em")
4855

49-
b-dropdown.vis-style-dropdown-btn(size="sm" variant="outline-secondary")
50-
template(v-slot:button-content)
51-
icon(name="cog")
52-
b-dropdown-item(v-for="t in types" :key="t" variant="outline-secondary" @click="$emit('onTypeChange', id, t)" v-bind:disabled="!get_type_available(t)")
53-
| {{ get_type_title(t) }}
5456
</template>
5557

56-
<style scoped lang="scss">
58+
<style lang="scss">
5759
.vis-style-dropdown-btn {
5860
position: absolute;
59-
bottom: 0;
60-
right: 0.5em;
61+
top: 0.8em;
62+
right: 1em;
6163
62-
background-color: #fff;
64+
> .btn {
65+
border: 0px;
66+
}
6367
}
6468
</style>
6569

@@ -109,24 +113,56 @@ export default {
109113
};
110114
},
111115
computed: {
112-
top_apps: function() {
113-
return this.$store.state.activity.window.top_apps;
114-
},
115-
top_titles: function() {
116-
return this.$store.state.activity.window.top_titles;
117-
},
118-
top_domains: function() {
119-
return this.$store.state.activity.browser.top_domains;
120-
},
121-
top_urls: function() {
122-
return this.$store.state.activity.browser.top_urls;
123-
},
124-
top_categories: function() {
125-
return this.$store.state.activity.category.top;
116+
visualizations: function() {
117+
return {
118+
top_apps: {
119+
title: 'Top Applications',
120+
available:
121+
this.$store.state.activity.window.available ||
122+
this.$store.state.activity.android.available,
123+
},
124+
top_titles: {
125+
title: 'Top Window Titles',
126+
available: this.$store.state.activity.window.available,
127+
},
128+
top_domains: {
129+
title: 'Top Browser Domains',
130+
available: this.$store.state.activity.browser.available,
131+
},
132+
top_urls: {
133+
title: 'Top Browser URLs',
134+
available: this.$store.state.activity.browser.available,
135+
},
136+
top_editor_files: {
137+
title: 'Top Editor Files',
138+
available: this.$store.state.activity.editor.available,
139+
},
140+
top_editor_languages: {
141+
title: 'Top Editor Languages',
142+
available: this.$store.state.activity.editor.available,
143+
},
144+
top_editor_projects: {
145+
title: 'Top Editor Projects',
146+
available: this.$store.state.activity.editor.available,
147+
},
148+
top_categories: {
149+
title: 'Top Categories',
150+
available: this.$store.state.activity.category.available,
151+
},
152+
category_tree: {
153+
title: 'Category Tree',
154+
available: this.$store.state.activity.category.available,
155+
},
156+
category_sunburst: {
157+
title: 'Category Sunburst',
158+
available: this.$store.state.activity.category.available,
159+
},
160+
};
126161
},
127162
top_categories_hierarchy: function() {
128-
if (this.top_categories) {
129-
const categories = this.top_categories.map(c => {
163+
const top_categories = this.$store.state.activity.category.top;
164+
if (top_categories) {
165+
const categories = top_categories.map(c => {
130166
return { name: c.data.$category, size: c.duration };
131167
});
132168
@@ -138,59 +174,6 @@ export default {
138174
return null;
139175
}
140176
},
141-
type_title: function() {
142-
return this.get_type_title(this.type);
143-
},
144-
},
145-
methods: {
146-
get_type_available: function(type) {
147-
if (type === 'top_apps' || type === 'top_titles') {
148-
return this.$store.state.activity.window.available;
149-
} else if (type === 'top_domains' || type === 'top_urls') {
150-
return this.$store.state.activity.browser.available;
151-
} else if (
152-
type === 'top_editor_files' ||
153-
type === 'top_editor_languages' ||
154-
type === 'top_editor_projects'
155-
) {
156-
return this.$store.state.activity.editor.available;
157-
} else if (
158-
type === 'top_categories' ||
159-
type === 'category_tree' ||
160-
type === 'category_sunburst'
161-
) {
162-
return this.$store.state.activity.category.available;
163-
} else {
164-
console.error('Unknown type available: ', type);
165-
return false;
166-
}
167-
},
168-
get_type_title: function(type) {
169-
if (type === 'top_apps') {
170-
return 'Top Applications';
171-
} else if (type === 'top_titles') {
172-
return 'Top Window Titles';
173-
} else if (type === 'top_domains') {
174-
return 'Top Browser Domains';
175-
} else if (type === 'top_urls') {
176-
return 'Top Browser URLs';
177-
} else if (type === 'top_editor_files') {
178-
return 'Top Editor Files';
179-
} else if (type === 'top_editor_languages') {
180-
return 'Top Editor Languages';
181-
} else if (type === 'top_editor_projects') {
182-
return 'Top Editor Projects';
183-
} else if (type === 'top_categories') {
184-
return 'Top Categories';
185-
} else if (type === 'category_tree') {
186-
return 'Category Tree';
187-
} else if (type === 'category_sunburst') {
188-
return 'Category Sunburst';
189-
} else {
190-
console.error('Unknown type: ', type);
191-
return 'Unknown';
192-
}
193-
},
194177
},
195178
};
196179
</script>

src/main.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ import 'typeface-varela-round';
2323
// Loads all the filters
2424
import './util/filters.js';
2525

26+
// Create an instance of AWClient as this.$aw
27+
import awclient from './util/awclient.js';
28+
console.log(awclient);
29+
Vue.prototype.$aw = awclient;
30+
2631
// Sets up the routing and the base app (using vue-router)
2732
import router from './route.js';
2833

@@ -54,10 +59,6 @@ Vue.component('aw-timeline-barchart', () => import('./visualizations/TimelineBar
5459
// A mixin to make async method errors propagate
5560
Vue.mixin(require('~/mixins/asyncErrorCaptured.js'));
5661

57-
// Create an instance of AWClient as this.$aw
58-
import awclient from './util/awclient.js';
59-
Vue.prototype.$aw = awclient;
60-
6162
// Set the PRODUCTION constant
6263
Vue.prototype.PRODUCTION = PRODUCTION;
6364

0 commit comments

Comments
 (0)