1<!-- Copyright (C) 2017 The Android Open Source Project
2
3     Licensed under the Apache License, Version 2.0 (the "License");
4     you may not use this file except in compliance with the License.
5     You may obtain a copy of the License at
6
7          http://www.apache.org/licenses/LICENSE-2.0
8
9     Unless required by applicable law or agreed to in writing, software
10     distributed under the License is distributed on an "AS IS" BASIS,
11     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12     See the License for the specific language governing permissions and
13     limitations under the License.
14-->
15<template>
16  <div id="app">
17    <md-app>
18      <md-app-toolbar md-tag="md-toolbar" class="top-toolbar">
19        <h1 class="md-title" style="flex: 1">{{title}}</h1>
20        <md-button
21          class="md-primary md-theme-default download-all-btn"
22          @click="downloadAsZip(files)"
23          v-if="dataLoaded"
24        >Download All</md-button>
25        <md-button
26          class="md-accent md-raised md-theme-default clear-btn"
27          style="box-shadow: none;"
28          @click="clear()"
29          v-if="dataLoaded"
30        >Clear</md-button>
31      </md-app-toolbar>
32
33      <md-app-content class="main-content" :style="mainContentStyle">
34        <section class="data-inputs" v-if="!dataLoaded">
35          <div class="input">
36            <dataadb class="adbinput" ref="adb" :store="store"
37              @dataReady="onDataReady" @statusChange="setStatus" />
38          </div>
39          <div class="input">
40            <datainput class="fileinput" ref="input" :store="store"
41              @dataReady="onDataReady" @statusChange="setStatus" />
42          </div>
43        </section>
44
45        <section class="data-view">
46          <div
47            class="data-view-container"
48            v-for="file in dataViewFiles"
49            :key="file.type"
50          >
51            <dataview
52              :ref="file.type"
53              :store="store"
54              :file="file"
55              @click="onDataViewFocus(file)"
56            />
57          </div>
58
59          <overlay
60            :store="store"
61            :ref="overlayRef"
62            v-if="dataLoaded"
63            v-on:bottom-nav-height-change="handleBottomNavHeightChange"
64          />
65        </section>
66      </md-app-content>
67    </md-app>
68  </div>
69</template>
70<script>
71import Overlay from './Overlay.vue';
72import DataView from './DataView.vue';
73import DataInput from './DataInput.vue';
74import LocalStore from './localstore.js';
75import DataAdb from './DataAdb.vue';
76import FileType from './mixins/FileType.js';
77import SaveAsZip from './mixins/SaveAsZip';
78import FocusedDataViewFinder from './mixins/FocusedDataViewFinder';
79import {DIRECTION} from './utils/utils';
80import {NAVIGATION_STYLE} from './utils/consts';
81
82const APP_NAME = 'Winscope';
83
84const CONTENT_BOTTOM_PADDING = 25;
85
86export default {
87  name: 'app',
88  mixins: [FileType, SaveAsZip, FocusedDataViewFinder],
89  data() {
90    return {
91      title: APP_NAME,
92      activeDataView: null,
93      // eslint-disable-next-line new-cap
94      store: LocalStore('app', {
95        flattened: false,
96        onlyVisible: false,
97        simplifyNames: true,
98        displayDefaults: true,
99        navigationStyle: NAVIGATION_STYLE.GLOBAL,
100      }),
101      overlayRef: 'overlay',
102      mainContentStyle: {
103        'padding-bottom': `${CONTENT_BOTTOM_PADDING}px`,
104      },
105    };
106  },
107  created() {
108    window.addEventListener('keydown', this.onKeyDown);
109    window.addEventListener('scroll', this.onScroll);
110    document.title = this.title;
111  },
112  destroyed() {
113    window.removeEventListener('keydown', this.onKeyDown);
114    window.removeEventListener('scroll', this.onScroll);
115  },
116  methods: {
117    clear() {
118      this.$store.commit('clearFiles');
119    },
120    onDataViewFocus(file) {
121      this.$store.commit('setActiveFile', file);
122      this.activeDataView = file.type;
123    },
124    onKeyDown(event) {
125      event = event || window.event;
126      if (event.keyCode == 37 /* left */ ) {
127        this.$store.dispatch('advanceTimeline', DIRECTION.BACKWARD);
128      } else if (event.keyCode == 39 /* right */ ) {
129        this.$store.dispatch('advanceTimeline', DIRECTION.FORWARD);
130      } else if (event.keyCode == 38 /* up */ ) {
131        this.$refs[this.activeView][0].arrowUp();
132      } else if (event.keyCode == 40 /* down */ ) {
133        this.$refs[this.activeView][0].arrowDown();
134      } else {
135        return false;
136      }
137      event.preventDefault();
138      return true;
139    },
140    onDataReady(files) {
141      this.$store.dispatch('setFiles', files);
142      this.updateFocusedView();
143    },
144    setStatus(status) {
145      if (status) {
146        this.title = status;
147      } else {
148        this.title = APP_NAME;
149      }
150    },
151    handleBottomNavHeightChange(newHeight) {
152      this.$set(
153          this.mainContentStyle,
154          'padding-bottom',
155          `${ CONTENT_BOTTOM_PADDING + newHeight }px`,
156      );
157    },
158  },
159  computed: {
160    files() {
161      return this.$store.getters.sortedFiles;
162    },
163    prettyDump() {
164      return JSON.stringify(this.dump, null, 2);
165    },
166    dataLoaded() {
167      return this.files.length > 0;
168    },
169    activeView() {
170      if (!this.activeDataView && this.files.length > 0) {
171        // eslint-disable-next-line vue/no-side-effects-in-computed-properties
172        this.activeDataView = this.files[0].type;
173      }
174      return this.activeDataView;
175    },
176    dataViewFiles() {
177      return this.files.filter((f) => this.hasDataView(f));
178    },
179  },
180  watch: {
181    title() {
182      document.title = this.title;
183    },
184  },
185  components: {
186    overlay: Overlay,
187    dataview: DataView,
188    datainput: DataInput,
189    dataadb: DataAdb,
190  },
191};
192</script>
193<style>
194@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@600&display=swap');
195
196#app .md-app-container {
197  /* Get rid of tranforms which prevent fixed position from being used */
198  transform: none!important;
199  min-height: 100vh;
200}
201
202#app .top-toolbar {
203  box-shadow: none;
204  background-color: #fff;
205  background-color: var(--md-theme-default-background, #fff);
206  border-bottom: thin solid rgba(0,0,0,.12);
207  padding:  0 40px;
208}
209
210#app .top-toolbar .md-title {
211  font-family: 'Open Sans', sans-serif;
212  white-space: nowrap;
213  color: #5f6368;
214  margin: 0;
215  padding: 0;
216  font-size: 22px;
217  letter-spacing: 0;
218  font-weight: 600;
219}
220
221.data-view {
222  display: flex;
223  flex-direction: column;
224}
225
226.card-toolbar {
227  border-bottom: 1px solid rgba(0, 0, 0, .12);
228}
229
230.timeline {
231  margin: 16px;
232}
233
234.container {
235  display: flex;
236  flex-wrap: wrap;
237}
238
239.md-button {
240  margin-top: 1em
241}
242
243h1,
244h2 {
245  font-weight: normal;
246}
247
248ul {
249  list-style-type: none;
250  padding: 0;
251}
252
253a {
254  color: #42b983;
255}
256
257.data-inputs {
258  display: flex;
259  flex-wrap: wrap;
260  height: 100%;
261  width: 100%;
262  align-self: center;
263  /* align-items: center; */
264  align-content: center;
265  justify-content: center;
266}
267
268.data-inputs .input {
269  padding: 15px;
270  flex: 1 1 0;
271  max-width: 840px;
272  /* align-self: center; */
273}
274
275.data-inputs .input > div {
276  height: 100%;
277}
278
279.data-view-container {
280  padding: 25px 20px 0 20px;
281}
282</style>
283