Add CI (#22)
* Create app-samples-CI.yml * Clean up SourceEditor * Clean up PhotoEditor * Clean up Widget and add to CI build
This commit is contained in:
Родитель
7fd01d5c91
Коммит
df56bd9356
|
@ -0,0 +1,112 @@
|
|||
# This workflow will build a Java project with Gradle
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
|
||||
|
||||
name: App samples CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, hero_notes, add-ci ]
|
||||
pull_request:
|
||||
branches: [ main, hero_notes ]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
name:
|
||||
description: 'manual build trigger'
|
||||
home:
|
||||
description: 'location'
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
- name: Cache SourceEditor Gradle packages
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: SourceEditor/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
|
||||
restore-keys: ${{ runner.os }}-gradle
|
||||
- name: Grant execute permission for SourceEditor gradlew
|
||||
run: chmod +x SourceEditor/gradlew
|
||||
- name: clean SourceEditor
|
||||
run: |
|
||||
cd SourceEditor
|
||||
./gradlew clean --info
|
||||
- name: assemble debug SourceEditor
|
||||
run: |
|
||||
cd SourceEditor
|
||||
./gradlew assembleDebug
|
||||
- name: unit tests SourceEditor
|
||||
run: |
|
||||
cd SourceEditor
|
||||
./gradlew testDebugUnitTest
|
||||
- name: lint SourceEditor
|
||||
run: |
|
||||
cd SourceEditor
|
||||
./gradlew lintDebug
|
||||
- name: ktlint SourceEditor
|
||||
run: |
|
||||
cd SourceEditor
|
||||
./gradlew ktlint
|
||||
- name: Cache PhotoEditor Gradle packages
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: PhotoEditor/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
|
||||
restore-keys: ${{ runner.os }}-gradle
|
||||
- name: Grant execute permission for PhotoEditor gradlew
|
||||
run: chmod +x PhotoEditor/gradlew
|
||||
- name: clean PhotoEditor
|
||||
run: |
|
||||
cd PhotoEditor
|
||||
./gradlew clean
|
||||
- name: assemble debug PhotoEditor
|
||||
run: |
|
||||
cd PhotoEditor
|
||||
./gradlew assembleDebug
|
||||
- name: unit tests PhotoEditor
|
||||
run: |
|
||||
cd PhotoEditor
|
||||
./gradlew testDebugUnitTest
|
||||
- name: lint PhotoEditor
|
||||
run: |
|
||||
cd PhotoEditor
|
||||
./gradlew lintDebug
|
||||
- name: ktlint PhotoEditor
|
||||
run: |
|
||||
cd PhotoEditor
|
||||
./gradlew ktlint
|
||||
- name: Cache Widget Gradle packages
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: Widget/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
|
||||
restore-keys: ${{ runner.os }}-gradle
|
||||
- name: Grant execute permission for Widget gradlew
|
||||
run: chmod +x Widget/gradlew
|
||||
- name: clean Widget
|
||||
run: |
|
||||
cd Widget
|
||||
./gradlew clean
|
||||
- name: assemble debug Widget
|
||||
run: |
|
||||
cd Widget
|
||||
./gradlew assembleDebug
|
||||
- name: unit tests Widget
|
||||
run: |
|
||||
cd Widget
|
||||
./gradlew testDebugUnitTest
|
||||
- name: lint Widget
|
||||
run: |
|
||||
cd Widget
|
||||
./gradlew lintDebug
|
||||
- name: ktlint Widget
|
||||
run: |
|
||||
cd Widget
|
||||
./gradlew ktlint
|
||||
|
|
@ -19,11 +19,11 @@ import androidx.test.uiautomator.By
|
|||
import androidx.test.uiautomator.UiDevice
|
||||
import androidx.test.uiautomator.Until
|
||||
import com.microsoft.device.dualscreen.layout.ScreenHelper
|
||||
import org.hamcrest.CoreMatchers.`is` as iz
|
||||
import org.hamcrest.CoreMatchers.not
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.hamcrest.CoreMatchers.`is` as iz
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
|
@ -164,15 +164,15 @@ class PhotoEditorUITest {
|
|||
val device: UiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
|
||||
|
||||
// Swipe constants
|
||||
const val leftX: Int = 675 // middle of left screen
|
||||
const val rightX: Int = 2109 // middle of right screen
|
||||
const val middleX: Int = 1350 // hinge area
|
||||
const val bottomY: Int = 1780 // bottom of screen
|
||||
const val middleY: Int = 900 // middle of screen
|
||||
const val spanSteps: Int = 400 // spanning swipe
|
||||
const val unspanSteps: Int = 200 // unspanning swipe
|
||||
const val switchSteps: Int = 100 // swipe to switch from one screen to the other
|
||||
const val closeSteps: Int = 50 // swipe to close app
|
||||
const val leftX: Int = 675 // middle of left screen
|
||||
const val rightX: Int = 2109 // middle of right screen
|
||||
const val middleX: Int = 1350 // hinge area
|
||||
const val bottomY: Int = 1780 // bottom of screen
|
||||
const val middleY: Int = 900 // middle of screen
|
||||
const val spanSteps: Int = 400 // spanning swipe
|
||||
const val unspanSteps: Int = 200 // unspanning swipe
|
||||
const val switchSteps: Int = 100 // swipe to switch from one screen to the other
|
||||
const val closeSteps: Int = 50 // swipe to close app
|
||||
}
|
||||
|
||||
private fun spanFromLeft() {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
![App samples CI](https://github.com/microsoft/surface-duo-app-samples/workflows/App%20samples%20CI/badge.svg)
|
||||
|
||||
# Surface Duo app samples
|
||||
|
||||
This repo contains sample Android applications for Microsoft Surface Duo.
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
package com.microsoft.device.display.samples.sourceeditor
|
||||
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.action.ViewActions.*
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.action.ViewActions.replaceText
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import androidx.test.espresso.web.assertion.WebViewAssertions.webMatches
|
||||
import androidx.test.espresso.web.sugar.Web.onWebView
|
||||
|
@ -52,7 +53,7 @@ class InteractiveTest {
|
|||
|
||||
@Test
|
||||
fun textPreservedOnSpanTest() {
|
||||
onView(withId(R.id.textinput_code)).perform(replaceText("<h1>" + testString + "</h1>"))
|
||||
onView(withId(R.id.textinput_code)).perform(replaceText("<h1>$testString</h1>"))
|
||||
spanFromLeft()
|
||||
assert(isSpanned())
|
||||
onWebView()
|
||||
|
@ -89,24 +90,31 @@ class InteractiveTest {
|
|||
|
||||
const val testString = "Testing in a different browser"
|
||||
}
|
||||
|
||||
private fun spanFromLeft() {
|
||||
device.swipe(leftX, bottomY, leftMiddleX, middleY, spanSteps)
|
||||
}
|
||||
|
||||
private fun unspanToLeft() {
|
||||
device.swipe(rightX, bottomY, leftX, middleY, spanSteps)
|
||||
}
|
||||
|
||||
private fun spanFromRight() {
|
||||
device.swipe(rightX, bottomY, rightMiddleX, middleY, spanSteps)
|
||||
}
|
||||
|
||||
private fun unspanToRight() {
|
||||
device.swipe(leftX, bottomY, rightX, middleY, spanSteps)
|
||||
}
|
||||
|
||||
private fun switchToLeft() {
|
||||
device.swipe(rightX, bottomY, leftX, middleY, switchSteps)
|
||||
}
|
||||
|
||||
private fun switchToRight() {
|
||||
device.swipe(leftX, bottomY, rightX, middleY, switchSteps)
|
||||
}
|
||||
|
||||
private fun isSpanned(): Boolean {
|
||||
return ScreenHelper.isDualMode(activityRule.activity)
|
||||
}
|
||||
|
|
|
@ -44,9 +44,9 @@ class CodeFragment : Fragment() {
|
|||
private lateinit var scrollVM: ScrollViewModel
|
||||
private lateinit var webVM: WebViewModel
|
||||
|
||||
private var scrollingBuffer : Int = Defines.DEFAULT_BUFFER_SIZE
|
||||
private var scrollRange : Int = Defines.DEFAULT_RANGE
|
||||
private var rangeFound : Boolean = false
|
||||
private var scrollingBuffer: Int = Defines.DEFAULT_BUFFER_SIZE
|
||||
private var scrollRange: Int = Defines.DEFAULT_RANGE
|
||||
private var rangeFound: Boolean = false
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
|
@ -83,7 +83,7 @@ class CodeFragment : Fragment() {
|
|||
}
|
||||
|
||||
// read from a base file in the assets folder
|
||||
private fun readFile(file : String, context : Context?) : String {
|
||||
private fun readFile(file: String, context: Context?): String {
|
||||
return BufferedReader(InputStreamReader(context?.assets?.open(file))).useLines { lines ->
|
||||
val results = StringBuilder()
|
||||
lines.forEach { results.append(it + System.getProperty("line.separator")) }
|
||||
|
@ -92,7 +92,7 @@ class CodeFragment : Fragment() {
|
|||
}
|
||||
|
||||
// mirror scrolling logic
|
||||
private fun handleScrolling (observing: Boolean, int: Int) {
|
||||
private fun handleScrolling(observing: Boolean, int: Int) {
|
||||
if (!rangeFound) {
|
||||
calibrateScrollView()
|
||||
} else {
|
||||
|
@ -138,12 +138,12 @@ class CodeFragment : Fragment() {
|
|||
rangeFound = false
|
||||
|
||||
// set event and data listeners
|
||||
scrollView.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
|
||||
scrollView.setOnScrollChangeListener { _, _, scrollY, _, _ ->
|
||||
handleScrolling(false, scrollY)
|
||||
}
|
||||
|
||||
scrollVM.getScroll().observe(requireActivity(), Observer { state ->
|
||||
if (!state.scrollKey.equals(Defines.CODE_KEY)) {
|
||||
if (state.scrollKey != Defines.CODE_KEY) {
|
||||
handleScrolling(true, state.scrollPercentage)
|
||||
}
|
||||
})
|
||||
|
@ -152,12 +152,12 @@ class CodeFragment : Fragment() {
|
|||
// method that triggers transition to preview fragment
|
||||
private fun startPreviewFragment() {
|
||||
parentFragmentManager.beginTransaction()
|
||||
.replace(
|
||||
R.id.single_screen_container_id,
|
||||
PreviewFragment(),
|
||||
null
|
||||
).addToBackStack(null)
|
||||
.commit()
|
||||
.replace(
|
||||
R.id.single_screen_container_id,
|
||||
PreviewFragment(),
|
||||
null
|
||||
).addToBackStack(null)
|
||||
.commit()
|
||||
}
|
||||
|
||||
// listener for changes to text in code editor
|
||||
|
@ -177,7 +177,7 @@ class CodeFragment : Fragment() {
|
|||
// get bounds of scroll window
|
||||
private fun calibrateScrollView() {
|
||||
if (scrollView.scrollY > Defines.MIN_RANGE_THRESHOLD) {
|
||||
scrollRange = scrollView.scrollY // successfully calibrated
|
||||
scrollRange = scrollView.scrollY // successfully calibrated
|
||||
rangeFound = true
|
||||
} else {
|
||||
scrollView.fullScroll(View.FOCUS_DOWN)
|
||||
|
@ -208,13 +208,13 @@ class CodeFragment : Fragment() {
|
|||
val handler = DragHandler(requireActivity(), webVM, requireActivity().contentResolver)
|
||||
|
||||
// Main target will trigger when textField has content
|
||||
textField.setOnDragListener { v, event ->
|
||||
handler.onDrag(v, event)
|
||||
textField.setOnDragListener { _, event ->
|
||||
handler.onDrag(event)
|
||||
}
|
||||
|
||||
// Sub target will trigger when textField is empty
|
||||
codeLayout.setOnDragListener { v, event ->
|
||||
handler.onDrag(v, event)
|
||||
codeLayout.setOnDragListener { _, event ->
|
||||
handler.onDrag(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ class MainActivity : AppCompatActivity() {
|
|||
|
||||
private lateinit var fileHandler: FileHandler
|
||||
private lateinit var webVM: WebViewModel
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
|
@ -48,20 +48,17 @@ class MainActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(
|
||||
requestCode: Int, resultCode: Int, resultData: Intent?) {
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, resultData)
|
||||
|
||||
// request to save a file has been made, add data to newly created file
|
||||
if (requestCode == fileHandler.CREATE_FILE
|
||||
&& resultCode == Activity.RESULT_OK) {
|
||||
if (requestCode == FileHandler.CREATE_FILE && resultCode == Activity.RESULT_OK) {
|
||||
resultData?.data?.also { uri ->
|
||||
fileHandler.alterDocument(uri)
|
||||
}
|
||||
}
|
||||
// request to load file contents has been made, process the file's contents
|
||||
else if (requestCode == fileHandler.PICK_TXT_FILE
|
||||
&& resultCode == Activity.RESULT_OK) {
|
||||
else if (requestCode == FileHandler.PICK_TXT_FILE && resultCode == Activity.RESULT_OK) {
|
||||
resultData?.data?.also { uri ->
|
||||
fileHandler.processFileData(uri)
|
||||
}
|
||||
|
|
|
@ -38,14 +38,14 @@ class PreviewFragment : Fragment() {
|
|||
private lateinit var scrollVM: ScrollViewModel
|
||||
private lateinit var webVM: WebViewModel
|
||||
|
||||
private var scrollingBuffer : Int = Defines.DEFAULT_BUFFER_SIZE
|
||||
private var scrollRange : Int = Defines.DEFAULT_RANGE
|
||||
private var rangeFound : Boolean = false
|
||||
private var scrollingBuffer: Int = Defines.DEFAULT_BUFFER_SIZE
|
||||
private var scrollRange: Int = Defines.DEFAULT_RANGE
|
||||
private var rangeFound: Boolean = false
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
val view = inflater.inflate(R.layout.fragment_item_preview, container, false)
|
||||
|
||||
|
@ -54,12 +54,12 @@ class PreviewFragment : Fragment() {
|
|||
webView.settings.javaScriptEnabled = true
|
||||
webView.webChromeClient = WebChromeClient()
|
||||
|
||||
activity?.let { activity ->
|
||||
activity?.let {
|
||||
// initialize ViewModels (find existing or create a new one)
|
||||
scrollVM = ViewModelProvider(requireActivity()).get(ScrollViewModel::class.java)
|
||||
webVM = ViewModelProvider(requireActivity()).get(WebViewModel::class.java)
|
||||
|
||||
val str : String? = (webVM.getText().value)
|
||||
val str: String? = (webVM.getText().value)
|
||||
webView.loadData(str, Defines.HTML_TYPE, Defines.ENCODING)
|
||||
|
||||
handleSpannedModeSelection(view, webView)
|
||||
|
@ -69,11 +69,10 @@ class PreviewFragment : Fragment() {
|
|||
}
|
||||
|
||||
// mirror scrolling logic
|
||||
private fun handleScrolling (observing: Boolean, int: Int) {
|
||||
private fun handleScrolling(observing: Boolean, int: Int) {
|
||||
if (!rangeFound) {
|
||||
calibrateScrollView()
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// code window scrolled, auto scroll to match editor
|
||||
if (observing) {
|
||||
autoScroll(int)
|
||||
|
@ -95,9 +94,8 @@ class PreviewFragment : Fragment() {
|
|||
})
|
||||
|
||||
if (ScreenHelper.isDualMode(activity)) {
|
||||
initializeDualScreen(view, webView)
|
||||
}
|
||||
else {
|
||||
initializeDualScreen(view)
|
||||
} else {
|
||||
initializeSingleScreen()
|
||||
}
|
||||
}
|
||||
|
@ -114,7 +112,7 @@ class PreviewFragment : Fragment() {
|
|||
}
|
||||
|
||||
// spanned selection helper
|
||||
private fun initializeDualScreen(view: View, webView: WebView) {
|
||||
private fun initializeDualScreen(view: View) {
|
||||
scrollingBuffer = Defines.DEFAULT_BUFFER_SIZE
|
||||
scrollRange = Defines.DEFAULT_RANGE
|
||||
rangeFound = false
|
||||
|
@ -123,12 +121,12 @@ class PreviewFragment : Fragment() {
|
|||
|
||||
// set event and data listeners
|
||||
scrollView = view.findViewById(R.id.scrollview_preview)
|
||||
scrollView.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
|
||||
scrollView.setOnScrollChangeListener { _, _, scrollY, _, _ ->
|
||||
handleScrolling(false, scrollY)
|
||||
}
|
||||
|
||||
scrollVM.getScroll().observe(requireActivity(), Observer { state ->
|
||||
if (!state.scrollKey.equals(Defines.PREVIEW_KEY)) {
|
||||
if (state.scrollKey != Defines.PREVIEW_KEY) {
|
||||
handleScrolling(true, state.scrollPercentage)
|
||||
}
|
||||
})
|
||||
|
@ -137,18 +135,18 @@ class PreviewFragment : Fragment() {
|
|||
// method that triggers transition to code fragment
|
||||
private fun startCodeFragment() {
|
||||
parentFragmentManager.beginTransaction()
|
||||
.replace(
|
||||
R.id.single_screen_container_id,
|
||||
CodeFragment(),
|
||||
null
|
||||
).addToBackStack(null)
|
||||
.commit()
|
||||
.replace(
|
||||
R.id.single_screen_container_id,
|
||||
CodeFragment(),
|
||||
null
|
||||
).addToBackStack(null)
|
||||
.commit()
|
||||
}
|
||||
|
||||
// get bounds of scroll window
|
||||
private fun calibrateScrollView() {
|
||||
if (scrollView.scrollY > Defines.MIN_RANGE_THRESHOLD) {
|
||||
scrollRange = scrollView.scrollY // successfully calibrated
|
||||
scrollRange = scrollView.scrollY // successfully calibrated
|
||||
rangeFound = true
|
||||
} else {
|
||||
scrollView.fullScroll(View.FOCUS_DOWN)
|
||||
|
@ -179,8 +177,8 @@ class PreviewFragment : Fragment() {
|
|||
val handler = DragHandler(requireActivity(), webVM, requireActivity().contentResolver)
|
||||
val target = webView
|
||||
|
||||
target.setOnDragListener { v, event ->
|
||||
handler.onDrag(v, event)
|
||||
target.setOnDragListener { _, event ->
|
||||
handler.onDrag(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,21 +10,18 @@ package com.microsoft.device.display.samples.sourceeditor.includes
|
|||
import android.app.Activity
|
||||
import android.content.ContentResolver
|
||||
import android.view.DragEvent
|
||||
import android.view.View
|
||||
import com.microsoft.device.display.samples.sourceeditor.viewmodel.WebViewModel
|
||||
|
||||
/* Class used to update app contents when an appropriate drag event occurs */
|
||||
class DragHandler (val activity: Activity,
|
||||
val webVM: WebViewModel,
|
||||
val contentResolver: ContentResolver) {
|
||||
class DragHandler(activity: Activity, webVM: WebViewModel, contentResolver: ContentResolver) {
|
||||
|
||||
val fileHandler = FileHandler(activity, webVM, contentResolver)
|
||||
private val fileHandler = FileHandler(activity, webVM, contentResolver)
|
||||
|
||||
// drag occurred, decide if event is relevant to app
|
||||
fun onDrag(v: View, event: DragEvent): Boolean {
|
||||
fun onDrag(event: DragEvent): Boolean {
|
||||
val action = event.action
|
||||
val isText = event.clipDescription?.getMimeType(0)
|
||||
.toString().startsWith(Defines.TEXT_PREFIX)
|
||||
.toString().startsWith(Defines.TEXT_PREFIX)
|
||||
|
||||
return when (action) {
|
||||
DragEvent.ACTION_DRAG_STARTED -> isText
|
||||
|
@ -35,7 +32,7 @@ class DragHandler (val activity: Activity,
|
|||
}
|
||||
|
||||
DragEvent.ACTION_DRAG_ENTERED, DragEvent.ACTION_DRAG_LOCATION,
|
||||
DragEvent.ACTION_DRAG_ENDED, DragEvent.ACTION_DRAG_EXITED ->
|
||||
DragEvent.ACTION_DRAG_ENDED, DragEvent.ACTION_DRAG_EXITED ->
|
||||
// Ignore events
|
||||
return true
|
||||
|
||||
|
|
|
@ -14,17 +14,25 @@ import android.net.Uri
|
|||
import android.provider.DocumentsContract
|
||||
import androidx.core.app.ActivityCompat.startActivityForResult
|
||||
import com.microsoft.device.display.samples.sourceeditor.viewmodel.WebViewModel
|
||||
import java.io.*
|
||||
import java.io.BufferedReader
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.FileOutputStream
|
||||
import java.io.InputStreamReader
|
||||
import java.io.IOException
|
||||
import java.nio.charset.Charset
|
||||
|
||||
/* Class used to make file read/write requests */
|
||||
class FileHandler (val activity: Activity,
|
||||
val webVM: WebViewModel,
|
||||
val contentResolver: ContentResolver) {
|
||||
class FileHandler(
|
||||
private val activity: Activity,
|
||||
private val webVM: WebViewModel,
|
||||
private val contentResolver: ContentResolver
|
||||
) {
|
||||
|
||||
// intent request codes
|
||||
val CREATE_FILE = 1
|
||||
val PICK_TXT_FILE = 2
|
||||
companion object {
|
||||
// intent request codes
|
||||
const val CREATE_FILE = 1
|
||||
const val PICK_TXT_FILE = 2
|
||||
}
|
||||
|
||||
// create a window prompting user to save a new file
|
||||
// defaults to public Downloads folder if uri is empty
|
||||
|
@ -72,11 +80,11 @@ class FileHandler (val activity: Activity,
|
|||
fun alterDocument(uri: Uri) {
|
||||
try {
|
||||
contentResolver.openFileDescriptor(uri, "w")?.use {
|
||||
FileOutputStream(it.fileDescriptor).use {
|
||||
FileOutputStream(it.fileDescriptor).use { stream ->
|
||||
val charset: Charset = Charsets.UTF_8
|
||||
it.write(
|
||||
webVM.getText().value.toString()
|
||||
.toByteArray(charset)
|
||||
stream.write(
|
||||
webVM.getText().value.toString()
|
||||
.toByteArray(charset)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +103,7 @@ class FileHandler (val activity: Activity,
|
|||
var initHeader = true
|
||||
|
||||
val lines = str.split("<")
|
||||
lines.forEach{
|
||||
lines.forEach {
|
||||
if (initHeader) {
|
||||
builder.append(it)
|
||||
initHeader = false
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
package com.microsoft.device.display.samples.sourceeditor.viewmodel
|
||||
|
||||
/* Class used to define a key, value pair for scrolling data */
|
||||
data class ScrollState (val scrollKey: String, val scrollPercentage: Int) {
|
||||
data class ScrollState(val scrollKey: String, val scrollPercentage: Int) {
|
||||
// empty body
|
||||
}
|
|
@ -23,4 +23,3 @@ class WebViewModel : ViewModel() {
|
|||
return webFormState
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
<!--
|
||||
~ Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
~ Licensed under the MIT License.
|
||||
~
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="78.5885"
|
||||
android:endY="90.9159"
|
||||
android:startX="48.7653"
|
||||
android:startY="61.0927"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
|
@ -10,7 +10,6 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/white"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
|
@ -39,7 +38,7 @@
|
|||
android:id="@+id/btn_save"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:paddingRight="15dp"
|
||||
android:paddingEnd="15dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/list_toolbar"
|
||||
app:layout_constraintEnd_toStartOf="@+id/btn_file"
|
||||
app:layout_constraintTop_toTopOf="@+id/list_toolbar"
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
~ Licensed under the MIT License.
|
||||
~
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/white">
|
||||
android:background="@color/white"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/button_toolbar"
|
||||
|
|
|
@ -6,5 +6,4 @@
|
|||
-->
|
||||
|
||||
<resources>
|
||||
<dimen name="text_size">28sp</dimen>
|
||||
</resources>
|
|
@ -12,8 +12,4 @@
|
|||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
<style name="DarkerGrayTheme" parent="AppTheme">
|
||||
<item name="android:background">@android:color/darker_gray</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
Двоичный файл не отображается.
|
@ -61,8 +61,6 @@ class WidgetApp : AppWidgetProvider() {
|
|||
getPendingSelfIntent(context, ACTION_UPDATE)
|
||||
)
|
||||
|
||||
val number = 10
|
||||
|
||||
// Adding settings button logic for every widget instance
|
||||
views.setOnClickPendingIntent(
|
||||
R.id.widgetSettingsButton,
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
android:textSize="14sp"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toRightOf="@+id/widgetLogo"
|
||||
android:layout_toEndOf="@+id/widgetLogo"
|
||||
android:textAllCaps="true" />
|
||||
|
||||
<ImageView
|
||||
|
|
Двоичный файл не отображается.
Загрузка…
Ссылка в новой задаче